Version 1.19.0-dev.0.0
Merge 9d5fd9d5bd9dea0098a8f49a87300ab578eb765c into dev
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8f44d60..26425b5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,4 @@
-## 1.18.0
+## 1.18.0 - 2016-07-27
### Core library changes
diff --git a/DEPS b/DEPS
index cbcfa64..3b3ac3b 100644
--- a/DEPS
+++ b/DEPS
@@ -56,7 +56,7 @@
"dart_services_rev" : "@7aea2574e6f3924bf409a80afb8ad52aa2be4f97",
"dart_style_tag": "@0.2.4",
"dartdoc_tag" : "@v0.9.6+2",
- "dev_compiler_rev": "@7e9708eb5e9f3fcdc68b9af039d78cf39ce502b7",
+ "dev_compiler_rev": "@108f2a2a03b1926e640013f3244df625b42ec380",
"fixnum_tag": "@0.10.5",
"func_rev": "@8d4aea75c21be2179cb00dc2b94a71414653094e",
"glob_rev": "@704cf75e4f26b417505c5c611bdaacd8808467dd",
@@ -68,6 +68,7 @@
"idl_parser_rev": "@7fbe68cab90c38147dee4f48c30ad0d496c17915",
"initialize_rev": "@595d501a92c3716395ad2d81f9aabdb9f90879b6",
"intl_tag": "@0.13.0",
+ "isolate_tag": "@0.2.2",
"jinja2_rev": "@2222b31554f03e62600cd7e383376a7c187967a1",
"json_rpc_2_tag": "@2.0.0",
"linter_rev": "@7ca3aab6ca45b988440e425c187993a533fbe27e",
@@ -92,7 +93,7 @@
"quiver_tag": "@0.21.4",
"resource_rev":"@a49101ba2deb29c728acba6fb86000a8f730f4b1",
"root_certificates_rev": "@aed07942ce98507d2be28cbd29e879525410c7fc",
- "scheduled_test_tag": "@0.12.5+2",
+ "scheduled_test_tag": "@0.12.6",
"shelf_static_tag": "@0.2.3+4",
"shelf_tag": "@0.6.5+2",
"shelf_web_socket_tag": "@0.2.0",
@@ -106,7 +107,7 @@
"string_scanner_tag": "@0.1.4",
"sunflower_rev": "@879b704933413414679396b129f5dfa96f7a0b1e",
"test_reflective_loader_tag": "@0.0.3",
- "test_tag": "@0.12.13+5",
+ "test_tag": "@0.12.15+1",
"typed_data_tag": "@1.1.2",
"usage_rev": "@b5080dac0d26a5609b266f8fdb0d053bc4c1c638",
"utf_rev": "@1f55027068759e2d52f2c12de6a57cce5f3c5ee6",
@@ -222,6 +223,8 @@
(Var("github_dartlang") % "initialize") + Var("initialize_rev"),
Var("dart_root") + "/third_party/pkg/intl":
(Var("github_mirror") % "intl") + Var("intl_tag"),
+ Var("dart_root") + "/third_party/pkg/isolate":
+ (Var("github_dartlang") % "isolate") + Var("isolate_tag"),
Var("dart_root") + "/third_party/pkg/json_rpc_2":
(Var("github_mirror") % "json_rpc_2") + Var("json_rpc_2_tag"),
Var("dart_root") + "/third_party/pkg/linter":
diff --git a/README.fuchsia b/README.fuchsia
deleted file mode 100644
index f09ff26..0000000
--- a/README.fuchsia
+++ /dev/null
@@ -1,41 +0,0 @@
-This is a README file describing how to build Dart for Fuchsia. It assumes that
-you have built the magenta kernel under //magenta, its toolchains are
-under //toolchains, and that you have a Dart checkout under //dart. It is early
-days and this is crufty. The process will improve from here.
-
-1. First, set up some symlinks in your Dart checkout:
-
- //dart/third_party/fuchsia_tools/toolchains
- -> symlinked to //toolchains
- //dart/third_party/fuchsia_tools/sysroot/x86_64/usr
- -> symlinked to //magenta/build-magenta-qemu-x86-64/sysroot/
-
- Also, copy the linker script:
-
- //magenta$ cp kernel/arch/x86/64/user.ld build-magenta-qemu-x86-64/sysroot/
-
- and similarly for arm64.
-
-2. Build:
-
- //dart$ tools/build.py -m product -a x64 --os=fuchsia fuchsia_test
-
- This will produce //dart/out/ProductFuchsiaX64/fuchsia_test
-
-3. Strip it:
-
- //dart$ third_party/fuchsia_tools/toolchains/x86_64-elf-5.3.0-Linux-x86_64/bin/x86_64-elf-strip out/ProductFuchsiaX64/fuchsia_test -o out/ProductFuchsiaX64/fuchsia_test.stripped
-
-4. Make a file //magenta/fuchsia_test.manifest containing:
-
- bin/fuchsia_test=//dart/out/ProductFuchsiaX64/fuchsia_test.stripped
-
- Where //dart is the actual path to your Dart checkout.
-
-5. Make an extra bootfs:
-
- //magenta$ build-magenta-qemu-x86-64/tools/mkbootfs -o fuchsia_test.bootfs fuchsia_test.manifest
-
-6. Run:
-
- //magenta$ ./scripts/run-magenta-x86-64 -x fuchsia_test.bootfs
diff --git a/dart.gyp b/dart.gyp
index f513625..b942371 100644
--- a/dart.gyp
+++ b/dart.gyp
@@ -35,13 +35,6 @@
],
},
{
- 'target_name': 'fuchsia_test',
- 'type': 'none',
- 'dependencies': [
- 'runtime/dart-runtime.gyp:fuchsia_test',
- ],
- },
- {
# This is the target that is built on the VM build bots. It
# must depend on anything that is required by the VM test
# suites.
diff --git a/docs/language/dartLangSpec.tex b/docs/language/dartLangSpec.tex
index 140a8df..0b76367 100644
--- a/docs/language/dartLangSpec.tex
+++ b/docs/language/dartLangSpec.tex
@@ -655,9 +655,11 @@
It is a compile-time error if a formal parameter is declared as a constant variable (\ref{variables}).
\begin{grammar}
-{\bf formalParameterList:}`(' `)';
- `(' normalFormalParameters ( `,' optionalFormalParameters)? `)';
- `(' optionalFormalParameters `)'
+{\bf formalParameterList:}
+ `(' `)';
+ `(' normalFormalParameters `,'? `)';
+ `(' normalFormalParameters `,' optionalFormalParameters `)';
+ `(' optionalFormalParameters `)'
.
%\end{grammar}
%}
@@ -673,18 +675,21 @@
normalFormalParameter (`,' normalFormalParameter)*
.
-{\bf optionalFormalParameters:}optionalPositionalFormalParameters;
+{\bf optionalFormalParameters:}
+ optionalPositionalFormalParameters;
namedFormalParameters
.
{\bf optionalPositionalFormalParameters:}
- `[' defaultFormalParameter (`,' defaultFormalParameter)* `]'
+ `[' defaultFormalParameter (`,' defaultFormalParameter)* `,'? `]'
.
{\bf namedFormalParameters:}
- `\{' defaultNamedParameter (`,' defaultNamedParameter)* `\}'
+ `\{' defaultNamedParameter (`,' defaultNamedParameter)* `,'? `\}'
.
\end{grammar}
+Formal parameter lists allow an optional trailing comma after the last parameter ($`,'?$). A parameter list with such a trailing comma is equivalent in all ways to the same parameter list without the trailing comma. All parameter lists in this specification are shown without a trailing comma, but the rules and semantics apply equally to the corresponding parameter list with a trailing comma.
+
%Formal parameters are always \FINAL{}.
%\Q{We're awaiting some data on whether enforcing this would cause widespread pain.}
%A formal parameter is always considered to be initialized. \rationale{This is because it will always be initialized by the call - even if it is optional.}
@@ -3608,10 +3613,11 @@
\begin{grammar}
{\bf arguments:}
- `(' argumentList? `)'
+ `(' (argumentList `,'?)? `)'
.
-{\bf argumentList:}namedArgument (`,' namedArgument)*;
+{\bf argumentList:}
+ namedArgument (`,' namedArgument)*;
% expressionList ',' spreadArgument;
expressionList (`,' namedArgument)*
% spreadArgument
@@ -3622,6 +3628,8 @@
.
\end{grammar}
+Argument lists allow an optional trailing comma after the last argument ($`,'?$). An argument list with such a trailing comma is equivalent in all ways to the same parameter list without the trailing comma. All argument lists in this specification are shown without a trailing comma, but the rules and semantics apply equally to the corresponding argument list with a trailing comma.
+
\LMHash{}
Evaluation of an actual argument list of the form
diff --git a/pkg/analysis_server/benchmark/perf/benchmark_flutter.dart b/pkg/analysis_server/benchmark/perf/benchmark_flutter.dart
new file mode 100644
index 0000000..87ccc30
--- /dev/null
+++ b/pkg/analysis_server/benchmark/perf/benchmark_flutter.dart
@@ -0,0 +1,217 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library server.performance.local;
+
+import 'dart:async';
+
+import 'package:analysis_server/plugin/protocol/protocol.dart';
+
+import 'benchmark_scenario.dart';
+import 'memory_tests.dart';
+
+main(List<String> args) async {
+ int length = args.length;
+ if (length < 1) {
+ print('Usage: dart benchmark_local.dart path_to_flutter_checkout'
+ ' [benchmark_id]');
+ return;
+ }
+ paths = new PathHolder(flutterPath: args[0]);
+ String id = args.length >= 2 ? args[1] : null;
+ if (id == null) {
+ for (String id in benchmarks.keys) {
+ BenchmarkFunction benchmark = benchmarks[id];
+ await benchmark(id);
+ }
+ } else {
+ BenchmarkFunction benchmark = benchmarks[id];
+ if (benchmark != null) {
+ benchmark(id);
+ }
+ }
+}
+
+const Map<String, BenchmarkFunction> benchmarks =
+ const <String, BenchmarkFunction>{
+ 'flutter-initialAnalysis-1': run_flutter_initialAnalysis_1,
+ 'flutter-initialAnalysis-2': run_flutter_initialAnalysis_2,
+ 'flutter-change-1': run_flutter_change_1,
+ 'flutter-change-2': run_flutter_change_2,
+ 'flutter-completion-1': run_flutter_completion_1,
+ 'flutter-completion-2': run_flutter_completion_2,
+ 'flutter-refactoring-1': run_flutter_refactoring_1,
+ 'flutter-memory-initialAnalysis-1': run_flutter_memory_initialAnalysis_1,
+ 'flutter-memory-initialAnalysis-2': run_flutter_memory_initialAnalysis_2,
+};
+
+PathHolder paths;
+
+Future run_flutter_change_1(String id) async {
+ String description = r'''
+1. Open 'packages/flutter'.
+2. Change a method body in lib/src/painting/colors.dart
+3. Measure the time to finish analysis.
+4. Rollback changes to the file and wait for analysis.
+5. Go to (2).
+''';
+ List<int> times = await new BenchmarkScenario().waitAnalyze_change_analyze(
+ roots: [paths.packageFlutter],
+ file: '${paths.packageFlutter}/lib/src/painting/colors.dart',
+ fileChange: new FileChange(
+ afterStr: 'final double h = hue % 360;', insertStr: 'print(12345);'),
+ numOfRepeats: 10);
+ printBenchmarkResults(id, description, times);
+}
+
+Future run_flutter_change_2(String id) async {
+ String description = r'''
+1. Open 'packages/flutter'.
+2. Change the name of a public method in lib/src/painting/colors.dart
+3. Measure the time to finish analysis.
+4. Rollback changes to the file and wait for analysis.
+5. Go to (2).
+''';
+ List<int> times = await new BenchmarkScenario().waitAnalyze_change_analyze(
+ roots: [paths.packageFlutter],
+ file: '${paths.packageFlutter}/lib/src/painting/colors.dart',
+ fileChange: new FileChange(
+ afterStr: 'withValue(dou', afterStrBack: 4, insertStr: 'NewName'),
+ numOfRepeats: 5);
+ printBenchmarkResults(id, description, times);
+}
+
+Future run_flutter_completion_1(String id) async {
+ String description = r'''
+1. Open 'packages/flutter'.
+2. Change a method body in packages/flutter/lib/src/material/button.dart
+3. Request code completion in this method and measure time to get results.
+4. Rollback changes to the file and wait for analysis.
+5. Go to (2).
+''';
+ String completionMarker = 'print(12345);';
+ List<int> times = await new BenchmarkScenario()
+ .waitAnalyze_change_getCompletion(
+ roots: [paths.packageFlutter],
+ file: '${paths.packageFlutter}/lib/src/material/button.dart',
+ fileChange: new FileChange(
+ afterStr: 'Widget build(BuildContext context) {',
+ insertStr: completionMarker),
+ completeAfterStr: completionMarker,
+ numOfRepeats: 10);
+ printBenchmarkResults(id, description, times);
+}
+
+Future run_flutter_completion_2(String id) async {
+ String description = r'''
+1. Open 'packages/flutter'.
+2. Change the name of a public method in lib/src/rendering/layer.dart
+3. Request code completion in this method and measure time to get results.
+4. Rollback changes to the file and wait for analysis.
+5. Go to (2).
+''';
+ List<int> times = await new BenchmarkScenario()
+ .waitAnalyze_change_getCompletion(
+ roots: [paths.packageFlutter],
+ file: '${paths.packageFlutter}/lib/src/rendering/layer.dart',
+ fileChange: new FileChange(
+ replaceWhat: 'void removeAllChildren() {',
+ replaceWith: 'void removeAllChildren2() {print(12345);parent.'),
+ completeAfterStr: 'print(12345);parent.',
+ numOfRepeats: 5);
+ printBenchmarkResults(id, description, times);
+}
+
+Future run_flutter_initialAnalysis_1(String id) async {
+ String description = r'''
+1. Start server, set 'hello_world' analysis root.
+2. Measure the time to finish initial analysis.
+3. Shutdown the server.
+4. Go to (1).
+''';
+ List<int> times = await BenchmarkScenario.start_waitInitialAnalysis_shutdown(
+ roots: [paths.exampleHelloWorld], numOfRepeats: 5);
+ printBenchmarkResults(id, description, times);
+}
+
+Future run_flutter_initialAnalysis_2(String id) async {
+ String description = r'''
+1. Start server, set 'hello_world' and 'flutter_gallery' analysis roots.
+2. Measure the time to finish initial analysis.
+3. Shutdown the server.
+4. Go to (1).
+''';
+ List<int> times = await BenchmarkScenario.start_waitInitialAnalysis_shutdown(
+ roots: [paths.exampleHelloWorld, paths.exampleGallery], numOfRepeats: 5);
+ printBenchmarkResults(id, description, times);
+}
+
+Future run_flutter_memory_initialAnalysis_1(String id) async {
+ String description = r'''
+1. Start server, set 'packages/flutter' as the analysis root.
+2. Measure the memory usage after finishing initial analysis.
+3. Shutdown the server.
+4. Go to (1).
+''';
+ List<int> sizes = await AnalysisServerMemoryUsageTest
+ .start_waitInitialAnalysis_shutdown(
+ roots: <String>[paths.packageFlutter], numOfRepeats: 3);
+ printMemoryResults(id, description, sizes);
+}
+
+Future run_flutter_memory_initialAnalysis_2(String id) async {
+ String description = r'''
+1. Start server, set 'packages/flutter' and 'packages/flutter_markdown' analysis roots.
+2. Measure the memory usage after finishing initial analysis.
+3. Shutdown the server.
+4. Go to (1).
+''';
+ List<int> sizes = await AnalysisServerMemoryUsageTest
+ .start_waitInitialAnalysis_shutdown(
+ roots: <String>[paths.packageFlutter, paths.packageMarkdown],
+ numOfRepeats: 3);
+ printMemoryResults(id, description, sizes);
+}
+
+Future run_flutter_refactoring_1(String id) async {
+ String description = r'''
+1. Open 'packages/flutter'.
+2. Change the name of a public method in lib/src/rendering/layer.dart
+3. Request rename refactoring for `getSourcesWithFullName` and measure time to get results.
+4. Rollback changes to the file and wait for analysis.
+5. Go to (2).
+''';
+ List<int> times = await new BenchmarkScenario()
+ .waitAnalyze_change_getRefactoring(
+ roots: [paths.packageFlutter],
+ file: '${paths.packageFlutter}/lib/src/rendering/layer.dart',
+ fileChange: new FileChange(
+ replaceWhat: 'void removeAllChildren() {',
+ replaceWith: 'void removeAllChildren2() {'),
+ refactoringAtStr: 'addToScene(ui.SceneBuilder builder',
+ refactoringKind: RefactoringKind.RENAME,
+ refactoringOptions: new RenameOptions('addToScene2'),
+ numOfRepeats: 5);
+ printBenchmarkResults(id, description, times);
+}
+
+typedef BenchmarkFunction(String id);
+
+class PathHolder {
+ String exampleHelloWorld;
+ String exampleGallery;
+ String exampleStocks;
+ String packageFlutter;
+ String packageMarkdown;
+ String packageSprites;
+
+ PathHolder({String flutterPath}) {
+ exampleHelloWorld = '$flutterPath/examples/hello_world';
+ exampleGallery = '$flutterPath/examples/flutter_gallery';
+ exampleStocks = '$flutterPath/examples/stocks';
+ packageFlutter = '$flutterPath/packages/flutter';
+ packageMarkdown = '$flutterPath/packages/flutter_markdown';
+ packageSprites = '$flutterPath/packages/flutter_sprites';
+ }
+}
diff --git a/pkg/analysis_server/benchmark/perf/benchmark_local.dart b/pkg/analysis_server/benchmark/perf/benchmark_local.dart
deleted file mode 100644
index 8cbdb89..0000000
--- a/pkg/analysis_server/benchmark/perf/benchmark_local.dart
+++ /dev/null
@@ -1,272 +0,0 @@
-// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library server.performance.local;
-
-import 'dart:async';
-
-import 'package:analysis_server/plugin/protocol/protocol.dart';
-
-import 'benchmark_scenario.dart';
-import 'memory_tests.dart';
-
-main(List<String> args) async {
- int length = args.length;
- if (length < 1) {
- print(
- 'Usage: dart benchmark_local.dart path_to_sdk_checkout [path_to_flutter_checkout]');
- return;
- } else if (length == 1) {
- paths = new PathHolder(sdkPath: args[0]);
- } else {
- paths = new PathHolder(sdkPath: args[0], flutterPath: args[1]);
- }
- String now = new DateTime.now().toUtc().toIso8601String();
- print('Benchmark started: $now');
- print('');
- print('');
- await run_local_initialAnalysis_1();
- await run_local_initialAnalysis_2();
- await run_local_initialAnalysis_3();
- await run_local_change_1();
- await run_local_change_2();
- await run_local_completion_1();
- await run_local_completion_2();
- await run_local_completion_3();
- await run_local_completion_4();
- await run_local_refactoring_1();
-
- await run_memory_initialAnalysis_1();
- await run_memory_initialAnalysis_2();
-}
-
-PathHolder paths;
-
-Future run_local_change_1() async {
- String id = 'local-change-1';
- String description = r'''
-1. Open 'analyzer'.
-2. Change a method body in src/task/dart.dart.
-3. Measure the time to finish analysis.
-4. Rollback changes to the file and wait for analysis.
-5. Go to (2).
-''';
- List<int> times = await new BenchmarkScenario().waitAnalyze_change_analyze(
- roots: [paths.analyzer],
- file: '${paths.analyzer}/lib/src/task/dart.dart',
- fileChange: new FileChange(
- afterStr: 'if (hasDirectiveChange) {', insertStr: 'print(12345);'),
- numOfRepeats: 10);
- printBenchmarkResults(id, description, times);
-}
-
-Future run_local_change_2() async {
- String id = 'local-change-2';
- String description = r'''
-1. Open 'analyzer'.
-2. Change the name of a public method in src/task/dart.dart.
-3. Measure the time to finish analysis.
-4. Rollback changes to the file and wait for analysis.
-5. Go to (2).
-''';
- List<int> times = await new BenchmarkScenario().waitAnalyze_change_analyze(
- roots: [paths.analyzer],
- file: '${paths.analyzer}/lib/src/task/dart.dart',
- fileChange: new FileChange(
- afterStr: 'resolveDirective(An',
- afterStrBack: 3,
- insertStr: 'NewName'),
- numOfRepeats: 5);
- printBenchmarkResults(id, description, times);
-}
-
-Future run_local_completion_1() async {
- String id = 'local-completion-1';
- String description = r'''
-1. Open 'analyzer'.
-2. Change a method body in src/task/dart.dart.
-3. Request code completion in this method and measure time to get results.
-4. Rollback changes to the file and wait for analysis.
-5. Go to (2).
-''';
- List<int> times = await new BenchmarkScenario()
- .waitAnalyze_change_getCompletion(
- roots: [paths.analyzer],
- file: '${paths.analyzer}/lib/src/task/dart.dart',
- fileChange: new FileChange(
- afterStr: 'if (hasDirectiveChange) {',
- insertStr: 'print(12345);'),
- completeAfterStr: 'print(12345);',
- numOfRepeats: 10);
- printBenchmarkResults(id, description, times);
-}
-
-Future run_local_completion_2() async {
- String id = 'local-completion-2';
- String description = r'''
-1. Open 'analyzer'.
-2. Change the name of a public method in src/task/dart.dart.
-3. Request code completion in this method and measure time to get results.
-4. Rollback changes to the file and wait for analysis.
-5. Go to (2).
-''';
- List<int> times = await new BenchmarkScenario()
- .waitAnalyze_change_getCompletion(
- roots: [paths.analyzer],
- file: '${paths.analyzer}/lib/src/task/dart.dart',
- fileChange: new FileChange(
- afterStr: 'DeltaResult validate(In',
- afterStrBack: 3,
- insertStr: 'NewName'),
- completeAfterStr: 'if (hasDirectiveChange) {',
- numOfRepeats: 5);
- printBenchmarkResults(id, description, times);
-}
-
-Future run_local_completion_3() async {
- String id = 'local-completion-3';
- String description = r'''
-1. Open 'analysis_server' and 'analyzer'.
-2. Change a method body in src/task/dart.dart.
-3. Request code completion in this method and measure time to get results.
-4. Rollback changes to the file and wait for analysis.
-5. Go to (2).
-''';
- List<int> times = await new BenchmarkScenario()
- .waitAnalyze_change_getCompletion(
- roots: [paths.analysisServer, paths.analyzer],
- file: '${paths.analyzer}/lib/src/task/dart.dart',
- fileChange: new FileChange(
- afterStr: 'if (hasDirectiveChange) {',
- insertStr: 'print(12345);'),
- completeAfterStr: 'print(12345);',
- numOfRepeats: 10);
- printBenchmarkResults(id, description, times);
-}
-
-Future run_local_completion_4() async {
- String id = 'local-completion-4';
- String description = r'''
-1. Open 'analysis_server' and 'analyzer'.
-2. Change the name of a public method in src/task/dart.dart.
-3. Request code completion in this method and measure time to get results.
-4. Rollback changes to the file and wait for analysis.
-5. Go to (2).
-''';
- List<int> times = await new BenchmarkScenario()
- .waitAnalyze_change_getCompletion(
- roots: [paths.analysisServer, paths.analyzer],
- file: '${paths.analyzer}/lib/src/task/dart.dart',
- fileChange: new FileChange(
- afterStr: 'DeltaResult validate(In',
- afterStrBack: 3,
- insertStr: 'NewName'),
- completeAfterStr: 'if (hasDirectiveChange) {',
- numOfRepeats: 5);
- printBenchmarkResults(id, description, times);
-}
-
-Future run_local_initialAnalysis_1() async {
- String id = 'local-initialAnalysis-1';
- String description = r'''
-1. Start server, set 'analyzer' analysis root.
-2. Measure the time to finish initial analysis.
-3. Shutdown the server.
-4. Go to (1).
-''';
- List<int> times = await BenchmarkScenario.start_waitInitialAnalysis_shutdown(
- roots: [paths.analyzer], numOfRepeats: 3);
- printBenchmarkResults(id, description, times);
-}
-
-Future run_local_initialAnalysis_2() async {
- String id = 'local-initialAnalysis-2';
- String description = r'''
-1. Start server, set 'analyzer' and 'analysis_server' analysis roots.
-2. Measure the time to finish initial analysis.
-3. Shutdown the server.
-4. Go to (1).
-''';
- List<int> times = await BenchmarkScenario.start_waitInitialAnalysis_shutdown(
- roots: [paths.analyzer, paths.analysisServer], numOfRepeats: 3);
- printBenchmarkResults(id, description, times);
-}
-
-Future run_local_initialAnalysis_3() async {
- String id = 'local-initialAnalysis-3';
- String description = r'''
-1. Start server, set 'hello_world' and 'stocks' analysis roots.
-2. Measure the time to finish initial analysis.
-3. Shutdown the server.
-4. Go to (1).
-''';
- List<int> times = await BenchmarkScenario.start_waitInitialAnalysis_shutdown(
- roots: [paths.flutterHelloWorld, paths.flutterStocks], numOfRepeats: 3);
- printBenchmarkResults(id, description, times);
-}
-
-Future run_local_refactoring_1() async {
- String id = 'local-refactoring-1';
- String description = r'''
-1. Open 'analyzer'.
-2. Change the name of a public method in src/context/cache.dart.
-3. Request rename refactoring for `getSourcesWithFullName` and measure time to get results.
-4. Rollback changes to the file and wait for analysis.
-5. Go to (2).
-''';
- List<int> times = await new BenchmarkScenario()
- .waitAnalyze_change_getRefactoring(
- roots: [paths.analyzer],
- file: '${paths.analyzer}/lib/src/context/cache.dart',
- fileChange: new FileChange(
- afterStr: 'getState(An', afterStrBack: 3, insertStr: 'NewName'),
- refactoringAtStr: 'getSourcesWithFullName(String path)',
- refactoringKind: RefactoringKind.RENAME,
- refactoringOptions: new RenameOptions('getSourcesWithFullName2'),
- numOfRepeats: 5);
- printBenchmarkResults(id, description, times);
-}
-
-Future run_memory_initialAnalysis_1() async {
- String id = 'memory-initialAnalysis-1';
- String description = r'''
-1. Start server, set 'analyzer' and 'analysis_server' analysis roots.
-2. Measure the memory usage after finishing initial analysis.
-3. Shutdown the server.
-4. Go to (1).
-''';
- List<int> sizes = await AnalysisServerMemoryUsageTest
- .start_waitInitialAnalysis_shutdown(
- roots: <String>[paths.analyzer], numOfRepeats: 3);
- printMemoryResults(id, description, sizes);
-}
-
-Future run_memory_initialAnalysis_2() async {
- String id = 'memory-initialAnalysis-2';
- String description = r'''
-1. Start server, set 'analyzer' and 'analysis_server' analysis roots.
-2. Measure the memory usage after finishing initial analysis.
-3. Shutdown the server.
-4. Go to (1).
-''';
- List<int> sizes = await AnalysisServerMemoryUsageTest
- .start_waitInitialAnalysis_shutdown(
- roots: <String>[paths.analyzer, paths.analysisServer],
- numOfRepeats: 3);
- printMemoryResults(id, description, sizes);
-}
-
-class PathHolder {
- String analysisServer;
- String analyzer;
- String flutterHelloWorld;
- String flutterStocks;
-
- PathHolder({String sdkPath, String flutterPath}) {
- analysisServer = '$sdkPath/pkg/analysis_server';
- analyzer = '$sdkPath/pkg/analyzer';
- flutterHelloWorld = '$flutterPath/examples/hello_world';
- flutterStocks = '$flutterPath/examples/stocks';
- }
-}
diff --git a/pkg/analysis_server/benchmark/perf/benchmark_scenario.dart b/pkg/analysis_server/benchmark/perf/benchmark_scenario.dart
index aac844b..3ec4c4c 100644
--- a/pkg/analysis_server/benchmark/perf/benchmark_scenario.dart
+++ b/pkg/analysis_server/benchmark/perf/benchmark_scenario.dart
@@ -6,6 +6,7 @@
import 'dart:async';
import 'dart:io';
+import 'dart:math';
import 'package:analysis_server/plugin/protocol/protocol.dart';
import 'package:unittest/unittest.dart';
@@ -13,9 +14,11 @@
import 'performance_tests.dart';
void printBenchmarkResults(String id, String description, List<int> times) {
+ int minTime = times.fold(1 << 20, min);
String now = new DateTime.now().toUtc().toIso8601String();
print('$now ========== $id');
print('times: $times');
+ print('min_time: $minTime');
print(description.trim());
print('--------------------');
print('');
@@ -185,11 +188,19 @@
*/
Future<String> _applyFileChange(String file, FileChange desc) async {
String originalContent = _getFileContent(file);
- int offset = _indexOfEnd(file, originalContent, desc.afterStr);
- offset -= desc.afterStrBack;
- String updatedContent = originalContent.substring(0, offset) +
- desc.insertStr +
- originalContent.substring(offset);
+ String updatedContent;
+ if (desc.afterStr != null) {
+ int offset = _indexOfEnd(file, originalContent, desc.afterStr);
+ offset -= desc.afterStrBack;
+ updatedContent = originalContent.substring(0, offset) +
+ desc.insertStr +
+ originalContent.substring(offset);
+ } else if (desc.replaceWhat != null) {
+ int offset = _indexOf(file, originalContent, desc.replaceWhat);
+ updatedContent = originalContent.substring(0, offset) +
+ desc.replaceWith +
+ originalContent.substring(offset + desc.replaceWhat.length);
+ }
await sendAnalysisUpdateContent(
{file: new AddContentOverlay(updatedContent)});
return updatedContent;
@@ -279,9 +290,14 @@
final String afterStr;
final int afterStrBack;
final String insertStr;
+ final String replaceWhat;
+ final String replaceWith;
- FileChange({this.afterStr, this.afterStrBack: 0, this.insertStr}) {
- expect(afterStr, isNotNull, reason: 'afterStr');
- expect(insertStr, isNotNull, reason: 'insertStr');
+ FileChange({this.afterStr, this.afterStrBack: 0, this.insertStr, this.replaceWhat, this.replaceWith}) {
+ if (afterStr != null) {
+ expect(insertStr, isNotNull, reason: 'insertStr');
+ } else if (replaceWhat != null) {
+ expect(replaceWith, isNotNull, reason: 'replaceWith');
+ }
}
}
diff --git a/pkg/analysis_server/benchmark/perf/memory_tests.dart b/pkg/analysis_server/benchmark/perf/memory_tests.dart
index 8522430..a648344 100644
--- a/pkg/analysis_server/benchmark/perf/memory_tests.dart
+++ b/pkg/analysis_server/benchmark/perf/memory_tests.dart
@@ -5,6 +5,7 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
+import 'dart:math';
import 'package:analysis_server/plugin/protocol/protocol.dart';
import 'package:unittest/unittest.dart';
@@ -12,9 +13,13 @@
import '../../test/integration/integration_tests.dart';
void printMemoryResults(String id, String description, List<int> sizes) {
+ int minMemory = sizes.fold(sizes.first, min);
+ int maxMemory = sizes.fold(sizes.first, max);
String now = new DateTime.now().toUtc().toIso8601String();
print('$now ========== $id');
print('memory: $sizes');
+ print('min_memory: $minMemory');
+ print('max_memory: $maxMemory');
print(description.trim());
print('--------------------');
print('');
@@ -98,7 +103,7 @@
* 1. Start Analysis Server.
* 2. Set the analysis [roots].
* 3. Wait for analysis to complete.
- * 4. Record the time to finish analysis.
+ * 4. Record the heap size after analysis is finished.
* 5. Shutdown.
* 6. Go to (1).
*/
diff --git a/pkg/analysis_server/benchmark/perf/performance_tests.dart b/pkg/analysis_server/benchmark/perf/performance_tests.dart
index 6d301c9..d6be917 100644
--- a/pkg/analysis_server/benchmark/perf/performance_tests.dart
+++ b/pkg/analysis_server/benchmark/perf/performance_tests.dart
@@ -46,7 +46,7 @@
expect(serverConnected.isCompleted, isFalse);
serverConnected.complete();
});
- return startServer().then((_) {
+ return startServer(checked: false).then((_) {
server.listenToOutput(dispatchNotification);
server.exitCode.then((_) {
skipShutdown = true;
diff --git a/pkg/analysis_server/lib/src/analysis_server.dart b/pkg/analysis_server/lib/src/analysis_server.dart
index 7e695a2..ca87546 100644
--- a/pkg/analysis_server/lib/src/analysis_server.dart
+++ b/pkg/analysis_server/lib/src/analysis_server.dart
@@ -699,23 +699,6 @@
return nodes;
}
-// TODO(brianwilkerson) Add the following method after 'prioritySources' has
-// been added to InternalAnalysisContext.
-// /**
-// * Return a list containing the full names of all of the sources that are
-// * priority sources.
-// */
-// List<String> getPriorityFiles() {
-// List<String> priorityFiles = new List<String>();
-// folderMap.values.forEach((ContextDirectory directory) {
-// InternalAnalysisContext context = directory.context;
-// context.prioritySources.forEach((Source source) {
-// priorityFiles.add(source.fullName);
-// });
-// });
-// return priorityFiles;
-// }
-
/**
* Returns resolved [CompilationUnit]s of the Dart file with the given [path].
*
@@ -745,6 +728,23 @@
return units;
}
+// TODO(brianwilkerson) Add the following method after 'prioritySources' has
+// been added to InternalAnalysisContext.
+// /**
+// * Return a list containing the full names of all of the sources that are
+// * priority sources.
+// */
+// List<String> getPriorityFiles() {
+// List<String> priorityFiles = new List<String>();
+// folderMap.values.forEach((ContextDirectory directory) {
+// InternalAnalysisContext context = directory.context;
+// context.prioritySources.forEach((Source source) {
+// priorityFiles.add(source.fullName);
+// });
+// });
+// return priorityFiles;
+// }
+
/**
* Handle a [request] that was read from the communication channel.
*/
@@ -929,6 +929,32 @@
}
/**
+ * Schedule cache consistency validation in [context].
+ * The most of the validation must be done asynchronously.
+ */
+ void scheduleCacheConsistencyValidation(AnalysisContext context) {
+ if (context is InternalAnalysisContext) {
+ CacheConsistencyValidator validator = context.cacheConsistencyValidator;
+ List<Source> sources = validator.getSourcesToComputeModificationTimes();
+ // Compute modification times and notify the validator asynchronously.
+ new Future(() async {
+ try {
+ List<int> modificationTimes =
+ await resourceProvider.getModificationTimes(sources);
+ bool cacheInconsistencyFixed = validator
+ .sourceModificationTimesComputed(sources, modificationTimes);
+ if (cacheInconsistencyFixed) {
+ scheduleOperation(new PerformAnalysisOperation(context, false));
+ }
+ } catch (exception, stackTrace) {
+ sendServerErrorNotification(
+ 'Failed to check cache consistency', exception, stackTrace);
+ }
+ });
+ }
+ }
+
+ /**
* Schedules execution of the given [ServerOperation].
*/
void scheduleOperation(ServerOperation operation) {
diff --git a/pkg/analysis_server/lib/src/context_manager.dart b/pkg/analysis_server/lib/src/context_manager.dart
index 585da46..347788b 100644
--- a/pkg/analysis_server/lib/src/context_manager.dart
+++ b/pkg/analysis_server/lib/src/context_manager.dart
@@ -625,7 +625,7 @@
if (analyzer is Map) {
// Set ignore patterns.
YamlList exclude = analyzer[AnalyzerOptions.exclude];
- List<String> excludeList = _toStringList(exclude);
+ List<String> excludeList = toStringList(exclude);
if (excludeList != null) {
setIgnorePatternsForContext(info, excludeList);
}
@@ -1594,25 +1594,6 @@
}
/**
- * If all of the elements of [list] are strings, return a list of strings
- * containing the same elements. Otherwise, return `null`.
- */
- List<String> _toStringList(YamlList list) {
- if (list == null) {
- return null;
- }
- List<String> stringList = <String>[];
- for (var element in list) {
- if (element is String) {
- stringList.add(element);
- } else {
- return null;
- }
- }
- return stringList;
- }
-
- /**
* If the given [object] is a map, and all of the keys in the map are strings,
* return a map containing the same mappings. Otherwise, return `null`.
*/
diff --git a/pkg/analysis_server/lib/src/operation/operation_analysis.dart b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
index 76b27ae..b99cec3 100644
--- a/pkg/analysis_server/lib/src/operation/operation_analysis.dart
+++ b/pkg/analysis_server/lib/src/operation/operation_analysis.dart
@@ -372,12 +372,7 @@
List<ChangeNotice> notices = result.changeNotices;
// nothing to analyze
if (notices == null) {
- bool cacheInconsistencyFixed = context.validateCacheConsistency();
- if (cacheInconsistencyFixed) {
- server.addOperation(new PerformAnalysisOperation(context, true));
- return;
- }
- // analysis is done
+ server.scheduleCacheConsistencyValidation(context);
setCacheSize(context, IDLE_CACHE_SIZE);
server.sendContextAnalysisDoneNotifications(
context, AnalysisDoneReason.COMPLETE);
diff --git a/pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart
index bbf9cb5..7e7ae5c 100644
--- a/pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart
+++ b/pkg/analysis_server/lib/src/provisional/completion/dart/completion_target.dart
@@ -22,6 +22,13 @@
if (args.isEmpty) {
return 0;
}
+ if (entity == argList.rightParenthesis) {
+ // Parser ignores trailing commas
+ if (argList.rightParenthesis.previous?.lexeme == ',') {
+ return args.length;
+ }
+ return args.length - 1;
+ }
}
return null;
}
diff --git a/pkg/analysis_server/lib/src/search/search_domain.dart b/pkg/analysis_server/lib/src/search/search_domain.dart
index 4a0e1b7..37c58a69 100644
--- a/pkg/analysis_server/lib/src/search/search_domain.dart
+++ b/pkg/analysis_server/lib/src/search/search_domain.dart
@@ -118,6 +118,15 @@
Future findTopLevelDeclarations(protocol.Request request) async {
var params =
new protocol.SearchFindTopLevelDeclarationsParams.fromRequest(request);
+ try {
+ // validate the regex
+ new RegExp(params.pattern);
+ } on FormatException catch (exception) {
+ server.sendResponse(new protocol.Response.invalidParameter(
+ request, 'pattern', exception.message));
+ return;
+ }
+
await server.onAnalysisComplete;
// respond
String searchId = (_nextSearchId++).toString();
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart b/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
index f29e7a6..3b26f60 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/arglist_contributor.dart
@@ -19,6 +19,12 @@
int _argCount(DartCompletionRequest request) {
AstNode node = request.target.containingNode;
if (node is ArgumentList) {
+ if (request.target.entity == node.rightParenthesis) {
+ // Parser ignores trailing commas
+ if (node.rightParenthesis.previous?.lexeme == ',') {
+ return node.arguments.length + 1;
+ }
+ }
return node.arguments.length;
}
return 0;
@@ -96,12 +102,15 @@
}
/**
- * Determine if the completion target is an emtpy argument list.
+ * Return `true` if the [request] is inside of a [NamedExpression] name.
*/
-bool _isEmptyArgList(DartCompletionRequest request) {
- AstNode node = request.target.containingNode;
- return node is ArgumentList &&
- node.leftParenthesis.next == node.rightParenthesis;
+bool _isInNamedExpression(DartCompletionRequest request) {
+ Object entity = request.target.entity;
+ if (entity is NamedExpression) {
+ Label name = entity.name;
+ return name.offset < request.offset && request.offset < name.end;
+ }
+ return false;
}
/**
@@ -217,61 +226,30 @@
return EMPTY_LIST;
}
- void _addArgListSuggestion(Iterable<ParameterElement> requiredParam) {
- // DEPRECATED... argument lists are no longer suggested.
- // See https://github.com/dart-lang/sdk/issues/25197
-
- // String _getParamType(ParameterElement param) {
- // DartType type = param.type;
- // if (type != null) {
- // return type.displayName;
- // }
- // return 'dynamic';
- // }
-
- // StringBuffer completion = new StringBuffer('(');
- // List<String> paramNames = new List<String>();
- // List<String> paramTypes = new List<String>();
- // for (ParameterElement param in requiredParam) {
- // String name = param.name;
- // if (name != null && name.length > 0) {
- // if (completion.length > 1) {
- // completion.write(', ');
- // }
- // completion.write(name);
- // paramNames.add(name);
- // paramTypes.add(_getParamType(param));
- // }
- // }
- // completion.write(')');
- // CompletionSuggestion suggestion = new CompletionSuggestion(
- // CompletionSuggestionKind.ARGUMENT_LIST,
- // DART_RELEVANCE_HIGH,
- // completion.toString(),
- // completion.length,
- // 0,
- // false,
- // false);
- // suggestion.parameterNames = paramNames;
- // suggestion.parameterTypes = paramTypes;
- // suggestions.add(suggestion);
- }
-
void _addDefaultParamSuggestions(Iterable<ParameterElement> parameters,
[bool appendComma = false]) {
+ bool appendColon = !_isInNamedExpression(request);
Iterable<String> namedArgs = _namedArgs(request);
for (ParameterElement param in parameters) {
if (param.parameterKind == ParameterKind.NAMED) {
_addNamedParameterSuggestion(request, namedArgs, param.name,
- param.type?.displayName, appendComma);
+ param.type?.displayName, appendColon, appendComma);
}
}
}
- void _addNamedParameterSuggestion(DartCompletionRequest request,
- List<String> namedArgs, String name, String paramType, bool appendComma) {
+ void _addNamedParameterSuggestion(
+ DartCompletionRequest request,
+ List<String> namedArgs,
+ String name,
+ String paramType,
+ bool appendColon,
+ bool appendComma) {
if (name != null && name.length > 0 && !namedArgs.contains(name)) {
- String completion = '$name: ';
+ String completion = name;
+ if (appendColon) {
+ completion += ': ';
+ }
if (appendComma) {
completion += ',';
}
@@ -295,10 +273,6 @@
Iterable<ParameterElement> requiredParam = parameters.where(
(ParameterElement p) => p.parameterKind == ParameterKind.REQUIRED);
int requiredCount = requiredParam.length;
- if (requiredCount > 0 && _isEmptyArgList(request)) {
- _addArgListSuggestion(requiredParam);
- return;
- }
// TODO (jwren) _isAppendingToArgList can be split into two cases (with and
// without preceded), then _isAppendingToArgList,
// _isInsertingToArgListWithNoSynthetic and
diff --git a/pkg/analysis_server/lib/src/services/completion/dart/optype.dart b/pkg/analysis_server/lib/src/services/completion/dart/optype.dart
index 917542c..132c823 100644
--- a/pkg/analysis_server/lib/src/services/completion/dart/optype.dart
+++ b/pkg/analysis_server/lib/src/services/completion/dart/optype.dart
@@ -184,8 +184,19 @@
if (elem is FunctionTypedElement) {
List<ParameterElement> parameters = elem.parameters;
if (parameters != null) {
- int index =
- node.arguments.isEmpty ? 0 : node.arguments.indexOf(entity);
+ int index;
+ if (node.arguments.isEmpty) {
+ index = 0;
+ } else if (entity == node.rightParenthesis) {
+ // Parser ignores trailing commas
+ if (node.rightParenthesis.previous?.lexeme == ',') {
+ index = node.arguments.length;
+ } else {
+ index = node.arguments.length - 1;
+ }
+ } else {
+ index = node.arguments.indexOf(entity);
+ }
if (0 <= index && index < parameters.length) {
ParameterElement param = parameters[index];
if (param?.parameterKind == ParameterKind.NAMED) {
diff --git a/pkg/analysis_server/lib/src/services/correction/assist.dart b/pkg/analysis_server/lib/src/services/correction/assist.dart
index 2024b75..2bcf316 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist.dart
@@ -89,6 +89,10 @@
'CONVERT_INTO_EXPRESSION_BODY', 30, "Convert into expression body");
static const CONVERT_INTO_FOR_INDEX = const AssistKind(
'CONVERT_INTO_FOR_INDEX', 30, "Convert into for-index loop");
+ static const CONVERT_INTO_FINAL_FIELD = const AssistKind(
+ 'CONVERT_INTO_FINAL_FIELD', 30, "Convert into final field");
+ static const CONVERT_INTO_GETTER =
+ const AssistKind('CONVERT_INTO_GETTER', 30, "Convert into getter");
static const CONVERT_INTO_IS_NOT =
const AssistKind('CONVERT_INTO_IS_NOT', 30, "Convert into is!");
static const CONVERT_INTO_IS_NOT_EMPTY = const AssistKind(
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 f58469d..1ae3201 100644
--- a/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/assist_internal.dart
@@ -97,6 +97,8 @@
_addProposal_addTypeAnnotation_SimpleFormalParameter();
_addProposal_addTypeAnnotation_VariableDeclaration();
_addProposal_assignToLocalVariable();
+ _addProposal_convertIntoFinalField();
+ _addProposal_convertIntoGetter();
_addProposal_convertDocumentationIntoBlock();
_addProposal_convertDocumentationIntoLine();
_addProposal_convertToBlockFunctionBody();
@@ -481,6 +483,113 @@
_addAssist(DartAssistKind.CONVERT_DOCUMENTATION_INTO_LINE, []);
}
+ void _addProposal_convertIntoFinalField() {
+ // Find the enclosing getter.
+ MethodDeclaration getter;
+ for (AstNode n = node; n != null; n = n.parent) {
+ if (n is MethodDeclaration) {
+ getter = n;
+ break;
+ }
+ if (n is SimpleIdentifier || n is TypeName || n is TypeArgumentList) {
+ continue;
+ }
+ break;
+ }
+ if (getter == null || !getter.isGetter) {
+ return;
+ }
+ // Check that there is no corresponding setter.
+ {
+ ExecutableElement element = getter.element;
+ if (element == null) {
+ return;
+ }
+ Element enclosing = element.enclosingElement;
+ if (enclosing is ClassElement) {
+ if (enclosing.getSetter(element.name) != null) {
+ return;
+ }
+ }
+ }
+ // Try to find the returned expression.
+ Expression expression;
+ {
+ FunctionBody body = getter.body;
+ if (body is ExpressionFunctionBody) {
+ expression = body.expression;
+ } else if (body is BlockFunctionBody) {
+ List<Statement> statements = body.block.statements;
+ if (statements.length == 1) {
+ Statement statement = statements.first;
+ if (statement is ReturnStatement) {
+ expression = statement.expression;
+ }
+ }
+ }
+ }
+ // Use the returned expression as the field initializer.
+ if (expression != null) {
+ AstNode beginNodeToReplace = getter.name;
+ String code = 'final';
+ if (getter.returnType != null) {
+ beginNodeToReplace = getter.returnType;
+ code += ' ' + _getNodeText(getter.returnType);
+ }
+ code += ' ' + _getNodeText(getter.name);
+ if (expression is! NullLiteral) {
+ code += ' = ' + _getNodeText(expression);
+ }
+ code += ';';
+ _addReplaceEdit(rangeStartEnd(beginNodeToReplace, getter), code);
+ _addAssist(DartAssistKind.CONVERT_INTO_FINAL_FIELD, []);
+ }
+ }
+
+ void _addProposal_convertIntoGetter() {
+ // Find the enclosing field declaration.
+ FieldDeclaration fieldDeclaration;
+ for (AstNode n = node; n != null; n = n.parent) {
+ if (n is FieldDeclaration) {
+ fieldDeclaration = n;
+ break;
+ }
+ if (n is SimpleIdentifier ||
+ n is VariableDeclaration ||
+ n is VariableDeclarationList ||
+ n is TypeName ||
+ n is TypeArgumentList) {
+ continue;
+ }
+ break;
+ }
+ if (fieldDeclaration == null) {
+ return;
+ }
+ // The field must be final and has only one variable.
+ VariableDeclarationList fieldList = fieldDeclaration.fields;
+ if (!fieldList.isFinal || fieldList.variables.length != 1) {
+ return;
+ }
+ VariableDeclaration field = fieldList.variables.first;
+ // Prepare the initializer.
+ Expression initializer = field.initializer;
+ if (initializer == null) {
+ return;
+ }
+ // Add proposal.
+ String code = '';
+ if (fieldList.type != null) {
+ code += _getNodeText(fieldList.type) + ' ';
+ }
+ code += 'get';
+ code += ' ' + _getNodeText(field.name);
+ code += ' => ' + _getNodeText(initializer);
+ code += ';';
+ _addReplaceEdit(rangeStartEnd(fieldList.keyword, fieldDeclaration), code);
+ _addAssist(DartAssistKind.CONVERT_INTO_GETTER, []);
+ }
+
void _addProposal_convertToBlockFunctionBody() {
FunctionBody body = getEnclosingFunctionBody();
// prepare expression body
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 117884d..4daa06e 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix_internal.dart
@@ -293,17 +293,17 @@
_addFix_updateConstructor_forUninitializedFinalFields();
}
if (errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER) {
- bool isAsync = _addFix_addAsync();
- if (!isAsync) {
- _addFix_undefinedClassAccessor_useSimilar();
- _addFix_createClass();
- _addFix_createField();
- _addFix_createGetter();
- _addFix_createFunction_forFunctionType();
- _addFix_importLibrary_withType();
- _addFix_importLibrary_withTopLevelVariable();
- _addFix_createLocalVariable();
- }
+ _addFix_undefinedClassAccessor_useSimilar();
+ _addFix_createClass();
+ _addFix_createField();
+ _addFix_createGetter();
+ _addFix_createFunction_forFunctionType();
+ _addFix_importLibrary_withType();
+ _addFix_importLibrary_withTopLevelVariable();
+ _addFix_createLocalVariable();
+ }
+ if (errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER_AWAIT) {
+ _addFix_addAsync();
}
if (errorCode == StaticTypeWarningCode.ILLEGAL_ASYNC_RETURN_TYPE) {
_addFix_illegalAsyncReturnType();
@@ -371,8 +371,8 @@
doSourceChange_addElementEdit(change, target, edit);
}
- void _addFix(FixKind kind, List args) {
- if (change.edits.isEmpty) {
+ void _addFix(FixKind kind, List args, {bool importsOnly: false}) {
+ if (change.edits.isEmpty && !importsOnly) {
return;
}
// configure Change
@@ -397,14 +397,12 @@
*/
bool _addFix_addAsync() {
AstNode node = this.node;
- if (_isAwaitNode()) {
- FunctionBody body = node.getAncestor((n) => n is FunctionBody);
- if (body != null && body.keyword == null) {
- _addReplaceEdit(rf.rangeStartLength(body, 0), 'async ');
- _replaceReturnTypeWithFuture(body);
- _addFix(DartFixKind.ADD_ASYNC, []);
- return true;
- }
+ FunctionBody body = node.getAncestor((n) => n is FunctionBody);
+ if (body != null && body.keyword == null) {
+ _addReplaceEdit(rf.rangeStartLength(body, 0), 'async ');
+ _replaceReturnTypeWithFuture(body);
+ _addFix(DartFixKind.ADD_ASYNC, []);
+ return true;
}
return false;
}
@@ -1349,7 +1347,10 @@
sb.append(prefix);
}
// return type
- _appendType(sb, element.type.returnType);
+ if (!isSetter) {
+ _appendType(sb, element.type.returnType);
+ }
+ // keyword
if (isGetter) {
sb.append('get ');
} else if (isSetter) {
@@ -1424,40 +1425,11 @@
_addFix(DartFixKind.REPLACE_RETURN_TYPE_FUTURE, []);
}
- void _addFix_importLibrary(FixKind kind, String importPath) {
- CompilationUnitElement libraryUnitElement =
- unitLibraryElement.definingCompilationUnit;
- CompilationUnit libraryUnit = getParsedUnit(libraryUnitElement);
- // prepare new import location
- int offset = 0;
- String prefix;
- String suffix;
- {
- // if no directives
- prefix = '';
- suffix = eol;
- CorrectionUtils libraryUtils = new CorrectionUtils(libraryUnit);
- // after last directive in library
- for (Directive directive in libraryUnit.directives) {
- if (directive is LibraryDirective || directive is ImportDirective) {
- offset = directive.end;
- prefix = eol;
- suffix = '';
- }
- }
- // if still beginning of file, skip shebang and line comments
- if (offset == 0) {
- CorrectionUtils_InsertDesc desc = libraryUtils.getInsertDescTop();
- offset = desc.offset;
- prefix = desc.prefix;
- suffix = '${desc.suffix}$eol';
- }
- }
- // insert new import
- String importSource = "${prefix}import '$importPath';$suffix";
- _addInsertEdit(offset, importSource, libraryUnitElement);
- // add proposal
- _addFix(kind, [importPath]);
+ void _addFix_importLibrary(FixKind kind, LibraryElement libraryElement) {
+ librariesToImport.add(libraryElement);
+ Source librarySource = libraryElement.source;
+ String libraryUri = getLibrarySourceUri(unitLibraryElement, librarySource);
+ _addFix(kind, [libraryUri], importsOnly: true);
}
void _addFix_importLibrary_withElement(String name, ElementKind kind) {
@@ -1544,7 +1516,7 @@
continue;
}
// add import
- _addFix_importLibrary(DartFixKind.IMPORT_LIBRARY_SDK, libraryUri);
+ _addFix_importLibrary(DartFixKind.IMPORT_LIBRARY_SDK, libraryElement);
}
}
// check project libraries
@@ -1576,21 +1548,8 @@
if (element.kind != kind) {
continue;
}
- // prepare "library" file
- String libraryFile = librarySource.fullName;
- // may be "package:" URI
- {
- String libraryPackageUri = findNonFileUri(context, libraryFile);
- if (libraryPackageUri != null) {
- _addFix_importLibrary(
- DartFixKind.IMPORT_LIBRARY_PROJECT, libraryPackageUri);
- continue;
- }
- }
- // relative URI
- String relativeFile = relative(libraryFile, from: unitLibraryFolder);
- relativeFile = split(relativeFile).join('/');
- _addFix_importLibrary(DartFixKind.IMPORT_LIBRARY_PROJECT, relativeFile);
+ _addFix_importLibrary(
+ DartFixKind.IMPORT_LIBRARY_PROJECT, libraryElement);
}
}
}
diff --git a/pkg/analysis_server/lib/src/services/correction/util.dart b/pkg/analysis_server/lib/src/services/correction/util.dart
index 551964a..445aab2 100644
--- a/pkg/analysis_server/lib/src/services/correction/util.dart
+++ b/pkg/analysis_server/lib/src/services/correction/util.dart
@@ -33,38 +33,91 @@
Set<LibraryElement> libraries) {
CompilationUnitElement libUnitElement = targetLibrary.definingCompilationUnit;
CompilationUnit libUnit = getParsedUnit(libUnitElement);
- // prepare new import location
- int offset = 0;
- String prefix;
- String suffix;
- {
- // if no directives
- prefix = '';
- CorrectionUtils libraryUtils = new CorrectionUtils(libUnit);
- String eol = libraryUtils.endOfLine;
- suffix = eol;
- // after last directive in library
- for (Directive directive in libUnit.directives) {
- if (directive is LibraryDirective || directive is ImportDirective) {
- offset = directive.end;
- prefix = eol;
- suffix = '';
- }
- }
- // if still at the beginning of the file, skip shebang and line comments
- if (offset == 0) {
- CorrectionUtils_InsertDesc desc = libraryUtils.getInsertDescTop();
- offset = desc.offset;
- prefix = desc.prefix;
- suffix = desc.suffix + eol;
+ CorrectionUtils libUtils = new CorrectionUtils(libUnit);
+ String eol = libUtils.endOfLine;
+ // Prepare information about existing imports.
+ LibraryDirective libraryDirective;
+ List<_ImportDirectiveInfo> importDirectives = <_ImportDirectiveInfo>[];
+ for (Directive directive in libUnit.directives) {
+ if (directive is LibraryDirective) {
+ libraryDirective = directive;
+ } else if (directive is ImportDirective) {
+ importDirectives.add(new _ImportDirectiveInfo(
+ directive.uriContent, directive.offset, directive.end));
}
}
- // insert imports
- for (LibraryElement library in libraries) {
- String importPath = getLibrarySourceUri(targetLibrary, library.source);
- String importCode = "${prefix}import '$importPath';$suffix";
- doSourceChange_addElementEdit(
- change, targetLibrary, new SourceEdit(offset, 0, importCode));
+
+ // Prepare all URIs to import.
+ List<String> uriList = libraries
+ .map((library) => getLibrarySourceUri(targetLibrary, library.source))
+ .toList();
+ uriList.sort((a, b) => a.compareTo(b));
+
+ // Insert imports: between existing imports.
+ if (importDirectives.isNotEmpty) {
+ bool isFirstPackage = true;
+ for (String importUri in uriList) {
+ bool inserted = false;
+ bool isPackage = importUri.startsWith('package:');
+ bool isAfterDart = false;
+ for (_ImportDirectiveInfo existingImport in importDirectives) {
+ if (existingImport.uri.startsWith('dart:')) {
+ isAfterDart = true;
+ }
+ if (existingImport.uri.startsWith('package:')) {
+ isFirstPackage = false;
+ }
+ if (importUri.compareTo(existingImport.uri) < 0) {
+ String importCode = "import '$importUri';$eol";
+ doSourceChange_addElementEdit(change, targetLibrary,
+ new SourceEdit(existingImport.offset, 0, importCode));
+ inserted = true;
+ break;
+ }
+ }
+ if (!inserted) {
+ String importCode = "${eol}import '$importUri';";
+ if (isPackage && isFirstPackage && isAfterDart) {
+ importCode = eol + importCode;
+ }
+ doSourceChange_addElementEdit(change, targetLibrary,
+ new SourceEdit(importDirectives.last.end, 0, importCode));
+ }
+ if (isPackage) {
+ isFirstPackage = false;
+ }
+ }
+ return;
+ }
+
+ // Insert imports: after the library directive.
+ if (libraryDirective != null) {
+ String prefix = eol + eol;
+ for (String importUri in uriList) {
+ String importCode = "${prefix}import '$importUri';";
+ prefix = eol;
+ doSourceChange_addElementEdit(change, targetLibrary,
+ new SourceEdit(libraryDirective.end, 0, importCode));
+ }
+ return;
+ }
+
+ // If still at the beginning of the file, skip shebang and line comments.
+ {
+ CorrectionUtils_InsertDesc desc = libUtils.getInsertDescTop();
+ int offset = desc.offset;
+ for (int i = 0; i < uriList.length; i++) {
+ String importUri = uriList[i];
+ String importCode = "import '$importUri';$eol";
+ if (i == 0) {
+ importCode = desc.prefix + importCode;
+ }
+ if (i == uriList.length - 1) {
+ importCode = importCode + desc.suffix;
+ }
+ doSourceChange_addElementEdit(
+ change, targetLibrary, new SourceEdit(offset, 0, importCode));
+ }
}
}
@@ -1466,6 +1519,14 @@
}
}
+class _ImportDirectiveInfo {
+ final String uri;
+ final int offset;
+ final int end;
+
+ _ImportDirectiveInfo(this.uri, this.offset, this.end);
+}
+
/**
* A container with a source and its precedence.
*/
diff --git a/pkg/analysis_server/lib/src/services/search/hierarchy.dart b/pkg/analysis_server/lib/src/services/search/hierarchy.dart
index c6b552f..b6e1c9e 100644
--- a/pkg/analysis_server/lib/src/services/search/hierarchy.dart
+++ b/pkg/analysis_server/lib/src/services/search/hierarchy.dart
@@ -76,8 +76,8 @@
Future<Set<ClassMemberElement>> getHierarchyMembers(
SearchEngine searchEngine, ClassMemberElement member) {
Set<ClassMemberElement> result = new HashSet<ClassMemberElement>();
- // constructor
- if (member is ConstructorElement) {
+ // static elements
+ if (member.isStatic || member is ConstructorElement) {
result.add(member);
return new Future.value(result);
}
diff --git a/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart b/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart
index 2d6f815..47eb392 100644
--- a/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart
+++ b/pkg/analysis_server/lib/src/services/search/search_engine_internal.dart
@@ -35,7 +35,8 @@
}
@override
- Future<List<SearchMatch>> searchMemberDeclarations(String pattern) {
+ Future<List<SearchMatch>> searchMemberDeclarations(String name) {
+ String pattern = '^$name\$';
return _searchDefinedNames(pattern, IndexNameKind.classMember);
}
diff --git a/pkg/analysis_server/lib/src/status/get_handler.dart b/pkg/analysis_server/lib/src/status/get_handler.dart
index 0e9a2ed..13a149a 100644
--- a/pkg/analysis_server/lib/src/status/get_handler.dart
+++ b/pkg/analysis_server/lib/src/status/get_handler.dart
@@ -21,6 +21,7 @@
import 'package:analysis_server/src/socket_server.dart';
import 'package:analysis_server/src/status/ast_writer.dart';
import 'package:analysis_server/src/status/element_writer.dart';
+import 'package:analysis_server/src/status/memory_use.dart';
import 'package:analysis_server/src/status/validator.dart';
import 'package:analysis_server/src/utilities/average.dart';
import 'package:analyzer/dart/ast/ast.dart';
@@ -258,6 +259,11 @@
static const String ELEMENT_PATH = '/element';
/**
+ * The path used to request an analysis of the memory use of the analyzer.
+ */
+ static const String MEMORY_USE_PATH = '/memoryUse';
+
+ /**
* The path used to request an overlay contents.
*/
static const String OVERLAY_PATH = '/overlay';
@@ -390,6 +396,8 @@
_returnDiagnosticInfo(request);
} else if (path == ELEMENT_PATH) {
_returnElement(request);
+ } else if (path == MEMORY_USE_PATH) {
+ _returnMemoryUsage(request);
} else if (path == OVERLAY_PATH) {
_returnOverlayContents(request);
} else if (path == OVERLAYS_PATH) {
@@ -812,6 +820,30 @@
classes: [null, "right"]);
}
buffer.write('</table>');
+
+ {
+ buffer.write('<p><b>Cache consistency statistics</b></p>');
+ buffer.write(
+ '<table style="border-collapse: separate; border-spacing: 10px 5px;">');
+ _writeRow(buffer, ['Name', 'Count'], header: true);
+ _writeRow(buffer, [
+ 'Modified',
+ PerformanceStatistics
+ .cacheConsistencyValidationStatistics.numOfModified
+ ], classes: [
+ null,
+ "right"
+ ]);
+ _writeRow(buffer, [
+ 'Deleted',
+ PerformanceStatistics
+ .cacheConsistencyValidationStatistics.numOfDeleted
+ ], classes: [
+ null,
+ "right"
+ ]);
+ buffer.write('</table>');
+ }
}, (StringBuffer buffer) {
//
// Write task model timing information.
@@ -1620,6 +1652,84 @@
});
}
+ void _returnMemoryUsage(HttpRequest request) {
+ _writeResponse(request, (StringBuffer buffer) {
+ _writePage(buffer, 'Analysis Server - Memory Use', [],
+ (StringBuffer buffer) {
+ AnalysisServer server = _server.analysisServer;
+ MemoryUseData data = new MemoryUseData();
+ data.processAnalysisServer(server);
+ Map<Type, Set> instances = data.instances;
+ List<Type> instanceTypes = instances.keys.toList();
+ instanceTypes.sort((Type left, Type right) =>
+ left.toString().compareTo(right.toString()));
+ Map<Type, Set> ownerMap = data.ownerMap;
+ List<Type> ownerTypes = ownerMap.keys.toList();
+ ownerTypes.sort((Type left, Type right) =>
+ left.toString().compareTo(right.toString()));
+
+ _writeTwoColumns(buffer, (StringBuffer buffer) {
+ buffer.write('<h3>Instance Counts (reachable from contexts)</h3>');
+ buffer.write('<table>');
+ _writeRow(buffer, ['Count', 'Class name'], header: true);
+ instanceTypes.forEach((Type type) {
+ _writeRow(buffer, [instances[type].length, type],
+ classes: ['right', null]);
+ });
+ buffer.write('</table>');
+
+ buffer.write(
+ '<h3>Ownership (which classes of objects hold on to others)</h3>');
+ buffer.write('<table>');
+ _writeRow(buffer, ['Referenced Type', 'Referencing Types'],
+ header: true);
+ ownerTypes.forEach((Type type) {
+ List<String> referencingTypes =
+ ownerMap[type].map((Type type) => type.toString()).toList();
+ referencingTypes.sort();
+ _writeRow(buffer, [type, referencingTypes.join('<br>')]);
+ });
+ buffer.write('</table>');
+
+ buffer.write('<h3>Other Data</h3>');
+ buffer.write('<p>');
+ buffer.write(data.uniqueTargetedResults.length);
+ buffer.write(' non-equal TargetedResults</p>');
+ buffer.write('<p>');
+ buffer.write(data.uniqueLSUs.length);
+ buffer.write(' non-equal LibrarySpecificUnits</p>');
+ int count = data.mismatchedTargets.length;
+ buffer.write('<p>');
+ buffer.write(count);
+ buffer.write(' mismatched targets</p>');
+ if (count < 100) {
+ for (AnalysisTarget target in data.mismatchedTargets) {
+ buffer.write(target);
+ buffer.write('<br>');
+ }
+ }
+ }, (StringBuffer buffer) {
+ void writeCountMap(String title, Map<Type, int> counts) {
+ List<Type> classNames = counts.keys.toList();
+ classNames.sort((Type left, Type right) =>
+ left.toString().compareTo(right.toString()));
+
+ buffer.write('<h3>$title</h3>');
+ buffer.write('<table>');
+ _writeRow(buffer, ['Count', 'Class name'], header: true);
+ classNames.forEach((Type type) {
+ _writeRow(buffer, [counts[type], type], classes: ['right', null]);
+ });
+ buffer.write('</table>');
+ }
+ writeCountMap('Directly Held AST Nodes', data.directNodeCounts);
+ writeCountMap('Indirectly Held AST Nodes', data.indirectNodeCounts);
+ writeCountMap('Directly Held Elements', data.elementCounts);
+ });
+ });
+ });
+ }
+
void _returnOverlayContents(HttpRequest request) {
String path = request.requestedUri.queryParameters[PATH_PARAM];
if (path == null) {
@@ -2204,6 +2314,7 @@
int length = keys.length;
buffer.write('{');
for (int i = 0; i < length; i++) {
+ buffer.write('<br>');
String key = keys[i];
if (i > 0) {
buffer.write(', ');
@@ -2212,7 +2323,7 @@
buffer.write(' = ');
buffer.write(map[key]);
}
- buffer.write('}');
+ buffer.write('<br>}');
}
/**
@@ -2265,6 +2376,8 @@
'table.column {border: 0px solid black; width: 100%; table-layout: fixed;}');
buffer.write('td.column {vertical-align: top; width: 50%;}');
buffer.write('td.right {text-align: right;}');
+ buffer.write('th {text-align: left; vertical-align:top;}');
+ buffer.write('tr {vertical-align:top;}');
buffer.write('</style>');
buffer.write('</head>');
@@ -2423,6 +2536,9 @@
buffer.write('<p>');
buffer.write(makeLink(DIAGNOSTIC_PATH, {}, 'General diagnostics'));
buffer.write('</p>');
+ buffer.write('<p>');
+ buffer.write(makeLink(MEMORY_USE_PATH, {}, 'Memory usage'));
+ buffer.write(' <small>(long running)</small></p>');
}, (StringBuffer buffer) {
_writeSubscriptionList(buffer, ServerService.VALUES, services);
});
diff --git a/pkg/analysis_server/lib/src/status/memory_use.dart b/pkg/analysis_server/lib/src/status/memory_use.dart
new file mode 100644
index 0000000..92657bc
--- /dev/null
+++ b/pkg/analysis_server/lib/src/status/memory_use.dart
@@ -0,0 +1,314 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library analysis_server.src.status.memory_use;
+
+import 'dart:collection';
+
+import 'package:analysis_server/src/analysis_server.dart';
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/visitor.dart';
+import 'package:analyzer/src/context/cache.dart';
+import 'package:analyzer/src/context/context.dart' show AnalysisContextImpl;
+import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/generated/engine.dart';
+import 'package:analyzer/src/generated/sdk.dart';
+import 'package:analyzer/task/dart.dart';
+import 'package:analyzer/task/model.dart';
+
+/**
+ * A visitor that will count the number of instances of each type of AST node.
+ */
+class AstNodeCounter extends UnifyingAstVisitor<Null> {
+ /**
+ * A table mapping the types of the AST nodes to the number of instances
+ * visited.
+ */
+ final Map<Type, int> nodeCounts;
+
+ /**
+ * Initialize a newly created counter to increment the counts in the given map
+ * of [nodeCounts].
+ */
+ AstNodeCounter(this.nodeCounts);
+
+ @override
+ visitNode(AstNode node) {
+ Type type = node.runtimeType;
+ int count = nodeCounts[type] ?? 0;
+ nodeCounts[type] = count + 1;
+ super.visitNode(node);
+ }
+}
+
+/**
+ * A visitor that will count the number of instances of each type of element.
+ */
+class ElementCounter extends GeneralizingElementVisitor<Null> {
+ /**
+ * A table mapping the types of the elements to the number of instances
+ * visited.
+ */
+ final Map<Type, int> elementCounts;
+
+ /**
+ * A table mapping the types of the AST nodes to the number of instances
+ * visited.
+ */
+ final Map<Type, int> nodeCounts;
+
+ /**
+ * Initialize a newly created counter to increment the counts in the given map
+ * of [elementCounts].
+ */
+ ElementCounter(this.elementCounts, this.nodeCounts);
+
+ @override
+ visitConstructorElement(ConstructorElement element) {
+ if (element is ConstructorElementImpl) {
+ List<ConstructorInitializer> initializers = element.constantInitializers;
+ if (initializers != null) {
+ initializers.forEach((ConstructorInitializer initializer) {
+ _countNodes(initializer);
+ });
+ }
+ }
+ visitElement(element);
+ }
+
+ @override
+ visitElement(Element element) {
+ Type type = element.runtimeType;
+ int count = elementCounts[type] ?? 0;
+ elementCounts[type] = count + 1;
+ element.metadata.forEach((ElementAnnotation annotation) {
+ if (annotation is ElementAnnotationImpl) {
+ _countNodes(annotation.annotationAst);
+ }
+ });
+ super.visitElement(element);
+ }
+
+ visitFieldElement(FieldElement element) {
+ if (element is ConstVariableElement) {
+ _countInitializer(element as ConstVariableElement);
+ }
+ visitElement(element);
+ }
+
+ visitLocalVariableElement(LocalVariableElement element) {
+ if (element is ConstVariableElement) {
+ _countInitializer(element as ConstVariableElement);
+ }
+ visitElement(element);
+ }
+
+ visitParameterElement(ParameterElement element) {
+ if (element is ConstVariableElement) {
+ _countInitializer(element as ConstVariableElement);
+ }
+ visitElement(element);
+ }
+
+ visitTopLevelVariableElement(TopLevelVariableElement element) {
+ if (element is ConstVariableElement) {
+ _countInitializer(element as ConstVariableElement);
+ }
+ visitElement(element);
+ }
+
+ void _countInitializer(ConstVariableElement element) {
+ _countNodes(element.constantInitializer);
+ }
+
+ void _countNodes(AstNode node) {
+ if (node != null) {
+ node.accept(new AstNodeCounter(nodeCounts));
+ }
+ }
+}
+
+/**
+ * A set used when the number of instances of some type is too large to be kept.
+ */
+class InfiniteSet implements Set {
+ /**
+ * The unique instance of this class.
+ */
+ static final InfiniteSet instance = new InfiniteSet();
+
+ @override
+ int get length => -1;
+
+ @override
+ dynamic noSuchMethod(Invocation invocation) {
+ throw new UnsupportedError('Do not use instances of InfiniteSet');
+ }
+}
+
+/**
+ * Computes memory usage data by traversing the data structures reachable from
+ * an analysis server.
+ */
+class MemoryUseData {
+ /**
+ * The maximum size of an instance set.
+ */
+ static const int maxInstanceSetSize = 1000000;
+
+ /**
+ * A table mapping classes to instances of the class.
+ */
+ Map<Type, Set> instances = new HashMap<Type, Set>();
+
+ /**
+ * A table mapping classes to the classes of objects from which they were
+ * reached.
+ */
+ Map<Type, Set<Type>> ownerMap = new HashMap<Type, Set<Type>>();
+
+ /**
+ * A set of all the library specific units, using equality rather than
+ * identity in order to determine whether re-using equal instances would save
+ * significant space.
+ */
+ Set<LibrarySpecificUnit> uniqueLSUs = new HashSet<LibrarySpecificUnit>();
+
+ /**
+ * A set of all the targeted results, using equality rather than identity in
+ * order to determine whether re-using equal instances would save significant
+ * space.
+ */
+ Set<TargetedResult> uniqueTargetedResults = new HashSet<TargetedResult>();
+
+ /**
+ * A set containing all of the analysis targets for which the key in the
+ * cache partition is not the same instance as the target stored in the entry.
+ */
+ Set<AnalysisTarget> mismatchedTargets = new HashSet<AnalysisTarget>();
+
+ /**
+ * A table mapping the types of AST nodes to the number of instances being
+ * held directly (as values in the cache).
+ */
+ Map<Type, int> directNodeCounts = new HashMap<Type, int>();
+
+ /**
+ * A table mapping the types of AST nodes to the number of instances being
+ * held indirectly (such as nodes reachable from element models).
+ */
+ Map<Type, int> indirectNodeCounts = new HashMap<Type, int>();
+
+ /**
+ * A table mapping the types of the elements to the number of instances being
+ * held directly (as values in the cache).
+ */
+ final Map<Type, int> elementCounts = new HashMap<Type, int>();
+
+ /**
+ * Initialize a newly created instance.
+ */
+ MemoryUseData();
+
+ /**
+ * Traverse an analysis [server] to compute memory usage data.
+ */
+ void processAnalysisServer(AnalysisServer server) {
+ _recordInstance(server, null);
+ Iterable<AnalysisContext> contexts = server.analysisContexts;
+ for (AnalysisContextImpl context in contexts) {
+ _processAnalysisContext(context, server);
+ }
+ DartSdkManager manager = server.sdkManager;
+ List<SdkDescription> descriptors = manager.sdkDescriptors;
+ for (SdkDescription descriptor in descriptors) {
+ _processAnalysisContext(
+ manager.getSdk(descriptor, () => null).context, manager);
+ }
+ }
+
+ void _processAnalysisContext(AnalysisContextImpl context, Object owner) {
+ _recordInstance(context, owner);
+ _recordInstance(context.analysisCache, context);
+ CachePartition partition = context.privateAnalysisCachePartition;
+ Map<AnalysisTarget, CacheEntry> map = partition.entryMap;
+ map.forEach((AnalysisTarget target, CacheEntry entry) {
+ _processAnalysisTarget(target, partition);
+ _processCacheEntry(entry, partition);
+ if (!identical(entry.target, target)) {
+ mismatchedTargets.add(target);
+ }
+ });
+ }
+
+ void _processAnalysisTarget(AnalysisTarget target, Object owner) {
+ _recordInstance(target, owner);
+ }
+
+ void _processCacheEntry(CacheEntry entry, Object owner) {
+ _recordInstance(entry, owner);
+ List<ResultDescriptor> descriptors = entry.nonInvalidResults;
+ for (ResultDescriptor descriptor in descriptors) {
+ _recordInstance(descriptor, entry);
+ _processResultData(entry.getResultDataOrNull(descriptor), entry);
+ }
+ }
+
+ void _processResultData(ResultData resultData, Object owner) {
+ _recordInstance(resultData, owner);
+ if (resultData != null) {
+ _recordInstance(resultData.state, resultData);
+ _recordInstance(resultData.value, resultData,
+ onFirstOccurrence: (Object object) {
+ if (object is AstNode) {
+ object.accept(new AstNodeCounter(directNodeCounts));
+ } else if (object is Element) {
+ object.accept(new ElementCounter(elementCounts, indirectNodeCounts));
+ }
+ });
+ resultData.dependedOnResults.forEach((TargetedResult result) =>
+ _processTargetedResult(result, resultData));
+ resultData.dependentResults.forEach((TargetedResult result) =>
+ _processTargetedResult(result, resultData));
+ }
+ }
+
+ void _processTargetedResult(TargetedResult result, Object owner) {
+ _recordInstance(result, owner);
+ uniqueTargetedResults.add(result);
+ _recordInstance(result.target, result);
+ _recordInstance(result.result, result);
+ }
+
+ /**
+ * Record the given [instance] that was found. If this is the first time that
+ * the instance has been found, execute the [onFirstOccurrence] function.
+ *
+ * Note that instances will not be recorded if there are more than
+ * [maxInstanceSetSize] instances of the same type, and that the
+ * [onFirstOccurrence] function will not be executed if the instance is not
+ * recorded.
+ */
+ void _recordInstance(Object instance, Object owner,
+ {void onFirstOccurrence(Object object)}) {
+ Type type = instance.runtimeType;
+ Set instanceSet = instances.putIfAbsent(type, () => new HashSet.identity());
+ if (instanceSet != InfiniteSet.instance) {
+ if (instanceSet.add(instance) && onFirstOccurrence != null) {
+ onFirstOccurrence(instance);
+ }
+ if (instanceSet.length >= maxInstanceSetSize) {
+ instances[type] = InfiniteSet.instance;
+ }
+ }
+ ownerMap
+ .putIfAbsent(instance.runtimeType, () => new HashSet<Type>())
+ .add(owner.runtimeType);
+ if (instance is LibrarySpecificUnit) {
+ uniqueLSUs.add(instance);
+ }
+ }
+}
diff --git a/pkg/analysis_server/pubspec.yaml b/pkg/analysis_server/pubspec.yaml
index 03722a1..9b4a4ff 100644
--- a/pkg/analysis_server/pubspec.yaml
+++ b/pkg/analysis_server/pubspec.yaml
@@ -9,6 +9,7 @@
analyzer: ^0.27.0
args: '>=0.13.0 <0.14.0'
dart_style: '>=0.2.0 <0.3.0'
+ isolate: ^0.2.2
linter: ^0.1.16
logging: any
path: any
diff --git a/pkg/analysis_server/test/analysis_server_test.dart b/pkg/analysis_server/test/analysis_server_test.dart
index eaea9a6..7699859e 100644
--- a/pkg/analysis_server/test/analysis_server_test.dart
+++ b/pkg/analysis_server/test/analysis_server_test.dart
@@ -447,7 +447,6 @@
AnalysisResult firstResult = new AnalysisResult([notice], 0, '', 0);
AnalysisResult lastResult = new AnalysisResult(null, 1, '', 1);
when(context.analysisOptions).thenReturn(new AnalysisOptionsImpl());
- when(context.validateCacheConsistency()).thenReturn(false);
when(context.performAnalysisTask)
.thenReturnList([firstResult, firstResult, firstResult, lastResult]);
server.serverServices.add(ServerService.STATUS);
diff --git a/pkg/analysis_server/test/context_manager_test.dart b/pkg/analysis_server/test/context_manager_test.dart
index 2f481cc..5b2416e 100644
--- a/pkg/analysis_server/test/context_manager_test.dart
+++ b/pkg/analysis_server/test/context_manager_test.dart
@@ -2659,7 +2659,7 @@
}
}
resolvers.addAll(disposition.createPackageUriResolvers(resourceProvider));
- resolvers.add(new ResourceUriResolver(PhysicalResourceProvider.INSTANCE));
+ resolvers.add(new ResourceUriResolver(resourceProvider));
currentContext.analysisOptions = options;
currentContext.sourceFactory =
new SourceFactory(resolvers, disposition.packages);
diff --git a/pkg/analysis_server/test/domain_completion_test.dart b/pkg/analysis_server/test/domain_completion_test.dart
index ec7c520..81d8a35 100644
--- a/pkg/analysis_server/test/domain_completion_test.dart
+++ b/pkg/analysis_server/test/domain_completion_test.dart
@@ -51,9 +51,9 @@
test_ArgumentList_imported_function_named_param_label1() async {
addTestFile('main() { int.parse("16", r^: 16);}');
await getSuggestions();
- assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'radix: ',
+ assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'radix',
relevance: DART_RELEVANCE_NAMED_PARAMETER);
- assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'onError: ',
+ assertHasResult(CompletionSuggestionKind.NAMED_ARGUMENT, 'onError',
relevance: DART_RELEVANCE_NAMED_PARAMETER);
expect(suggestions, hasLength(2));
}
diff --git a/pkg/analysis_server/test/integration/analysis/highlights_test2.dart b/pkg/analysis_server/test/integration/analysis/highlights_test2.dart
index 3ac66ce..bd07449 100644
--- a/pkg/analysis_server/test/integration/analysis/highlights_test2.dart
+++ b/pkg/analysis_server/test/integration/analysis/highlights_test2.dart
@@ -20,9 +20,11 @@
@reflectiveTest
class AnalysisHighlightsTest extends AbstractAnalysisServerIntegrationTest {
- Future startServer({int servicesPort}) {
+ Future startServer({int servicesPort, bool checked: true}) {
return server.start(
- servicesPort: servicesPort, useAnalysisHighlight2: true);
+ servicesPort: servicesPort,
+ checked: checked,
+ useAnalysisHighlight2: true);
}
test_highlights() {
diff --git a/pkg/analysis_server/test/integration/integration_tests.dart b/pkg/analysis_server/test/integration/integration_tests.dart
index 9e764a0..9835a1e 100644
--- a/pkg/analysis_server/test/integration/integration_tests.dart
+++ b/pkg/analysis_server/test/integration/integration_tests.dart
@@ -205,8 +205,8 @@
/**
* Start [server].
*/
- Future startServer({int servicesPort}) =>
- server.start(servicesPort: servicesPort);
+ Future startServer({int servicesPort, bool checked: true}) =>
+ server.start(servicesPort: servicesPort, checked: checked);
/**
* After every test, the server is stopped and [sourceDirectory] is deleted.
@@ -601,6 +601,7 @@
int diagnosticPort,
bool profileServer: false,
int servicesPort,
+ bool checked: true,
bool useAnalysisHighlight2: false}) {
if (_process != null) {
throw new Exception('Process already started');
@@ -627,7 +628,9 @@
if (Platform.packageRoot != null) {
arguments.add('--package-root=${Platform.packageRoot}');
}
- arguments.add('--checked');
+ if (checked) {
+ arguments.add('--checked');
+ }
arguments.add(serverPath);
if (diagnosticPort != null) {
arguments.add('--port');
diff --git a/pkg/analysis_server/test/search/element_references_test.dart b/pkg/analysis_server/test/search/element_references_test.dart
index 809a962..cdd7e13 100644
--- a/pkg/analysis_server/test/search/element_references_test.dart
+++ b/pkg/analysis_server/test/search/element_references_test.dart
@@ -268,13 +268,13 @@
test_hierarchy_method() async {
addTestFile('''
class A {
- mmm() {} // in A
+ mmm(_) {} // in A
}
class B extends A {
- mmm() {} // in B
+ mmm(_) {} // in B
}
class C extends B {
- mmm() {} // in C
+ mmm(_) {} // in C
}
main(A a, B b, C c) {
a.mmm(10);
@@ -282,13 +282,36 @@
c.mmm(30);
}
''');
- await findElementReferences('mmm() {} // in B', false);
+ await findElementReferences('mmm(_) {} // in B', false);
expect(searchElement.kind, ElementKind.METHOD);
assertHasResult(SearchResultKind.INVOCATION, 'mmm(10)');
assertHasResult(SearchResultKind.INVOCATION, 'mmm(20)');
assertHasResult(SearchResultKind.INVOCATION, 'mmm(30)');
}
+ test_hierarchy_method_static() async {
+ addTestFile('''
+class A {
+ static void mmm(_) {} // in A
+}
+class B extends A {
+ static void mmm(_) {} // in B
+}
+class C extends B {
+ static void mmm(_) {} // in C
+}
+main() {
+ A.mmm(10);
+ B.mmm(20);
+ C.mmm(30);
+}
+''');
+ await findElementReferences('mmm(_) {} // in B', false);
+ expect(searchElement.kind, ElementKind.METHOD);
+ expect(results, hasLength(1));
+ assertHasResult(SearchResultKind.INVOCATION, 'mmm(20)');
+ }
+
test_label() async {
addTestFile('''
main() {
diff --git a/pkg/analysis_server/test/search/top_level_declarations_test.dart b/pkg/analysis_server/test/search/top_level_declarations_test.dart
index 81fa08b..8b1829c 100644
--- a/pkg/analysis_server/test/search/top_level_declarations_test.dart
+++ b/pkg/analysis_server/test/search/top_level_declarations_test.dart
@@ -39,6 +39,9 @@
Request request =
new SearchFindTopLevelDeclarationsParams(pattern).toRequest('0');
Response response = await waitResponse(request);
+ if (response.error != null) {
+ return response.error;
+ }
searchId =
new SearchFindTopLevelDeclarationsResult.fromResponse(response).id;
return waitForSearchResults();
@@ -71,4 +74,9 @@
assertHasDeclaration(ElementKind.TOP_LEVEL_VARIABLE, 'E');
assertNoDeclaration(ElementKind.CLASS, 'ABC');
}
+
+ test_invalidRegex() async {
+ var result = await findTopLevelDeclarations('[A');
+ expect(result, new isInstanceOf<RequestError>());
+ }
}
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 569610c..f7cca21 100644
--- a/pkg/analysis_server/test/services/completion/completion_target_test.dart
+++ b/pkg/analysis_server/test/services/completion/completion_target_test.dart
@@ -61,6 +61,16 @@
assertTarget(')', '()', argIndex: 0);
}
+ test_ArgumentList_InstanceCreationExpression2() {
+ // ArgumentList InstanceCreationExpression Block
+ addTestSource('main() {new Foo(a,^)}');
+ if (context.analysisOptions.enableTrailingCommas) {
+ assertTarget(')', '(a)', argIndex: 1);
+ } else {
+ assertTarget('', '(a, )', argIndex: 1);
+ }
+ }
+
test_ArgumentList_InstanceCreationExpression_functionArg2() {
// ArgumentList InstanceCreationExpression Block
addTestSource('main() {new B(^)} class B{B(f()){}}');
@@ -85,10 +95,20 @@
assertTarget('n', '(n)', argIndex: 0);
}
+ test_ArgumentList_MethodInvocation3a() {
+ // ArgumentList MethodInvocation Block
+ addTestSource('main() {foo((n)^)}');
+ assertTarget(')', '((n))', argIndex: 0);
+ }
+
test_ArgumentList_MethodInvocation4() {
// ArgumentList MethodInvocation Block
addTestSource('main() {foo(n,^)}');
- assertTarget('', '(n, )', argIndex: 1);
+ if (context.analysisOptions.enableTrailingCommas) {
+ assertTarget(')', '(n)', argIndex: 1);
+ } else {
+ assertTarget('', '(n, )', argIndex: 1);
+ }
}
test_ArgumentList_MethodInvocation_functionArg() {
diff --git a/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart b/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart
index db17859..44ddc2a 100644
--- a/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart
+++ b/pkg/analysis_server/test/services/completion/dart/arglist_contributor_test.dart
@@ -81,10 +81,11 @@
* the only suggestions.
*/
void assertSuggestArgumentsAndTypes(
- {Map<String, String> namedArgumentsWithTypes}) {
+ {Map<String, String> namedArgumentsWithTypes, bool includeColon: true}) {
List<CompletionSuggestion> expected = new List<CompletionSuggestion>();
namedArgumentsWithTypes.forEach((String name, String type) {
- expected.add(assertSuggest('$name: ',
+ String completion = includeColon ? '$name: ' : name;
+ expected.add(assertSuggest(completion,
csKind: CompletionSuggestionKind.NAMED_ARGUMENT,
relevance: DART_RELEVANCE_NAMED_PARAMETER,
paramName: name,
@@ -432,7 +433,8 @@
addTestSource('main() { int.parse("16", r^: 16);}');
await computeSuggestions();
assertSuggestArgumentsAndTypes(
- namedArgumentsWithTypes: {'radix': 'int', 'onError': '(String) → int'});
+ namedArgumentsWithTypes: {'radix': 'int', 'onError': '(String) → int'},
+ includeColon: false);
}
test_ArgumentList_imported_function_named_param_label2() async {
diff --git a/pkg/analysis_server/test/services/correction/assist_test.dart b/pkg/analysis_server/test/services/correction/assist_test.dart
index 5c84d35..4188664 100644
--- a/pkg/analysis_server/test/services/correction/assist_test.dart
+++ b/pkg/analysis_server/test/services/correction/assist_test.dart
@@ -326,8 +326,8 @@
'future in',
DartAssistKind.ADD_TYPE_ANNOTATION,
'''
-import 'my_lib.dart';
import 'dart:async';
+import 'my_lib.dart';
main() {
for (Future<int> future in getFutures()) {
}
@@ -466,8 +466,8 @@
'v =',
DartAssistKind.ADD_TYPE_ANNOTATION,
'''
-import 'my_lib.dart';
import 'dart:async';
+import 'my_lib.dart';
main() {
Future<int> v = getFutureInt();
}
@@ -515,8 +515,8 @@
resultCode,
'''
library my_app;
-import 'my_lib.dart';
import 'dart:async';
+import 'my_lib.dart';
part 'test.dart';
''');
}
@@ -556,8 +556,8 @@
'v =',
DartAssistKind.ADD_TYPE_ANNOTATION,
'''
-import 'ccc/lib_b.dart';
import 'aa/bbb/lib_a.dart';
+import 'ccc/lib_b.dart';
main() {
MyClass v = newMyClass();
}
@@ -1432,6 +1432,177 @@
''');
}
+ test_convertToFinalField_BAD_hasSetter_inThisClass() async {
+ resolveTestUnit('''
+class A {
+ int get foo => null;
+ void set foo(_) {}
+}
+''');
+ await assertNoAssistAt('get foo', DartAssistKind.CONVERT_INTO_FINAL_FIELD);
+ }
+
+ test_convertToFinalField_BAD_notExpressionBody() async {
+ resolveTestUnit('''
+class A {
+ int get foo {
+ int v = 1 + 2;
+ return v + 3;
+ }
+}
+''');
+ await assertNoAssistAt('get foo', DartAssistKind.CONVERT_INTO_FINAL_FIELD);
+ }
+
+ test_convertToFinalField_BAD_notGetter() async {
+ resolveTestUnit('''
+class A {
+ int foo() => 42;
+}
+''');
+ await assertNoAssistAt('foo', DartAssistKind.CONVERT_INTO_FINAL_FIELD);
+ }
+
+ test_convertToFinalField_OK_blockBody_onlyReturnStatement() async {
+ resolveTestUnit('''
+class A {
+ int get foo {
+ return 1 + 2;
+ }
+}
+''');
+ await assertHasAssistAt(
+ 'get foo',
+ DartAssistKind.CONVERT_INTO_FINAL_FIELD,
+ '''
+class A {
+ final int foo = 1 + 2;
+}
+''');
+ }
+
+ test_convertToFinalField_OK_hasOverride() async {
+ resolveTestUnit('''
+const myAnnotation = const Object();
+class A {
+ @myAnnotation
+ int get foo => 42;
+}
+''');
+ await assertHasAssistAt(
+ 'get foo',
+ DartAssistKind.CONVERT_INTO_FINAL_FIELD,
+ '''
+const myAnnotation = const Object();
+class A {
+ @myAnnotation
+ final int foo = 42;
+}
+''');
+ }
+
+ test_convertToFinalField_OK_hasSetter_inSuper() async {
+ resolveTestUnit('''
+class A {
+ void set foo(_) {}
+}
+class B extends A {
+ int get foo => null;
+}
+''');
+ await assertHasAssistAt(
+ 'get foo',
+ DartAssistKind.CONVERT_INTO_FINAL_FIELD,
+ '''
+class A {
+ void set foo(_) {}
+}
+class B extends A {
+ final int foo;
+}
+''');
+ }
+
+ test_convertToFinalField_OK_notNull() async {
+ resolveTestUnit('''
+class A {
+ int get foo => 1 + 2;
+}
+''');
+ await assertHasAssistAt(
+ 'get foo',
+ DartAssistKind.CONVERT_INTO_FINAL_FIELD,
+ '''
+class A {
+ final int foo = 1 + 2;
+}
+''');
+ }
+
+ test_convertToFinalField_OK_null() async {
+ resolveTestUnit('''
+class A {
+ int get foo => null;
+}
+''');
+ await assertHasAssistAt(
+ 'get foo',
+ DartAssistKind.CONVERT_INTO_FINAL_FIELD,
+ '''
+class A {
+ final int foo;
+}
+''');
+ }
+
+ test_convertToFinalField_OK_onName() async {
+ resolveTestUnit('''
+class A {
+ int get foo => 42;
+}
+''');
+ await assertHasAssistAt(
+ 'foo',
+ DartAssistKind.CONVERT_INTO_FINAL_FIELD,
+ '''
+class A {
+ final int foo = 42;
+}
+''');
+ }
+
+ test_convertToFinalField_OK_onReturnType_parameterized() async {
+ resolveTestUnit('''
+class A {
+ List<int> get foo => null;
+}
+''');
+ await assertHasAssistAt(
+ 'nt> get',
+ DartAssistKind.CONVERT_INTO_FINAL_FIELD,
+ '''
+class A {
+ final List<int> foo;
+}
+''');
+ }
+
+ test_convertToFinalField_OK_onReturnType_simple() async {
+ resolveTestUnit('''
+class A {
+ int get foo => 42;
+}
+''');
+ await assertHasAssistAt(
+ 'int get',
+ DartAssistKind.CONVERT_INTO_FINAL_FIELD,
+ '''
+class A {
+ final int foo = 42;
+}
+''');
+ }
+
test_convertToForIndex_BAD_bodyNotBlock() async {
resolveTestUnit('''
main(List<String> items) {
@@ -1598,6 +1769,69 @@
''');
}
+ test_convertToGetter_BAD_noInitializer() async {
+ resolveTestUnit('''
+class A {
+ final int foo;
+}
+''');
+ await assertNoAssistAt('foo', DartAssistKind.CONVERT_INTO_GETTER);
+ }
+
+ test_convertToGetter_BAD_notFinal() async {
+ resolveTestUnit('''
+class A {
+ int foo = 1;
+}
+''');
+ await assertNoAssistAt('foo', DartAssistKind.CONVERT_INTO_GETTER);
+ }
+
+ test_convertToGetter_BAD_notSingleField() async {
+ resolveTestUnit('''
+class A {
+ final int foo = 1, bar = 2;
+}
+''');
+ await assertNoAssistAt('foo', DartAssistKind.CONVERT_INTO_GETTER);
+ }
+
+ test_convertToGetter_OK() async {
+ resolveTestUnit('''
+const myAnnotation = const Object();
+class A {
+ @myAnnotation
+ final int foo = 1 + 2;
+}
+''');
+ await assertHasAssistAt(
+ 'foo =',
+ DartAssistKind.CONVERT_INTO_GETTER,
+ '''
+const myAnnotation = const Object();
+class A {
+ @myAnnotation
+ int get foo => 1 + 2;
+}
+''');
+ }
+
+ test_convertToGetter_OK_noType() async {
+ resolveTestUnit('''
+class A {
+ final foo = 42;
+}
+''');
+ await assertHasAssistAt(
+ 'foo =',
+ DartAssistKind.CONVERT_INTO_GETTER,
+ '''
+class A {
+ get foo => 42;
+}
+''');
+ }
+
test_convertToIsNot_BAD_is_alreadyIsNot() async {
resolveTestUnit('''
main(p) {
diff --git a/pkg/analysis_server/test/services/correction/fix_test.dart b/pkg/analysis_server/test/services/correction/fix_test.dart
index 4ec437f..5244097 100644
--- a/pkg/analysis_server/test/services/correction/fix_test.dart
+++ b/pkg/analysis_server/test/services/correction/fix_test.dart
@@ -463,40 +463,42 @@
''');
List<AnalysisError> errors = context.computeErrors(testSource);
expect(errors, hasLength(2));
- String message1 = "Expected to find ';'";
- String message2 = "Undefined name 'await'";
- expect(errors.map((e) => e.message), unorderedEquals([message1, message2]));
- for (AnalysisError error in errors) {
- if (error.message == message1) {
- List<Fix> fixes = await _computeFixes(error);
- expect(fixes, isEmpty);
- }
- if (error.message == message2) {
- List<Fix> fixes = await _computeFixes(error);
- // has exactly one fix
- expect(fixes, hasLength(1));
- Fix fix = fixes[0];
- expect(fix.kind, DartFixKind.ADD_ASYNC);
- // apply to "file"
- List<SourceFileEdit> fileEdits = fix.change.edits;
- expect(fileEdits, hasLength(1));
- resultCode = SourceEdit.applySequence(testCode, fileEdits[0].edits);
- // verify
- expect(
- resultCode,
- '''
+ errors.sort((a, b) => a.message.compareTo(b.message));
+ // No fix for ";".
+ {
+ AnalysisError error = errors[0];
+ expect(error.message, "Expected to find ';'");
+ List<Fix> fixes = await _computeFixes(error);
+ expect(fixes, isEmpty);
+ }
+ // Has fix for "await".
+ {
+ AnalysisError error = errors[1];
+ expect(error.message, startsWith("Undefined name 'await';"));
+ List<Fix> fixes = await _computeFixes(error);
+ // has exactly one fix
+ expect(fixes, hasLength(1));
+ Fix fix = fixes[0];
+ expect(fix.kind, DartFixKind.ADD_ASYNC);
+ // apply to "file"
+ List<SourceFileEdit> fileEdits = fix.change.edits;
+ expect(fileEdits, hasLength(1));
+ resultCode = SourceEdit.applySequence(testCode, fileEdits[0].edits);
+ // verify
+ expect(
+ resultCode,
+ '''
foo() {}
main() async {
await foo();
}
''');
- }
}
}
test_addSync_expressionFunctionBody() async {
errorFilter = (AnalysisError error) {
- return error.errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER;
+ return error.errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER_AWAIT;
};
resolveTestUnit('''
foo() {}
@@ -512,7 +514,7 @@
test_addSync_returnFuture() async {
errorFilter = (AnalysisError error) {
- return error.errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER;
+ return error.errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER_AWAIT;
};
resolveTestUnit('''
foo() {}
@@ -536,7 +538,7 @@
test_addSync_returnFuture_alreadyFuture() async {
errorFilter = (AnalysisError error) {
- return error.errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER;
+ return error.errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER_AWAIT;
};
resolveTestUnit('''
import 'dart:async';
@@ -560,7 +562,7 @@
test_addSync_returnFuture_dynamic() async {
errorFilter = (AnalysisError error) {
- return error.errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER;
+ return error.errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER_AWAIT;
};
resolveTestUnit('''
foo() {}
@@ -582,7 +584,7 @@
test_addSync_returnFuture_noType() async {
errorFilter = (AnalysisError error) {
- return error.errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER;
+ return error.errorCode == StaticWarningCode.UNDEFINED_IDENTIFIER_AWAIT;
};
resolveTestUnit('''
foo() {}
@@ -708,8 +710,8 @@
await assertHasFix(
DartFixKind.CHANGE_TO_STATIC_ACCESS,
'''
-import 'libB.dart';
import 'libA.dart';
+import 'libB.dart';
main(B b) {
A.foo();
}
@@ -779,8 +781,8 @@
await assertHasFix(
DartFixKind.CHANGE_TO_STATIC_ACCESS,
'''
-import 'libB.dart';
import 'libA.dart';
+import 'libB.dart';
main(B b) {
A.foo;
}
@@ -1239,8 +1241,8 @@
await assertHasFix(
DartFixKind.CREATE_CONSTRUCTOR_SUPER,
'''
-import 'libB.dart';
import 'libA.dart';
+import 'libB.dart';
class C extends B {
C(A a) : super(a);
}
@@ -1563,8 +1565,8 @@
await assertHasFix(
DartFixKind.CREATE_FIELD,
'''
-import 'libB.dart';
import 'libA.dart';
+import 'libB.dart';
class C {
A test;
}
@@ -2631,7 +2633,7 @@
}
@override
- void set s3(String x) {
+ set s3(String x) {
// TODO: implement s3
}
}
@@ -2802,8 +2804,8 @@
await assertHasFix(
DartFixKind.CREATE_FUNCTION,
'''
-import 'libB.dart';
import 'libA.dart';
+import 'libB.dart';
main() {
useFunction(test);
}
@@ -2976,6 +2978,7 @@
DartFixKind.REPLACE_RETURN_TYPE_FUTURE,
'''
library main;
+
import 'dart:async';
Future<int> main() async {
}
@@ -3111,8 +3114,8 @@
await assertHasFix(
DartFixKind.IMPORT_LIBRARY_PROJECT,
'''
-import 'b.dart' show Two;
import 'a.dart';
+import 'b.dart' show Two;
main () {
new Two();
new One();
@@ -4131,8 +4134,8 @@
await assertHasFix(
DartFixKind.CREATE_FUNCTION,
'''
-import 'lib.dart';
import 'dart:async';
+import 'lib.dart';
main() {
test(getFuture());
}
diff --git a/pkg/analysis_server/test/services/correction/test_all.dart b/pkg/analysis_server/test/services/correction/test_all.dart
index d1a6bb5..f00f310 100644
--- a/pkg/analysis_server/test/services/correction/test_all.dart
+++ b/pkg/analysis_server/test/services/correction/test_all.dart
@@ -17,6 +17,7 @@
import 'source_range_test.dart' as source_range_test;
import 'status_test.dart' as status_test;
import 'strings_test.dart' as strings_test;
+import 'util_test.dart' as util_test;
/// Utility for manually running all tests.
main() {
@@ -32,5 +33,6 @@
source_range_test.main();
status_test.main();
strings_test.main();
+ util_test.main();
});
}
diff --git a/pkg/analysis_server/test/services/correction/util_test.dart b/pkg/analysis_server/test/services/correction/util_test.dart
new file mode 100644
index 0000000..a435b1c
--- /dev/null
+++ b/pkg/analysis_server/test/services/correction/util_test.dart
@@ -0,0 +1,293 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library test.services.correction.util;
+
+import 'package:analysis_server/plugin/protocol/protocol.dart';
+import 'package:analysis_server/src/services/correction/strings.dart';
+import 'package:analysis_server/src/services/correction/util.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/generated/source.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+import 'package:unittest/unittest.dart';
+
+import '../../abstract_single_unit.dart';
+import '../../utils.dart';
+
+main() {
+ initializeTestEnvironment();
+ defineReflectiveTests(UtilTest);
+}
+
+@reflectiveTest
+class UtilTest extends AbstractSingleUnitTest {
+ test_addLibraryImports_dart_hasImports_between() {
+ resolveTestUnit('''
+import 'dart:async';
+import 'dart:math';
+''');
+ LibraryElement newLibrary = _getDartLibrary('dart:collection');
+ _assertAddLibraryImport(
+ <LibraryElement>[newLibrary],
+ '''
+import 'dart:async';
+import 'dart:collection';
+import 'dart:math';
+''');
+ }
+
+ test_addLibraryImports_dart_hasImports_first() {
+ resolveTestUnit('''
+import 'dart:collection';
+import 'dart:math';
+''');
+ LibraryElement newLibrary = _getDartLibrary('dart:async');
+ _assertAddLibraryImport(
+ <LibraryElement>[newLibrary],
+ '''
+import 'dart:async';
+import 'dart:collection';
+import 'dart:math';
+''');
+ }
+
+ test_addLibraryImports_dart_hasImports_last() {
+ resolveTestUnit('''
+import 'dart:async';
+import 'dart:collection';
+''');
+ LibraryElement newLibrary = _getDartLibrary('dart:math');
+ _assertAddLibraryImport(
+ <LibraryElement>[newLibrary],
+ '''
+import 'dart:async';
+import 'dart:collection';
+import 'dart:math';
+''');
+ }
+
+ test_addLibraryImports_dart_hasImports_multiple() {
+ resolveTestUnit('''
+import 'dart:collection';
+import 'dart:math';
+''');
+ LibraryElement newLibrary1 = _getDartLibrary('dart:async');
+ LibraryElement newLibrary2 = _getDartLibrary('dart:html');
+ _assertAddLibraryImport(
+ <LibraryElement>[newLibrary1, newLibrary2],
+ '''
+import 'dart:async';
+import 'dart:collection';
+import 'dart:html';
+import 'dart:math';
+''');
+ }
+
+ test_addLibraryImports_dart_hasImports_multiple_first() {
+ resolveTestUnit('''
+import 'dart:html';
+import 'dart:math';
+''');
+ LibraryElement newLibrary1 = _getDartLibrary('dart:async');
+ LibraryElement newLibrary2 = _getDartLibrary('dart:collection');
+ _assertAddLibraryImport(
+ <LibraryElement>[newLibrary1, newLibrary2],
+ '''
+import 'dart:async';
+import 'dart:collection';
+import 'dart:html';
+import 'dart:math';
+''');
+ }
+
+ test_addLibraryImports_dart_hasImports_multiple_last() {
+ resolveTestUnit('''
+import 'dart:async';
+import 'dart:collection';
+''');
+ LibraryElement newLibrary1 = _getDartLibrary('dart:html');
+ LibraryElement newLibrary2 = _getDartLibrary('dart:math');
+ _assertAddLibraryImport(
+ <LibraryElement>[newLibrary1, newLibrary2],
+ '''
+import 'dart:async';
+import 'dart:collection';
+import 'dart:html';
+import 'dart:math';
+''');
+ }
+
+ test_addLibraryImports_dart_hasLibraryDirective() {
+ resolveTestUnit('''
+library test;
+
+class A {}
+''');
+ LibraryElement newLibrary1 = _getDartLibrary('dart:math');
+ LibraryElement newLibrary2 = _getDartLibrary('dart:async');
+ _assertAddLibraryImport(
+ <LibraryElement>[newLibrary1, newLibrary2],
+ '''
+library test;
+
+import 'dart:async';
+import 'dart:math';
+
+class A {}
+''');
+ }
+
+ test_addLibraryImports_dart_noDirectives_hasComment() {
+ resolveTestUnit('''
+/// Comment.
+
+class A {}
+''');
+ LibraryElement newLibrary1 = _getDartLibrary('dart:math');
+ LibraryElement newLibrary2 = _getDartLibrary('dart:async');
+ _assertAddLibraryImport(
+ <LibraryElement>[newLibrary1, newLibrary2],
+ '''
+/// Comment.
+
+import 'dart:async';
+import 'dart:math';
+
+class A {}
+''');
+ }
+
+ test_addLibraryImports_dart_noDirectives_hasShebang() {
+ resolveTestUnit('''
+#!/bin/dart
+
+class A {}
+''');
+ LibraryElement newLibrary1 = _getDartLibrary('dart:math');
+ LibraryElement newLibrary2 = _getDartLibrary('dart:async');
+ _assertAddLibraryImport(
+ <LibraryElement>[newLibrary1, newLibrary2],
+ '''
+#!/bin/dart
+
+import 'dart:async';
+import 'dart:math';
+
+class A {}
+''');
+ }
+
+ test_addLibraryImports_dart_noDirectives_noShebang() {
+ resolveTestUnit('''
+class A {}
+''');
+ LibraryElement newLibrary1 = _getDartLibrary('dart:math');
+ LibraryElement newLibrary2 = _getDartLibrary('dart:async');
+ _assertAddLibraryImport(
+ <LibraryElement>[newLibrary1, newLibrary2],
+ '''
+import 'dart:async';
+import 'dart:math';
+
+class A {}
+''');
+ }
+
+ test_addLibraryImports_package_hasDart_hasPackages_insertAfter() {
+ resolveTestUnit('''
+import 'dart:async';
+
+import 'package:aaa/aaa.dart';
+''');
+ LibraryElement newLibrary =
+ _mockLibraryElement('/lib/bbb.dart', 'package:bbb/bbb.dart');
+ _assertAddLibraryImport(
+ <LibraryElement>[newLibrary],
+ '''
+import 'dart:async';
+
+import 'package:aaa/aaa.dart';
+import 'package:bbb/bbb.dart';
+''');
+ }
+
+ test_addLibraryImports_package_hasDart_hasPackages_insertBefore() {
+ resolveTestUnit('''
+import 'dart:async';
+
+import 'package:bbb/bbb.dart';
+''');
+ LibraryElement newLibrary =
+ _mockLibraryElement('/lib/aaa.dart', 'package:aaa/aaa.dart');
+ _assertAddLibraryImport(
+ <LibraryElement>[newLibrary],
+ '''
+import 'dart:async';
+
+import 'package:aaa/aaa.dart';
+import 'package:bbb/bbb.dart';
+''');
+ }
+
+ test_addLibraryImports_package_hasImports_between() {
+ resolveTestUnit('''
+import 'package:aaa/aaa.dart';
+import 'package:ddd/ddd.dart';
+''');
+ LibraryElement newLibrary1 =
+ _mockLibraryElement('/lib/bbb.dart', 'package:bbb/bbb.dart');
+ LibraryElement newLibrary2 =
+ _mockLibraryElement('/lib/ccc.dart', 'package:ccc/ccc.dart');
+ _assertAddLibraryImport(
+ <LibraryElement>[newLibrary1, newLibrary2],
+ '''
+import 'package:aaa/aaa.dart';
+import 'package:bbb/bbb.dart';
+import 'package:ccc/ccc.dart';
+import 'package:ddd/ddd.dart';
+''');
+ }
+
+ void _assertAddLibraryImport(
+ List<LibraryElement> newLibraries, String expectedCode) {
+ SourceChange change = new SourceChange('');
+ addLibraryImports(change, testLibraryElement, newLibraries.toSet());
+ SourceFileEdit testEdit = change.getFileEdit(testFile);
+ expect(testEdit, isNotNull);
+ String resultCode = SourceEdit.applySequence(testCode, testEdit.edits);
+ expect(resultCode, expectedCode);
+ }
+
+ LibraryElement _getDartLibrary(String uri) {
+ String path = removeStart(uri, 'dart:');
+ Source newSource = new _SourceMock('/sdk/lib/$path.dart', Uri.parse(uri));
+ return new _LibraryElementMock(newSource);
+ }
+
+ LibraryElement _mockLibraryElement(String path, String uri) {
+ Source newSource = new _SourceMock(path, Uri.parse(uri));
+ return new _LibraryElementMock(newSource);
+ }
+}
+
+class _LibraryElementMock implements LibraryElement {
+ @override
+ final Source source;
+
+ _LibraryElementMock(this.source);
+
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
+
+class _SourceMock implements Source {
+ @override
+ final String fullName;
+
+ @override
+ final Uri uri;
+
+ _SourceMock(this.fullName, this.uri);
+
+ noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
+}
diff --git a/pkg/analysis_server/test/services/refactoring/rename_class_member_test.dart b/pkg/analysis_server/test/services/refactoring/rename_class_member_test.dart
index 46ed173..cc09692 100644
--- a/pkg/analysis_server/test/services/refactoring/rename_class_member_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/rename_class_member_test.dart
@@ -90,6 +90,22 @@
expectedContextSearch: 'newName() {} // existing');
}
+ test_checkFinalConditions_OK_dropSuffix() async {
+ indexTestUnit(r'''
+abstract class A {
+ void testOld();
+}
+class B implements A {
+ void testOld() {}
+}
+''');
+ createRenameRefactoringAtString('testOld() {}');
+ // check status
+ refactoring.newName = 'test';
+ RefactoringStatus status = await refactoring.checkFinalConditions();
+ assertRefactoringStatusOK(status);
+ }
+
test_checkFinalConditions_OK_noShadow() async {
indexTestUnit('''
class A {
diff --git a/pkg/analysis_server/test/services/search/hierarchy_test.dart b/pkg/analysis_server/test/services/search/hierarchy_test.dart
index 027c237..802f351 100644
--- a/pkg/analysis_server/test/services/search/hierarchy_test.dart
+++ b/pkg/analysis_server/test/services/search/hierarchy_test.dart
@@ -118,6 +118,41 @@
return Future.wait([futureA, futureB, futureC, futureD]);
}
+ Future test_getHierarchyMembers_fields_static() async {
+ _indexTestUnit('''
+class A {
+ static int foo;
+}
+class B extends A {
+ static get foo => null;
+}
+class C extends B {
+ static set foo(x) {}
+}
+''');
+ ClassElement classA = findElement('A');
+ ClassElement classB = findElement('B');
+ ClassElement classC = findElement('C');
+ ClassMemberElement memberA = classA.fields[0];
+ ClassMemberElement memberB = classB.fields[0];
+ ClassMemberElement memberC = classC.fields[0];
+ {
+ Set<ClassMemberElement> members =
+ await getHierarchyMembers(searchEngine, memberA);
+ expect(members, unorderedEquals([memberA]));
+ }
+ {
+ Set<ClassMemberElement> members =
+ await getHierarchyMembers(searchEngine, memberB);
+ expect(members, unorderedEquals([memberB]));
+ }
+ {
+ Set<ClassMemberElement> members =
+ await getHierarchyMembers(searchEngine, memberC);
+ expect(members, unorderedEquals([memberC]));
+ }
+ }
+
Future test_getHierarchyMembers_methods() {
_indexTestUnit('''
class A {
@@ -164,6 +199,31 @@
return Future.wait([futureA, futureB, futureC, futureD, futureE]);
}
+ Future test_getHierarchyMembers_methods_static() async {
+ _indexTestUnit('''
+class A {
+ static foo() {}
+}
+class B extends A {
+ static foo() {}
+}
+''');
+ ClassElement classA = findElement('A');
+ ClassElement classB = findElement('B');
+ ClassMemberElement memberA = classA.methods[0];
+ ClassMemberElement memberB = classB.methods[0];
+ {
+ Set<ClassMemberElement> members =
+ await getHierarchyMembers(searchEngine, memberA);
+ expect(members, unorderedEquals([memberA]));
+ }
+ {
+ Set<ClassMemberElement> members =
+ await getHierarchyMembers(searchEngine, memberB);
+ expect(members, unorderedEquals([memberB]));
+ }
+ }
+
Future test_getHierarchyMembers_withInterfaces() {
_indexTestUnit('''
class A {
diff --git a/pkg/analysis_server/test/services/search/search_engine_test.dart b/pkg/analysis_server/test/services/search/search_engine_test.dart
index 4bf728d..cea1817 100644
--- a/pkg/analysis_server/test/services/search/search_engine_test.dart
+++ b/pkg/analysis_server/test/services/search/search_engine_test.dart
@@ -101,8 +101,9 @@
}
class B {
int test = 1;
+ int testTwo = 2;
main() {
- int test = 2;
+ int test = 3;
}
}
''');
diff --git a/pkg/analysis_server/test/stress/replay/replay.dart b/pkg/analysis_server/test/stress/replay/replay.dart
index 6c56047..dd9016d 100644
--- a/pkg/analysis_server/test/stress/replay/replay.dart
+++ b/pkg/analysis_server/test/stress/replay/replay.dart
@@ -9,6 +9,7 @@
import 'dart:async';
import 'dart:io';
+import 'dart:math' as math;
import 'package:analysis_server/plugin/protocol/protocol.dart';
import 'package:analyzer/dart/ast/token.dart';
@@ -168,7 +169,8 @@
LineInfo info = fileEdit.lineInfo;
for (DiffHunk hunk in blobDiff.hunks) {
int srcStart = info.getOffsetOfLine(hunk.srcLine);
- int srcEnd = info.getOffsetOfLine(hunk.srcLine + hunk.removeLines.length);
+ int srcEnd = info.getOffsetOfLine(
+ math.min(hunk.srcLine + hunk.removeLines.length, info.lineCount - 1));
String addedText = _join(hunk.addLines);
//
// Create the source edits.
@@ -320,6 +322,7 @@
//
// Iterate over the history, applying changes.
//
+ int dotCount = 0;
bool firstCheckout = true;
ErrorMap expectedErrors = null;
Iterable<String> changedPubspecs;
@@ -363,6 +366,10 @@
}
changedPubspecs = commitDelta.filesMatching(PUBSPEC_FILE_NAME);
stdout.write('.');
+ if (dotCount++ > 100) {
+ stdout.writeln();
+ dotCount = 0;
+ }
}
server.removeAllOverlays();
stdout.writeln();
@@ -632,10 +639,8 @@
if (hours > 0) {
return '$hours:$minutes:$seconds.$milliseconds';
} else if (minutes > 0) {
- return '$minutes:$seconds.$milliseconds m';
- } else if (seconds > 0) {
- return '$seconds.$milliseconds s';
+ return '$minutes:$seconds.$milliseconds';
}
- return '$milliseconds ms';
+ return '$seconds.$milliseconds';
}
}
diff --git a/pkg/analyzer/CHANGELOG.md b/pkg/analyzer/CHANGELOG.md
index 07f8a30..4be083e 100644
--- a/pkg/analyzer/CHANGELOG.md
+++ b/pkg/analyzer/CHANGELOG.md
@@ -1,3 +1,16 @@
+## 0.27.4-alpha.19
+* Added support for running the dev compiler in the browser.
+
+## 0.27.4-alpha.18
+* Support for references to operators in doc comments (#26929).
+
+## 0.27.4-alpha.17
+* Support for trailing commas in parameter and argument lists (#26647).
+* Strong mode breaking change: can now infer generic type arguments from the constructor invocation arguments (#25220).
+
+## 0.27.4-alpha.16
+* (Internal) Corresponds with the analyzer/server in the `1.18.0-dev.4.0` SDK.
+
## 0.27.4-alpha.9
* Restore EmbedderUriResolver API.
diff --git a/pkg/analyzer/doc/tasks.html b/pkg/analyzer/doc/tasks.html
index eb19b8b..b5a88d0 100644
--- a/pkg/analyzer/doc/tasks.html
+++ b/pkg/analyzer/doc/tasks.html
@@ -30,7 +30,6 @@
BuildLibraryElementTask -> BUILD_LIBRARY_ERRORS
BuildLibraryElementTask -> IS_LAUNCHABLE
BuildLibraryElementTask -> LIBRARY_ELEMENT1
- BuildLibraryElementTask -> REFERENCED_NAMES
BuildPublicNamespaceTask -> LIBRARY_ELEMENT3
BuildSourceExportClosureTask -> EXPORT_SOURCE_CLOSURE
BuildTypeProviderTask -> TYPE_PROVIDER
@@ -96,6 +95,7 @@
EXPORTED_LIBRARIES -> ResolveTopLevelLibraryTypeBoundsTask
EXPORTED_LIBRARIES [shape=box]
EXPORT_SOURCE_CLOSURE -> BuildExportNamespaceTask
+ EXPORT_SOURCE_CLOSURE -> ResolveTopLevelUnitTypeBoundsTask
EXPORT_SOURCE_CLOSURE [shape=box]
EvaluateUnitConstantsTask -> CREATED_RESOLVED_UNIT13
EvaluateUnitConstantsTask -> RESOLVED_UNIT13
@@ -216,6 +216,7 @@
ParseDartTask -> LIBRARY_SPECIFIC_UNITS
ParseDartTask -> PARSED_UNIT
ParseDartTask -> PARSE_ERRORS
+ ParseDartTask -> REFERENCED_NAMES
ParseDartTask -> REFERENCED_SOURCES
ParseDartTask -> SOURCE_KIND
ParseDartTask -> UNITS
diff --git a/pkg/analyzer/lib/context/declared_variables.dart b/pkg/analyzer/lib/context/declared_variables.dart
index 9a0322c..86d6234 100644
--- a/pkg/analyzer/lib/context/declared_variables.dart
+++ b/pkg/analyzer/lib/context/declared_variables.dart
@@ -23,6 +23,11 @@
HashMap<String, String> _declaredVariables = new HashMap<String, String>();
/**
+ * Return the names of the variables for which a value has been defined.
+ */
+ Iterable<String> get variableNames => _declaredVariables.keys;
+
+ /**
* Define a variable with the given [name] to have the given [value].
*/
void define(String name, String value) {
diff --git a/pkg/analyzer/lib/file_system/file_system.dart b/pkg/analyzer/lib/file_system/file_system.dart
index 7a12c6f1c..41d6f84 100644
--- a/pkg/analyzer/lib/file_system/file_system.dart
+++ b/pkg/analyzer/lib/file_system/file_system.dart
@@ -166,6 +166,11 @@
* this folder.
*/
bool isOrContains(String path);
+
+ /**
+ * Return a Uri representing this resource.
+ */
+ Uri toUri();
}
/**
@@ -198,6 +203,14 @@
Folder getFolder(String path);
/**
+ * Complete with a list of modification times for the given [sources].
+ *
+ * If the file of a source is not managed by this provider, return `null`.
+ * If the file a source does not exist, return `-1`.
+ */
+ Future<List<int>> getModificationTimes(List<Source> sources);
+
+ /**
* Return the [Resource] that corresponds to the given [path].
*/
Resource getResource(String path);
@@ -225,6 +238,8 @@
ResourceUriResolver(this._provider);
+ ResourceProvider get provider => _provider;
+
@override
Source resolveAbsolute(Uri uri, [Uri actualUri]) {
if (!isFileUri(uri)) {
@@ -242,8 +257,6 @@
Uri restoreAbsolute(Source source) =>
_provider.pathContext.toUri(source.fullName);
- ResourceProvider get provider => _provider;
-
/**
* Return `true` if the given [uri] is a `file` URI.
*/
diff --git a/pkg/analyzer/lib/file_system/memory_file_system.dart b/pkg/analyzer/lib/file_system/memory_file_system.dart
index 3391433..cd8e149 100644
--- a/pkg/analyzer/lib/file_system/memory_file_system.dart
+++ b/pkg/analyzer/lib/file_system/memory_file_system.dart
@@ -80,6 +80,14 @@
Folder getFolder(String path) => newFolder(path);
@override
+ Future<List<int>> getModificationTimes(List<Source> sources) async {
+ return sources.map((source) {
+ String path = source.fullName;
+ return _pathToTimestamp[path] ?? -1;
+ }).toList();
+ }
+
+ @override
Resource getResource(String path) {
path = pathContext.normalize(path);
Resource resource = _pathToResource[path];
@@ -306,6 +314,9 @@
}
@override
+ Uri toUri() => new Uri.file(path, windows: _provider.pathContext == windows);
+
+ @override
void writeAsBytesSync(List<int> bytes) {
throw new FileSystemException(path, 'File could not be written');
}
@@ -380,6 +391,9 @@
}
@override
+ Uri toUri() => new Uri.file(path, windows: _provider.pathContext == windows);
+
+ @override
void writeAsBytesSync(List<int> bytes) {
_provider._setFileBytes(this, bytes);
}
@@ -553,6 +567,10 @@
}
return contains(path);
}
+
+ @override
+ Uri toUri() =>
+ new Uri.directory(path, windows: _provider.pathContext == windows);
}
/**
diff --git a/pkg/analyzer/lib/file_system/physical_file_system.dart b/pkg/analyzer/lib/file_system/physical_file_system.dart
index 9cd62b6..8b8618e 100644
--- a/pkg/analyzer/lib/file_system/physical_file_system.dart
+++ b/pkg/analyzer/lib/file_system/physical_file_system.dart
@@ -12,10 +12,34 @@
import 'package:analyzer/src/generated/java_io.dart';
import 'package:analyzer/src/generated/source_io.dart';
import 'package:analyzer/src/util/absolute_path.dart';
+import 'package:isolate/isolate_runner.dart';
import 'package:path/path.dart';
import 'package:watcher/watcher.dart';
/**
+ * Return modification times for every file path in [paths].
+ *
+ * If a path is `null`, the modification time is also `null`.
+ *
+ * If any exception happens, the file is considered as a not existing and
+ * `-1` is its modification time.
+ */
+List<int> _pathsToTimes(List<String> paths) {
+ return paths.map((path) {
+ if (path != null) {
+ try {
+ io.File file = new io.File(path);
+ return file.lastModifiedSync().millisecondsSinceEpoch;
+ } catch (_) {
+ return -1;
+ }
+ } else {
+ return null;
+ }
+ }).toList();
+}
+
+/**
* A `dart:io` based implementation of [ResourceProvider].
*/
class PhysicalResourceProvider implements ResourceProvider {
@@ -31,6 +55,9 @@
*/
static final String SERVER_DIR = ".dartServer";
+ static _SingleIsolateRunnerProvider pathsToTimesIsolateProvider =
+ new _SingleIsolateRunnerProvider();
+
@override
final AbsolutePathContext absolutePathContext =
new AbsolutePathContext(io.Platform.isWindows);
@@ -51,6 +78,15 @@
Folder getFolder(String path) => new _PhysicalFolder(new io.Directory(path));
@override
+ Future<List<int>> getModificationTimes(List<Source> sources) async {
+ List<String> paths = sources
+ .map((source) => source is FileBasedSource ? source.fullName : null)
+ .toList();
+ IsolateRunner runner = await pathsToTimesIsolateProvider.get();
+ return runner.run(_pathsToTimes, paths);
+ }
+
+ @override
Resource getResource(String path) {
if (io.FileSystemEntity.isDirectorySync(path)) {
return getFolder(path);
@@ -143,6 +179,9 @@
}
@override
+ Uri toUri() => new Uri.file(path);
+
+ @override
void writeAsBytesSync(List<int> bytes) {
try {
io.File file = _entry as io.File;
@@ -220,6 +259,9 @@
}
return contains(path);
}
+
+ @override
+ Uri toUri() => new Uri.directory(path);
}
/**
@@ -274,3 +316,33 @@
@override
String toString() => path;
}
+
+/**
+ * This class encapsulates logic for creating a single [IsolateRunner].
+ */
+class _SingleIsolateRunnerProvider {
+ bool _isSpawning = false;
+ IsolateRunner _runner;
+
+ /**
+ * Complete with the only [IsolateRunner] instance.
+ */
+ Future<IsolateRunner> get() async {
+ if (_runner != null) {
+ return _runner;
+ }
+ if (_isSpawning) {
+ Completer<IsolateRunner> completer = new Completer<IsolateRunner>();
+ new Timer.periodic(new Duration(milliseconds: 10), (Timer timer) {
+ if (_runner != null) {
+ completer.complete(_runner);
+ timer.cancel();
+ }
+ });
+ return completer.future;
+ }
+ _isSpawning = true;
+ _runner = await IsolateRunner.spawn();
+ return _runner;
+ }
+}
diff --git a/pkg/analyzer/lib/source/config.dart b/pkg/analyzer/lib/source/config.dart
index 0ca954a..db44b4e 100644
--- a/pkg/analyzer/lib/source/config.dart
+++ b/pkg/analyzer/lib/source/config.dart
@@ -91,7 +91,8 @@
Uri pragma = new Uri.file('config/${descriptor.pragma}.yaml',
windows: false);
Uri optionsUri = uri.resolveUri(pragma);
- File file = resourceProvider.getFile(optionsUri.toFilePath());
+ String path = resourceProvider.pathContext.fromUri(optionsUri);
+ File file = resourceProvider.getFile(path);
if (file.exists) {
return optionsProvider.getOptionsFromFile(file);
}
diff --git a/pkg/analyzer/lib/source/sdk_ext.dart b/pkg/analyzer/lib/source/sdk_ext.dart
index 3e833df..f25d65e 100644
--- a/pkg/analyzer/lib/source/sdk_ext.dart
+++ b/pkg/analyzer/lib/source/sdk_ext.dart
@@ -31,6 +31,12 @@
final Map<String, String> _urlMappings = <String, String>{};
+ /**
+ * The absolute paths of the extension files that contributed to the
+ * [_urlMappings].
+ */
+ final List<String> extensionFilePaths = <String>[];
+
/// Construct a [SdkExtUriResolver] from a package map
/// (see [PackageMapProvider]).
SdkExtUriResolver(Map<String, List<Folder>> packageMap) {
@@ -147,18 +153,27 @@
if ((sdkExt == null) || (sdkExt is! Map)) {
return;
}
- sdkExt.forEach((k, v) => _processSdkExtension(k, v, libDir));
+ bool contributed = false;
+ sdkExt.forEach((k, v) {
+ if (_processSdkExtension(k, v, libDir)) {
+ contributed = true;
+ }
+ });
+ if (contributed) {
+ extensionFilePaths.add(libDir.getChild(SDK_EXT_NAME).path);
+ }
}
/// Install the mapping from [name] to [libDir]/[file].
- void _processSdkExtension(String name, String file, Folder libDir) {
+ bool _processSdkExtension(String name, String file, Folder libDir) {
if (!name.startsWith(DART_COLON_PREFIX)) {
// SDK extensions must begin with 'dart:'.
- return;
+ return false;
}
var key = name;
var value = libDir.canonicalizePath(file);
_urlMappings[key] = value;
+ return true;
}
/// Read the contents of [libDir]/[SDK_EXT_NAME] as a string.
diff --git a/pkg/analyzer/lib/src/context/builder.dart b/pkg/analyzer/lib/src/context/builder.dart
index 6abd7bd..3755353 100644
--- a/pkg/analyzer/lib/src/context/builder.dart
+++ b/pkg/analyzer/lib/src/context/builder.dart
@@ -8,6 +8,7 @@
import 'dart:core' hide Resource;
import 'dart:io' as io;
+import 'package:analyzer/context/declared_variables.dart';
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/plugin/resolver_provider.dart';
import 'package:analyzer/source/analysis_options_provider.dart';
@@ -25,7 +26,6 @@
import 'package:package_config/packages.dart';
import 'package:package_config/packages_file.dart';
import 'package:package_config/src/packages_impl.dart';
-import 'package:path/path.dart' as path;
import 'package:yaml/yaml.dart';
/**
@@ -75,48 +75,83 @@
ResolverProvider packageResolverProvider;
/**
+ * The resolver provider used to create a file: URI resolver, or `null` if
+ * the normal file URI resolver is to be used.
+ */
+ ResolverProvider fileResolverProvider;
+
+ /**
* The file path of the .packages file that should be used in place of any
- * file found using the normal (Package Specification DEP) lookup mechanism.
+ * file found using the normal (Package Specification DEP) lookup mechanism,
+ * or `null` if the normal lookup mechanism should be used.
*/
String defaultPackageFilePath;
/**
* The file path of the packages directory that should be used in place of any
- * file found using the normal (Package Specification DEP) lookup mechanism.
+ * file found using the normal (Package Specification DEP) lookup mechanism,
+ * or `null` if the normal lookup mechanism should be used.
*/
String defaultPackagesDirectoryPath;
/**
* The file path of the analysis options file that should be used in place of
- * any file in the root directory.
+ * any file in the root directory or a parent of the root directory, or `null`
+ * if the normal lookup mechanism should be used.
*/
String defaultAnalysisOptionsFilePath;
/**
* The default analysis options that should be used unless some or all of them
- * are overridden in the analysis options file.
+ * are overridden in the analysis options file, or `null` if the default
+ * defaults should be used.
*/
AnalysisOptions defaultOptions;
/**
+ * A table mapping variable names to values for the declared variables, or
+ * `null` if no additional variables should be declared.
+ */
+ Map<String, String> declaredVariables;
+
+ /**
* Initialize a newly created builder to be ready to build a context rooted in
* the directory with the given [rootDirectoryPath].
*/
ContextBuilder(this.resourceProvider, this.sdkManager, this.contentCache);
- AnalysisContext buildContext(String rootDirectoryPath) {
+ /**
+ * Return an analysis context that is configured correctly to analyze code in
+ * the directory with the given [path].
+ *
+ * *Note:* This method is not yet fully implemented and should not be used.
+ */
+ AnalysisContext buildContext(String path) {
// TODO(brianwilkerson) Split getAnalysisOptions so we can capture the
// option map and use it to run the options processors.
- AnalysisOptions options = getAnalysisOptions(rootDirectoryPath);
+ AnalysisOptions options = getAnalysisOptions(path);
InternalAnalysisContext context =
AnalysisEngine.instance.createAnalysisContext();
context.contentCache = contentCache;
- context.sourceFactory = createSourceFactory(rootDirectoryPath, options);
+ context.sourceFactory = createSourceFactory(path, options);
context.analysisOptions = options;
//_processAnalysisOptions(context, optionMap);
+ declareVariables(context);
return context;
}
+ Map<String, List<Folder>> convertPackagesToMap(Packages packages) {
+ if (packages == null || packages == Packages.noPackages) {
+ return null;
+ }
+ Map<String, List<Folder>> folderMap = new HashMap<String, List<Folder>>();
+ packages.asMap().forEach((String packagePath, Uri uri) {
+ String path = resourceProvider.pathContext.fromUri(uri);
+ folderMap[packagePath] = [resourceProvider.getFolder(path)];
+ });
+ return folderMap;
+ }
+
// void _processAnalysisOptions(
// AnalysisContext context, Map<String, YamlNode> optionMap) {
// List<OptionsProcessor> optionsProcessors =
@@ -140,15 +175,14 @@
// }
// }
- Map<String, List<Folder>> convertPackagesToMap(Packages packages) {
- if (packages == null || packages == Packages.noPackages) {
- return null;
+ /**
+ * Return an analysis options object containing the default option values.
+ */
+ AnalysisOptions createDefaultOptions() {
+ if (defaultOptions == null) {
+ return new AnalysisOptionsImpl();
}
- Map<String, List<Folder>> folderMap = new HashMap<String, List<Folder>>();
- packages.asMap().forEach((String packagePath, Uri uri) {
- folderMap[packagePath] = [resourceProvider.getFolder(path.fromUri(uri))];
- });
- return folderMap;
+ return new AnalysisOptionsImpl.from(defaultOptions);
}
Packages createPackageMap(String rootDirectoryPath) {
@@ -169,17 +203,23 @@
SourceFactory createSourceFactory(
String rootDirectoryPath, AnalysisOptions options) {
+ Folder _folder = null;
+ Folder folder() {
+ return _folder ??= resourceProvider.getResource('.');
+ }
+ UriResolver fileResolver = fileResolverProvider == null
+ ? new ResourceUriResolver(resourceProvider)
+ : fileResolverProvider(folder());
if (packageResolverProvider != null) {
- Folder folder = resourceProvider.getResource('.');
- UriResolver resolver = packageResolverProvider(folder);
- if (resolver != null) {
+ UriResolver packageResolver = packageResolverProvider(folder());
+ if (packageResolver != null) {
// TODO(brianwilkerson) This doesn't support either embedder files or
// sdk extensions because we don't have a way to get the package map
// from the resolver.
List<UriResolver> resolvers = <UriResolver>[
new DartUriResolver(findSdk(null, options)),
- resolver,
- new ResourceUriResolver(resourceProvider)
+ packageResolver,
+ fileResolver
];
return new SourceFactory(resolvers);
}
@@ -189,36 +229,79 @@
List<UriResolver> resolvers = <UriResolver>[];
resolvers.add(new DartUriResolver(findSdk(packageMap, options)));
if (packageMap != null) {
- resolvers.add(new SdkExtUriResolver(packageMap));
resolvers.add(new PackageMapUriResolver(resourceProvider, packageMap));
}
- resolvers.add(new ResourceUriResolver(resourceProvider));
+ resolvers.add(fileResolver);
return new SourceFactory(resolvers);
}
/**
- * Use the given [packageMap] and [options] to locate the SDK.
+ * Add any [declaredVariables] to the list of declared variables used by the
+ * given [context].
+ */
+ void declareVariables(InternalAnalysisContext context) {
+ if (declaredVariables != null && declaredVariables.isNotEmpty) {
+ DeclaredVariables contextVariables = context.declaredVariables;
+ declaredVariables.forEach((String variableName, String value) {
+ contextVariables.define(variableName, value);
+ });
+ }
+ }
+
+ /**
+ * Return the SDK that should be used to analyze code. Use the given
+ * [packageMap] and [options] to locate the SDK.
*/
DartSdk findSdk(
Map<String, List<Folder>> packageMap, AnalysisOptions options) {
if (packageMap != null) {
+ // TODO(brianwilkerson) Fix it so that we don't have to create a resolver
+ // to figure out what the extensions are.
+ SdkExtUriResolver extResolver = new SdkExtUriResolver(packageMap);
+ List<String> extFilePaths = extResolver.extensionFilePaths;
EmbedderYamlLocator locator = new EmbedderYamlLocator(packageMap);
Map<Folder, YamlMap> embedderYamls = locator.embedderYamls;
EmbedderSdk embedderSdk = new EmbedderSdk(embedderYamls);
if (embedderSdk.sdkLibraries.length > 0) {
+ //
+ // There is an embedder file that defines the content of the SDK and
+ // there might be an extension file that extends it.
+ //
List<String> paths = <String>[];
for (Folder folder in embedderYamls.keys) {
paths.add(folder
.getChildAssumingFile(EmbedderYamlLocator.EMBEDDER_FILE_NAME)
.path);
}
+ paths.addAll(extFilePaths);
SdkDescription description = new SdkDescription(paths, options);
DartSdk dartSdk = sdkManager.getSdk(description, () {
+ if (extFilePaths.isNotEmpty) {
+ embedderSdk.addExtensions(extResolver.urlMappings);
+ }
embedderSdk.analysisOptions = options;
embedderSdk.useSummary = sdkManager.canUseSummaries;
return embedderSdk;
});
return dartSdk;
+ } else if (extFilePaths != null) {
+ //
+ // We have an extension file, but no embedder file.
+ //
+ String sdkPath = sdkManager.defaultSdkDirectory;
+ List<String> paths = <String>[sdkPath];
+ paths.addAll(extFilePaths);
+ SdkDescription description = new SdkDescription(paths, options);
+ return sdkManager.getSdk(description, () {
+ DirectoryBasedDartSdk sdk =
+ new DirectoryBasedDartSdk(new JavaFile(sdkPath));
+ if (extFilePaths.isNotEmpty) {
+ embedderSdk.addExtensions(extResolver.urlMappings);
+ }
+ sdk.analysisOptions = options;
+ sdk.useSummary = sdkManager.canUseSummaries;
+ return sdk;
+ });
}
}
String sdkPath = sdkManager.defaultSdkDirectory;
@@ -232,9 +315,13 @@
});
}
- AnalysisOptions getAnalysisOptions(String rootDirectoryPath) {
- AnalysisOptionsImpl options = new AnalysisOptionsImpl.from(defaultOptions);
- File optionsFile = getOptionsFile(rootDirectoryPath);
+ /**
+ * Return the analysis options that should be used when analyzing code in the
+ * directory with the given [path].
+ */
+ AnalysisOptions getAnalysisOptions(String path) {
+ AnalysisOptionsImpl options = createDefaultOptions();
+ File optionsFile = getOptionsFile(path);
if (optionsFile != null) {
Map<String, YamlNode> fileOptions =
new AnalysisOptionsProvider().getOptionsFromFile(optionsFile);
@@ -243,11 +330,15 @@
return options;
}
- File getOptionsFile(String rootDirectoryPath) {
+ /**
+ * Return the analysis options file that should be used when analyzing code in
+ * the directory with the given [path].
+ */
+ File getOptionsFile(String path) {
if (defaultAnalysisOptionsFilePath != null) {
return resourceProvider.getFile(defaultAnalysisOptionsFilePath);
}
- Folder root = resourceProvider.getFolder(rootDirectoryPath);
+ Folder root = resourceProvider.getFolder(path);
for (Folder folder = root; folder != null; folder = folder.parent) {
File file =
folder.getChildAssumingFile(AnalysisEngine.ANALYSIS_OPTIONS_FILE);
diff --git a/pkg/analyzer/lib/src/context/cache.dart b/pkg/analyzer/lib/src/context/cache.dart
index 1f0f42c..50207ac 100644
--- a/pkg/analyzer/lib/src/context/cache.dart
+++ b/pkg/analyzer/lib/src/context/cache.dart
@@ -7,6 +7,7 @@
import 'dart:async';
import 'dart:collection';
+import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/src/dart/element/element.dart'
show ElementImpl, Modifier;
import 'package:analyzer/src/generated/engine.dart';
@@ -17,6 +18,11 @@
import 'package:analyzer/task/model.dart';
/**
+ * The cache results visiting function type.
+ */
+typedef void CacheResultVisitor(AnalysisTarget target, ResultData data);
+
+/**
* Return `true` if the [result] of the [target] should be flushed.
*/
typedef bool FlushResultFilter<V>(
@@ -296,9 +302,9 @@
static int _EXPLICITLY_ADDED_FLAG = 0;
/**
- * The next invalidation process identifier.
+ * The next visit process identifier.
*/
- static int nextInvalidateId = 0;
+ static int nextVisitId = 0;
/**
* A table containing the number of times the value of a result descriptor was
@@ -340,9 +346,7 @@
Map<ResultDescriptor, ResultData> _resultMap =
new HashMap<ResultDescriptor, ResultData>();
- CacheEntry(this.target) {
- _markAsCacheKey(target);
- }
+ CacheEntry(this.target);
/**
* The exception that caused one or more values to have a state of
@@ -391,10 +395,6 @@
}
});
_resultMap.clear();
- AnalysisTarget oldTarget = target;
- if (oldTarget is ElementImpl) {
- oldTarget.setModifier(Modifier.CACHE_KEY, false);
- }
}
/**
@@ -526,7 +526,12 @@
if (state == CacheState.INVALID) {
ResultData data = _resultMap[descriptor];
if (data != null) {
- _invalidate(nextInvalidateId++, descriptor, delta, 0);
+ bool canUseDelta =
+ _gatherResultsInvalidatedByDelta(descriptor, delta, 0);
+ if (!canUseDelta) {
+ delta = null;
+ }
+ _invalidate(nextVisitId++, descriptor, delta, 0);
}
} else {
ResultData data = getResultData(descriptor);
@@ -583,7 +588,7 @@
data.value = value;
}
if (invalidateDependent) {
- _invalidateDependentResults(nextInvalidateId++, data, null, 0);
+ _invalidateDependentResults(nextVisitId++, data, null, 0);
}
}
@@ -595,6 +600,35 @@
}
/**
+ * Visit the given [result] and all results that depend on it, and
+ * ask [delta] to gather changes. Return `true` if the [delta] can be used
+ * to perform limited invalidation, or `false` if the changes collection
+ * process does not stop (should not happen).
+ */
+ bool _gatherResultsInvalidatedByDelta(
+ ResultDescriptor result, Delta delta, int level) {
+ if (delta == null) {
+ return false;
+ }
+ for (int i = 0; i < 64; i++) {
+ bool hasVisitChanges = false;
+ _visitResults(nextVisitId++, result,
+ (AnalysisTarget target, ResultData data) {
+ bool hasDeltaChanges = delta.gatherChanges(
+ _partition.context, target, data.descriptor, data.value);
+ if (hasDeltaChanges) {
+ hasVisitChanges = true;
+ }
+ });
+ delta.gatherEnd();
+ if (!hasVisitChanges) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* Return the value of the flag with the given [index].
*/
bool _getFlag(int index) => BooleanArray.get(_flags, index);
@@ -611,10 +645,10 @@
}
// Stop if already validated.
if (delta != null) {
- if (thisData.invalidateId == id) {
+ if (thisData.visitId == id) {
return;
}
- thisData.invalidateId = id;
+ thisData.visitId = id;
}
// Ask the delta to validate.
DeltaResult deltaResult = null;
@@ -687,7 +721,7 @@
int length = results.length;
for (int i = 0; i < length; i++) {
ResultDescriptor result = results[i];
- _invalidate(nextInvalidateId++, result, null, 0);
+ _invalidate(nextVisitId++, result, null, 0);
}
}
@@ -715,15 +749,6 @@
}
/**
- * If the given `target` is an element, mark it as being a cache key.
- */
- void _markAsCacheKey(AnalysisTarget target) {
- if (target is ElementImpl) {
- target.setModifier(Modifier.CACHE_KEY, true);
- }
- }
-
- /**
* Set the [dependedOn] on which this result depends.
*/
void _setDependedOnResults(ResultData thisData, TargetedResult thisResult,
@@ -754,10 +779,8 @@
AnalysisCache cache = caches[j];
CacheEntry entry = cache.get(dependedOnResult.target);
if (entry != null) {
- ResultData data = entry.getResultDataOrNull(dependedOnResult.result);
- if (data != null) {
- data.dependentResults.add(thisResult);
- }
+ ResultData data = entry.getResultData(dependedOnResult.result);
+ data.dependentResults.add(thisResult);
}
}
}
@@ -818,6 +841,41 @@
}
/**
+ * Call [visitor] for the result described by the given [descriptor] and all
+ * results that depend on directly or indirectly. Each result is visited
+ * only once.
+ */
+ void _visitResults(
+ int id, ResultDescriptor descriptor, CacheResultVisitor visitor) {
+ ResultData thisData = _resultMap[descriptor];
+ if (thisData == null) {
+ return;
+ }
+ // Stop if already visited.
+ if (thisData.visitId == id) {
+ return;
+ }
+ thisData.visitId = id;
+ // Visit this result.
+ visitor(target, thisData);
+ // Visit results that depend on this result.
+ List<AnalysisCache> caches = _partition.containingCaches;
+ int cacheLength = caches.length;
+ List<TargetedResult> dependentResults = thisData.dependentResults.toList();
+ int resultLength = dependentResults.length;
+ for (int i = 0; i < resultLength; i++) {
+ TargetedResult dependentResult = dependentResults[i];
+ for (int j = 0; j < cacheLength; j++) {
+ AnalysisCache cache = caches[j];
+ CacheEntry entry = cache.get(dependentResult.target);
+ if (entry != null) {
+ entry._visitResults(id, dependentResult.result, visitor);
+ }
+ }
+ }
+ }
+
+ /**
* Write a textual representation of this entry to the given [buffer]. The
* result should only be used for debugging purposes.
*/
@@ -1185,6 +1243,16 @@
Delta(this.source);
+ bool gatherChanges(InternalAnalysisContext context, AnalysisTarget target,
+ ResultDescriptor descriptor, Object value) {
+ return false;
+ }
+
+ /**
+ * The current cache results visit is done.
+ */
+ void gatherEnd() {}
+
/**
* Check whether this delta affects the result described by the given
* [descriptor] and [target]. The current [value] of the result is provided.
@@ -1250,6 +1318,29 @@
}
/**
+ * A cache partition that contains all of the targets in a single package.
+ */
+class PackageCachePartition extends CachePartition {
+ /**
+ * The root of the directory representing the package.
+ */
+ final Folder packageRoot;
+
+ /**
+ * Initialize a newly created cache partition, belonging to the given
+ * [context].
+ */
+ PackageCachePartition(InternalAnalysisContext context, this.packageRoot)
+ : super(context);
+
+ @override
+ bool isResponsibleFor(AnalysisTarget target) {
+ Source source = target.source;
+ return source != null && packageRoot.contains(source.fullName);
+ }
+}
+
+/**
* A Stream-like interface, which broadcasts events synchronously.
* If a second event is fired while delivering a first event, then the second
* event will be delivered first, and then delivering of the first will be
@@ -1320,11 +1411,10 @@
Object value;
/**
- * The identifier of the invalidation process that most recently checked
- * this value. If it is the same as the current invalidation identifier,
- * then there is no reason to check it (and its subtree again).
+ * The identifier of the most recent visiting process. We use it to visit
+ * every result only once.
*/
- int invalidateId = -1;
+ int visitId = -1;
/**
* A list of the results on which this result depends.
diff --git a/pkg/analyzer/lib/src/context/context.dart b/pkg/analyzer/lib/src/context/context.dart
index 27098db..7ef0108 100644
--- a/pkg/analyzer/lib/src/context/context.dart
+++ b/pkg/analyzer/lib/src/context/context.dart
@@ -34,6 +34,7 @@
import 'package:analyzer/src/task/driver.dart';
import 'package:analyzer/src/task/incremental_element_builder.dart';
import 'package:analyzer/src/task/manager.dart';
+import 'package:analyzer/src/task/model.dart';
import 'package:analyzer/task/dart.dart';
import 'package:analyzer/task/general.dart';
import 'package:analyzer/task/html.dart';
@@ -41,6 +42,13 @@
import 'package:html/dom.dart' show Document;
/**
+ * The descriptor used to associate exclude patterns with an analysis context in
+ * configuration data.
+ */
+final ListResultDescriptor<String> CONTEXT_EXCLUDES =
+ new ListResultDescriptorImpl('CONTEXT_EXCLUDES', const <String>[]);
+
+/**
* Type of callback functions used by PendingFuture. Functions of this type
* should perform a computation based on the data in [entry] and return it. If
* the computation can't be performed yet because more analysis is needed,
@@ -158,6 +166,8 @@
*/
List<Source> _priorityOrder = <Source>[];
+ CacheConsistencyValidatorImpl _cacheConsistencyValidator;
+
/**
* A map from all sources for which there are futures pending to a list of
* the corresponding PendingFuture objects. These sources will be analyzed
@@ -347,6 +357,9 @@
driver.reset();
}
+ CacheConsistencyValidator get cacheConsistencyValidator =>
+ _cacheConsistencyValidator ??= new CacheConsistencyValidatorImpl(this);
+
@override
set contentCache(ContentCache value) {
_contentCache = value;
@@ -1375,57 +1388,6 @@
}
@override
- bool validateCacheConsistency() {
- int consistencyCheckStart = JavaSystem.nanoTime();
- HashSet<Source> changedSources = new HashSet<Source>();
- HashSet<Source> missingSources = new HashSet<Source>();
- for (Source source in _cache.sources) {
- CacheEntry entry = _cache.get(source);
- int sourceTime = getModificationStamp(source);
- if (sourceTime != entry.modificationTime) {
- changedSources.add(source);
- }
- if (entry.exception != null) {
- if (!exists(source)) {
- missingSources.add(source);
- }
- }
- }
- for (Source source in changedSources) {
- _sourceChanged(source);
- }
- int removalCount = 0;
- for (Source source in missingSources) {
- if (getLibrariesContaining(source).isEmpty &&
- getLibrariesDependingOn(source).isEmpty) {
- _removeFromCache(source);
- removalCount++;
- }
- }
- int consistencyCheckEnd = JavaSystem.nanoTime();
- if (changedSources.length > 0 || missingSources.length > 0) {
- StringBuffer buffer = new StringBuffer();
- buffer.write("Consistency check took ");
- buffer.write((consistencyCheckEnd - consistencyCheckStart) / 1000000.0);
- buffer.writeln(" ms and found");
- buffer.write(" ");
- buffer.write(changedSources.length);
- buffer.writeln(" inconsistent entries");
- buffer.write(" ");
- buffer.write(missingSources.length);
- buffer.write(" missing sources (");
- buffer.write(removalCount);
- buffer.writeln(" removed");
- for (Source source in missingSources) {
- buffer.write(" ");
- buffer.writeln(source.fullName);
- }
- _logInformation(buffer.toString());
- }
- return changedSources.length > 0;
- }
-
- @override
void visitContentCache(ContentCacheVisitor visitor) {
_contentCache.accept(visitor);
}
@@ -1871,21 +1833,25 @@
// (For example, in getLibrariesContaining.)
entry.setState(CONTENT, CacheState.FLUSHED);
- if (oldContents != null) {
- // Fast path if the content is the same as it was last time.
- try {
- TimestampedData<String> fileContents = getContents(source);
- if (fileContents.data == oldContents) {
- int time = fileContents.modificationTime;
- for (CacheEntry entry in _entriesFor(source)) {
- entry.modificationTime = time;
- }
- return;
- }
- } catch (e) {
- entry.modificationTime = -1;
+ // Prepare the new contents.
+ TimestampedData<String> fileContents;
+ try {
+ fileContents = getContents(source);
+ } catch (e) {}
+
+ // Update 'modificationTime' - we are going to update the entry.
+ {
+ int time = fileContents?.modificationTime ?? -1;
+ for (CacheEntry entry in _entriesFor(source)) {
+ entry.modificationTime = time;
}
}
+
+ // Fast path if the contents is the same as it was last time.
+ if (oldContents != null && fileContents?.data == oldContents) {
+ return;
+ }
+
// We need to invalidate the cache.
{
if (analysisOptions.finerGrainedInvalidation &&
@@ -1910,18 +1876,12 @@
builder.build();
CompilationUnitElementDelta unitDelta = builder.unitDelta;
if (!unitDelta.hasDirectiveChange) {
+ unitEntry.setValueIncremental(
+ COMPILATION_UNIT_CONSTANTS, builder.unitConstants, false);
DartDelta dartDelta = new DartDelta(source);
- dartDelta.hasDirectiveChange = unitDelta.hasDirectiveChange;
unitDelta.addedDeclarations.forEach(dartDelta.elementChanged);
unitDelta.removedDeclarations.forEach(dartDelta.elementChanged);
unitDelta.classDeltas.values.forEach(dartDelta.classChanged);
- // Add other names in the library that are changed transitively.
- {
- ReferencedNames referencedNames = new ReferencedNames(source);
- new ReferencedNamesBuilder(referencedNames).build(oldUnit);
- dartDelta.addChangedElements(referencedNames);
- }
- // Invalidate using the prepared DartDelta.
entry.setState(CONTENT, CacheState.INVALID, delta: dartDelta);
return;
}
@@ -2097,6 +2057,86 @@
}
}
+class CacheConsistencyValidatorImpl implements CacheConsistencyValidator {
+ final AnalysisContextImpl context;
+
+ CacheConsistencyValidatorImpl(this.context);
+
+ @override
+ List<Source> getSourcesToComputeModificationTimes() {
+ return context._privatePartition.sources.toList();
+ }
+
+ @override
+ bool sourceModificationTimesComputed(List<Source> sources, List<int> times) {
+ int consistencyCheckStart = JavaSystem.nanoTime();
+ HashSet<Source> changedSources = new HashSet<Source>();
+ HashSet<Source> missingSources = new HashSet<Source>();
+ for (int i = 0; i < sources.length; i++) {
+ Source source = sources[i];
+ // When a source is in the content cache,
+ // its modification time in the file system does not matter.
+ if (context._contentCache.getModificationStamp(source) != null) {
+ continue;
+ }
+ // When we were not able to compute the modification time in the
+ // file system, there is nothing to compare with, so skip the source.
+ int sourceTime = times[i];
+ if (sourceTime == null) {
+ continue;
+ }
+ // Compare with the modification time in the cache entry.
+ CacheEntry entry = context._privatePartition.get(source);
+ if (entry != null) {
+ if (sourceTime != entry.modificationTime) {
+ changedSources.add(source);
+ PerformanceStatistics
+ .cacheConsistencyValidationStatistics.numOfModified++;
+ }
+ if (entry.exception != null) {
+ if (sourceTime == -1) {
+ missingSources.add(source);
+ PerformanceStatistics
+ .cacheConsistencyValidationStatistics.numOfModified++;
+ }
+ }
+ }
+ }
+ for (Source source in changedSources) {
+ context._sourceChanged(source);
+ }
+ int removalCount = 0;
+ for (Source source in missingSources) {
+ if (context.getLibrariesContaining(source).isEmpty &&
+ context.getLibrariesDependingOn(source).isEmpty) {
+ context._removeFromCache(source);
+ removalCount++;
+ }
+ }
+ int consistencyCheckEnd = JavaSystem.nanoTime();
+ if (changedSources.length > 0 || missingSources.length > 0) {
+ StringBuffer buffer = new StringBuffer();
+ buffer.write("Consistency check took ");
+ buffer.write((consistencyCheckEnd - consistencyCheckStart) / 1000000.0);
+ buffer.writeln(" ms and found");
+ buffer.write(" ");
+ buffer.write(changedSources.length);
+ buffer.writeln(" inconsistent entries");
+ buffer.write(" ");
+ buffer.write(missingSources.length);
+ buffer.write(" missing sources (");
+ buffer.write(removalCount);
+ buffer.writeln(" removed");
+ for (Source source in missingSources) {
+ buffer.write(" ");
+ buffer.writeln(source.fullName);
+ }
+ context._logInformation(buffer.toString());
+ }
+ return changedSources.length > 0;
+ }
+}
+
/**
* An object that manages the partitions that can be shared between analysis
* contexts.
diff --git a/pkg/analyzer/lib/src/context/context_factory.dart b/pkg/analyzer/lib/src/context/context_factory.dart
deleted file mode 100644
index b96100d..0000000
--- a/pkg/analyzer/lib/src/context/context_factory.dart
+++ /dev/null
@@ -1,136 +0,0 @@
-// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library analyzer.src.context_factory;
-
-import 'dart:convert';
-import 'dart:core' hide Resource;
-
-import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/src/generated/sdk.dart';
-import 'package:yaml/yaml.dart';
-import 'package:analyzer/src/generated/engine.dart';
-import 'dart:io' as io;
-
-/// (Placeholder)
-abstract class ContextFactory {
- /// Create an analysis context for the given [source] directory or file, with
- /// the given [defaultOptions].
- AnalysisContext createContext(
- io.FileSystemEntity source, AnalysisOptions defaultOptions);
-}
-
-/// Processes package maps, extracting SDK embedders and extenders, creating a
-/// consolidated [libraryMap].
-class PackageMapProcessor {
- static const String _EMBEDDED_LIB_MAP_KEY = 'embedded_libs';
- static const String _EMBEDDER_FILE_NAME = '_embedder.yaml';
- static const String _SDK_EXT_NAME = '_sdkext';
-
- /// Map of processed embedder libraries.
- final LibraryMap embeddedLibraries = new LibraryMap();
-
- /// Map of processed SDK extension libraries.
- final LibraryMap extendedLibraries = new LibraryMap();
-
- /// Combined map of processed libraries.
- LibraryMap get libraryMap {
- LibraryMap libraryMap = new LibraryMap();
-
- // Add extenders first, allowing for overwrite by embedders who take precedence.
- for (String uri in extendedLibraries.uris) {
- libraryMap.setLibrary(uri, extendedLibraries.getLibrary(uri));
- }
- for (String uri in embeddedLibraries.uris) {
- libraryMap.setLibrary(uri, embeddedLibraries.getLibrary(uri));
- }
- return libraryMap;
- }
-
- /// Create a processor for the given [packageMap].
- PackageMapProcessor(Map<String, List<Folder>> packageMap) {
- packageMap?.forEach(_processPackage);
- }
-
- /// Whether the package map contains an SDK embedder.
- bool get hasEmbedder => embeddedLibraries.size() > 0;
-
- /// Whether the package map contains an SDK extension.
- bool get hasSdkExtension => extendedLibraries.size() > 0;
-
- void _processEmbedderYaml(String embedderYaml, Folder libDir) {
- try {
- YamlNode map = loadYaml(embedderYaml);
- if (map is YamlMap) {
- YamlNode embedded_libs = map[_EMBEDDED_LIB_MAP_KEY];
- if (embedded_libs is YamlMap) {
- embedded_libs.forEach(
- (k, v) => _processMapping(embeddedLibraries, k, v, libDir));
- }
- }
- } catch (_) {
- // Ignored.
- }
- }
-
- void _processMapping(
- LibraryMap libraryMap, String name, String file, Folder libDir) {
- if (!_hasDartPrefix(name)) {
- // SDK libraries must begin with 'dart:'.
- return;
- }
- if (libraryMap.getLibrary(name) != null) {
- // Libraries can't be redefined.
- return;
- }
- String libPath = libDir.canonicalizePath(file);
- SdkLibraryImpl library = new SdkLibraryImpl(name)..path = libPath;
- libraryMap.setLibrary(name, library);
- }
-
- void _processPackage(String name, List<Folder> libDirs) {
- for (Folder libDir in libDirs) {
- String embedderYaml = _readEmbedderYaml(libDir);
- if (embedderYaml != null) {
- _processEmbedderYaml(embedderYaml, libDir);
- }
- String sdkExt = _readDotSdkExt(libDir);
- if (sdkExt != null) {
- _processSdkExt(sdkExt, libDir);
- }
- }
- }
-
- void _processSdkExt(String sdkExtJSON, Folder libDir) {
- try {
- var sdkExt = JSON.decode(sdkExtJSON);
- if (sdkExt is Map) {
- sdkExt.forEach(
- (k, v) => _processMapping(extendedLibraries, k, v, libDir));
- }
- } catch (_) {
- // Ignored.
- }
- }
-
- static bool _hasDartPrefix(String uri) =>
- uri.startsWith(DartSdk.DART_LIBRARY_PREFIX);
-
- static String _readDotSdkExt(Folder libDir) =>
- _safeRead(libDir.getChild(_SDK_EXT_NAME));
-
- static String _readEmbedderYaml(Folder libDir) =>
- _safeRead(libDir.getChild(_EMBEDDER_FILE_NAME));
-
- static String _safeRead(Resource file) {
- try {
- if (file is File) {
- return file.readAsStringSync();
- }
- } on FileSystemException {
- // File can't be read.
- }
- return null;
- }
-}
diff --git a/pkg/analyzer/lib/src/dart/constant/evaluation.dart b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
index 0c8288a..57eee89 100644
--- a/pkg/analyzer/lib/src/dart/constant/evaluation.dart
+++ b/pkg/analyzer/lib/src/dart/constant/evaluation.dart
@@ -23,7 +23,6 @@
import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/java_core.dart';
import 'package:analyzer/src/generated/resolver.dart' show TypeProvider;
-import 'package:analyzer/src/generated/source.dart' show Source;
import 'package:analyzer/src/generated/type_system.dart'
show TypeSystem, TypeSystemImpl;
import 'package:analyzer/src/generated/utilities_collection.dart';
@@ -930,15 +929,13 @@
*/
final ConstantEvaluationEngine evaluationEngine;
- final AnalysisContext _context;
-
/**
* Initialize a newly created constant value computer. The [typeProvider] is
* the type provider used to access known types. The [declaredVariables] is
* the set of variables declared on the command line using '-D'.
*/
- ConstantValueComputer(this._context, TypeProvider typeProvider,
- DeclaredVariables declaredVariables,
+ ConstantValueComputer(
+ TypeProvider typeProvider, DeclaredVariables declaredVariables,
[ConstantEvaluationValidator validator, TypeSystem typeSystem])
: evaluationEngine = new ConstantEvaluationEngine(
typeProvider, declaredVariables,
@@ -948,9 +945,8 @@
* Add the constants in the given compilation [unit] to the list of constants
* whose value needs to be computed.
*/
- void add(CompilationUnit unit, Source source, Source librarySource) {
- ConstantFinder constantFinder =
- new ConstantFinder(_context, source, librarySource);
+ void add(CompilationUnit unit) {
+ ConstantFinder constantFinder = new ConstantFinder();
unit.accept(constantFinder);
_constantsToCompute.addAll(constantFinder.constantsToCompute);
}
diff --git a/pkg/analyzer/lib/src/dart/constant/utilities.dart b/pkg/analyzer/lib/src/dart/constant/utilities.dart
index 62b3ec8..90c8a38 100644
--- a/pkg/analyzer/lib/src/dart/constant/utilities.dart
+++ b/pkg/analyzer/lib/src/dart/constant/utilities.dart
@@ -14,8 +14,6 @@
import 'package:analyzer/src/dart/element/handle.dart'
show ConstructorElementHandle;
import 'package:analyzer/src/dart/element/member.dart';
-import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/source.dart' show Source;
import 'package:analyzer/src/task/dart.dart';
ConstructorElementImpl getConstructorImpl(ConstructorElement constructor) {
@@ -156,10 +154,6 @@
* those compilation units.
*/
class ConstantFinder extends RecursiveAstVisitor<Object> {
- final AnalysisContext context;
- final Source source;
- final Source librarySource;
-
/**
* The elements and AST nodes whose constant values need to be computed.
*/
@@ -172,8 +166,6 @@
*/
bool treatFinalInstanceVarAsConst = false;
- ConstantFinder(this.context, this.source, this.librarySource);
-
@override
Object visitAnnotation(Annotation node) {
super.visitAnnotation(node);
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 4619738..7743244 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -474,6 +474,13 @@
bool _hasBeenInferred = false;
/**
+ * The version of this element. The version is changed when the element is
+ * incrementally updated, so that its lists of constructors, accessors and
+ * methods might be different.
+ */
+ int version = 0;
+
+ /**
* Initialize a newly created class element to have the given [name] at the
* given [offset] in the file that contains the declaration of this element.
*/
@@ -2526,7 +2533,7 @@
/**
* The compilation unit in which this annotation appears.
*/
- final CompilationUnitElementImpl compilationUnit;
+ CompilationUnitElementImpl compilationUnit;
/**
* The AST of the annotation itself, cloned from the resolved AST for the
@@ -2777,7 +2784,6 @@
*/
void set enclosingElement(Element element) {
_enclosingElement = element as ElementImpl;
- _updateCaches();
}
/**
@@ -2921,7 +2927,6 @@
*/
void set name(String name) {
this._name = name;
- _updateCaches();
}
@override
@@ -2938,7 +2943,6 @@
*/
void set nameOffset(int offset) {
_nameOffset = offset;
- _updateCaches();
}
@override
@@ -3150,33 +3154,14 @@
}
}
- /**
- * Updates cached values after an input changed.
- *
- * Throws [FrozenHashCodeException] if not allowed.
- */
- void _updateCaches() {
- if (!hasModifier(Modifier.CACHE_KEY)) {
- // Fast path.
- _cachedLocation = null;
- _cachedHashCode = null;
- return;
+ static int _findElementIndexUsingIdentical(List items, Object item) {
+ int length = items.length;
+ for (int i = 0; i < length; i++) {
+ if (identical(items[i], item)) {
+ return i;
+ }
}
-
- // Save originals.
- ElementLocation oldLocation = _cachedLocation;
- int oldHashCode = _cachedHashCode;
-
- _cachedLocation = null;
- _cachedHashCode = null;
-
- if (oldHashCode != hashCode) {
- // Prevent cache corruption by restoring originals.
- _cachedLocation = oldLocation;
- _cachedHashCode = oldHashCode;
- throw new FrozenHashCodeException(
- "can't update hashCode for a cache key: $this ($runtimeType)");
- }
+ throw new StateError('Unable to find $item in $items');
}
}
@@ -4343,18 +4328,6 @@
}
/**
- * Indicates that an ElementImpl's hashCode cannot currently be changed.
- */
-class FrozenHashCodeException implements Exception {
- final String _message;
-
- FrozenHashCodeException(this._message);
-
- @override
- String toString() => "FrozenHashCodeException($_message)";
-}
-
-/**
* A concrete implementation of a [FunctionElement].
*/
class FunctionElementImpl extends ExecutableElementImpl
@@ -4416,8 +4389,11 @@
@override
String get identifier {
String identifier = super.identifier;
- if (!isStatic) {
- identifier += "@$nameOffset";
+ Element enclosing = this.enclosingElement;
+ if (enclosing is ExecutableElement) {
+ int id = ElementImpl._findElementIndexUsingIdentical(
+ enclosing.functions, this);
+ identifier += "@$id";
}
return identifier;
}
@@ -6159,10 +6135,14 @@
@override
String get identifier {
- int enclosingOffset =
- enclosingElement != null ? enclosingElement.nameOffset : 0;
- int delta = nameOffset - enclosingOffset;
- return '${super.identifier}@$delta';
+ String identifier = super.identifier;
+ Element enclosing = this.enclosingElement;
+ if (enclosing is ExecutableElement) {
+ int id = ElementImpl._findElementIndexUsingIdentical(
+ enclosing.localVariables, this);
+ identifier += "@$id";
+ }
+ return identifier;
}
@override
@@ -6426,12 +6406,7 @@
*/
static const Modifier SYNTHETIC = const Modifier('SYNTHETIC', 16);
- /**
- * Indicates that this element is being used as an analyzer cache key.
- */
- static const Modifier CACHE_KEY = const Modifier('CACHE_KEY', 17);
-
- static const List<Modifier> persistedValues = const [
+ static const List<Modifier> values = const [
ABSTRACT,
ASYNCHRONOUS,
CONST,
@@ -6451,11 +6426,6 @@
SYNTHETIC
];
- static const List<Modifier> transientValues = const [CACHE_KEY];
-
- static final values = new List.unmodifiable(
- []..addAll(persistedValues)..addAll(transientValues));
-
const Modifier(String name, int ordinal) : super(name, ordinal);
}
diff --git a/pkg/analyzer/lib/src/dart/element/type.dart b/pkg/analyzer/lib/src/dart/element/type.dart
index 22a247a..df19008 100644
--- a/pkg/analyzer/lib/src/dart/element/type.dart
+++ b/pkg/analyzer/lib/src/dart/element/type.dart
@@ -1176,6 +1176,11 @@
final List<FunctionTypeAliasElement> prunedTypedefs;
/**
+ * The version of [element] for which members are cached.
+ */
+ int _versionOfCachedMembers = null;
+
+ /**
* Cached [ConstructorElement]s - members or raw elements.
*/
List<ConstructorElement> _constructors;
@@ -1223,6 +1228,7 @@
@override
List<PropertyAccessorElement> get accessors {
+ _flushCachedMembersIfStale();
if (_accessors == null) {
List<PropertyAccessorElement> accessors = element.accessors;
List<PropertyAccessorElement> members =
@@ -1237,6 +1243,7 @@
@override
List<ConstructorElement> get constructors {
+ _flushCachedMembersIfStale();
if (_constructors == null) {
List<ConstructorElement> constructors = element.constructors;
List<ConstructorElement> members =
@@ -1331,6 +1338,7 @@
@override
List<MethodElement> get methods {
+ _flushCachedMembersIfStale();
if (_methods == null) {
List<MethodElement> methods = element.methods;
List<MethodElement> members = new List<MethodElement>(methods.length);
@@ -1891,6 +1899,23 @@
instantiate(argumentTypes);
/**
+ * Flush cache members if the version of [element] for which members are
+ * cached and the current version of the [element].
+ */
+ void _flushCachedMembersIfStale() {
+ ClassElement element = this.element;
+ if (element is ClassElementImpl) {
+ int currentVersion = element.version;
+ if (_versionOfCachedMembers != currentVersion) {
+ _constructors = null;
+ _accessors = null;
+ _methods = null;
+ }
+ _versionOfCachedMembers = currentVersion;
+ }
+ }
+
+ /**
* Starting from this type, search its class hierarchy for types of the form
* Future<R>, and return a list of the resulting R's.
*/
diff --git a/pkg/analyzer/lib/src/dart/resolver/scope.dart b/pkg/analyzer/lib/src/dart/resolver/scope.dart
index 04da23d..9211f8a 100644
--- a/pkg/analyzer/lib/src/dart/resolver/scope.dart
+++ b/pkg/analyzer/lib/src/dart/resolver/scope.dart
@@ -125,7 +125,7 @@
getSource(identifier),
identifier.offset,
identifier.length,
- CompileTimeErrorCode.REFERENCED_BEFORE_DECLARATION, []));
+ CompileTimeErrorCode.REFERENCED_BEFORE_DECLARATION, [name]));
return hiddenElement;
}
}
diff --git a/pkg/analyzer/lib/src/generated/element_resolver.dart b/pkg/analyzer/lib/src/generated/element_resolver.dart
index dcb40d6..6c2cd97 100644
--- a/pkg/analyzer/lib/src/generated/element_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/element_resolver.dart
@@ -1100,19 +1100,23 @@
if (_isConstructorReturnType(node)) {
_resolver.errorReporter.reportErrorForNode(
CompileTimeErrorCode.INVALID_CONSTRUCTOR_NAME, node);
+ } else if (parent is Annotation) {
+ _resolver.errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.INVALID_ANNOTATION, parent);
+ } else if (element != null) {
+ _resolver.errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT,
+ node,
+ [element.name]);
+ } else if (node.name == "await" && _resolver.enclosingFunction != null) {
+ _recordUndefinedNode(
+ _resolver.enclosingClass,
+ StaticWarningCode.UNDEFINED_IDENTIFIER_AWAIT,
+ node,
+ [_resolver.enclosingFunction.displayName]);
} else {
- if (parent is Annotation) {
- _resolver.errorReporter.reportErrorForNode(
- CompileTimeErrorCode.INVALID_ANNOTATION, parent);
- } else if (element != null) {
- _resolver.errorReporter.reportErrorForNode(
- CompileTimeErrorCode.PREFIX_IDENTIFIER_NOT_FOLLOWED_BY_DOT,
- node,
- [element.name]);
- } else {
- _recordUndefinedNode(_resolver.enclosingClass,
- StaticWarningCode.UNDEFINED_IDENTIFIER, node, [node.name]);
- }
+ _recordUndefinedNode(_resolver.enclosingClass,
+ StaticWarningCode.UNDEFINED_IDENTIFIER, node, [node.name]);
}
}
node.staticElement = element;
diff --git a/pkg/analyzer/lib/src/generated/engine.dart b/pkg/analyzer/lib/src/generated/engine.dart
index 67a931c7..9cd12c7 100644
--- a/pkg/analyzer/lib/src/generated/engine.dart
+++ b/pkg/analyzer/lib/src/generated/engine.dart
@@ -629,14 +629,6 @@
* so that the default contents will be returned.
*/
void setContents(Source source, String contents);
-
- /**
- * Check the cache for any invalid entries (entries whose modification time
- * does not match the modification time of the source associated with the
- * entry). Invalid entries will be marked as invalid so that the source will
- * be re-analyzed. Return `true` if at least one entry was invalid.
- */
- bool validateCacheConsistency();
}
/**
@@ -1249,7 +1241,7 @@
bool enableTiming = false;
@override
- bool enableTrailingCommas = false;
+ bool enableTrailingCommas = true;
/**
* A flag indicating whether errors, warnings and hints should be generated
@@ -1553,6 +1545,50 @@
}
/**
+ * Statistics about cache consistency validation.
+ */
+class CacheConsistencyValidationStatistics {
+ /**
+ * Number of sources which were modified, but the context was not notified
+ * about it, so this fact was detected only during cache consistency
+ * validation.
+ */
+ int numOfModified = 0;
+
+ /**
+ * Number of sources which were deleted, but the context was not notified
+ * about it, so this fact was detected only during cache consistency
+ * validation.
+ */
+ int numOfDeleted = 0;
+}
+
+/**
+ * Interface for cache consistency validation in an [InternalAnalysisContext].
+ */
+abstract class CacheConsistencyValidator {
+ /**
+ * Return sources for which the contexts needs to know modification times.
+ */
+ List<Source> getSourcesToComputeModificationTimes();
+
+ /**
+ * Notify the validator that modification [times] were computed for [sources].
+ * If a source does not exist, its modification time is `-1`.
+ *
+ * It's up to the validator and the context how to use this information,
+ * the list of sources the context has might have been changed since the
+ * previous invocation of [getSourcesToComputeModificationTimes].
+ *
+ * Check the cache for any invalid entries (entries whose modification time
+ * does not match the modification time of the source associated with the
+ * entry). Invalid entries will be marked as invalid so that the source will
+ * be re-analyzed. Return `true` if at least one entry was invalid.
+ */
+ bool sourceModificationTimesComputed(List<Source> sources, List<int> times);
+}
+
+/**
* The possible states of cached data.
*/
class CacheState extends Enum<CacheState> {
@@ -2037,6 +2073,11 @@
AnalysisCache get analysisCache;
/**
+ * The cache consistency validator for this context.
+ */
+ CacheConsistencyValidator get cacheConsistencyValidator;
+
+ /**
* Allow the client to supply its own content cache. This will take the
* place of the content cache created by default, allowing clients to share
* the content cache between contexts.
@@ -2332,6 +2373,13 @@
* The [PerformanceTag] for time spent in summaries support.
*/
static PerformanceTag summary = new PerformanceTag('summary');
+
+ /**
+ * Statistics about cache consistency validation.
+ */
+ static final CacheConsistencyValidationStatistics
+ cacheConsistencyValidationStatistics =
+ new CacheConsistencyValidationStatistics();
}
/**
diff --git a/pkg/analyzer/lib/src/generated/error.dart b/pkg/analyzer/lib/src/generated/error.dart
index f8b369c..728435f 100644
--- a/pkg/analyzer/lib/src/generated/error.dart
+++ b/pkg/analyzer/lib/src/generated/error.dart
@@ -2223,7 +2223,7 @@
*/
static const CompileTimeErrorCode REFERENCED_BEFORE_DECLARATION =
const CompileTimeErrorCode('REFERENCED_BEFORE_DECLARATION',
- "Local variables cannot be referenced before they are declared");
+ "Local variable '{0}' cannot be referenced before it is declared");
/**
* 12.8.1 Rethrow: It is a compile-time error if an expression of the form
@@ -2698,6 +2698,7 @@
HintCode.MISSING_RETURN,
HintCode.NULL_AWARE_IN_CONDITION,
HintCode.OVERRIDE_ON_NON_OVERRIDING_GETTER,
+ HintCode.OVERRIDE_ON_NON_OVERRIDING_FIELD,
HintCode.OVERRIDE_ON_NON_OVERRIDING_METHOD,
HintCode.OVERRIDE_ON_NON_OVERRIDING_SETTER,
HintCode.OVERRIDE_EQUALS_BUT_NOT_HASH_CODE,
@@ -2881,6 +2882,7 @@
StrongModeCode.INVALID_SUPER_INVOCATION,
StrongModeCode.NON_GROUND_TYPE_CHECK_INFO,
StrongModeCode.STATIC_TYPE_ERROR,
+ StrongModeCode.UNSAFE_BLOCK_CLOSURE_INFERENCE,
TodoCode.TODO,
@@ -2894,10 +2896,6 @@
ParserErrorCode.ABSTRACT_TOP_LEVEL_VARIABLE,
ParserErrorCode.ABSTRACT_TYPEDEF,
ParserErrorCode.ANNOTATION_ON_ENUM_CONSTANT,
- ParserErrorCode.ASSERT_DOES_NOT_TAKE_ASSIGNMENT,
- ParserErrorCode.ASSERT_DOES_NOT_TAKE_CASCADE,
- ParserErrorCode.ASSERT_DOES_NOT_TAKE_THROW,
- ParserErrorCode.ASSERT_DOES_NOT_TAKE_RETHROW,
ParserErrorCode.ASYNC_KEYWORD_USED_AS_IDENTIFIER,
ParserErrorCode.ASYNC_NOT_SUPPORTED,
ParserErrorCode.BREAK_OUTSIDE_OF_LOOP,
@@ -3734,6 +3732,13 @@
"Getter does not override an inherited getter");
/**
+ * A field with the override annotation does not override a getter or setter.
+ */
+ static const HintCode OVERRIDE_ON_NON_OVERRIDING_FIELD = const HintCode(
+ 'OVERRIDE_ON_NON_OVERRIDING_FIELD',
+ "Field does not override an inherited getter or setter");
+
+ /**
* A method with the override annotation does not override an existing method.
*/
static const HintCode OVERRIDE_ON_NON_OVERRIDING_METHOD = const HintCode(
@@ -5760,6 +5765,13 @@
const StaticWarningCode('UNDEFINED_IDENTIFIER', "Undefined name '{0}'");
/**
+ * If the identifier is 'await', be helpful about it.
+ */
+ static const StaticWarningCode UNDEFINED_IDENTIFIER_AWAIT =
+ const StaticWarningCode('UNDEFINED_IDENTIFIER_AWAIT',
+ "Undefined name 'await'; did you mean to add the 'async' marker to '{0}'?");
+
+ /**
* 12.14.2 Binding Actuals to Formals: Furthermore, each <i>q<sub>i</sub></i>,
* <i>1<=i<=l</i>, must have a corresponding named parameter in the set
* {<i>p<sub>n+1</sub></i> … <i>p<sub>n+k</sub></i>} or a static
@@ -5894,6 +5906,11 @@
static const String _implicitCastMessage =
'Unsound implicit cast from {0} to {1}';
+ static const String _unsafeBlockClosureInferenceMessage =
+ 'Unsafe use of block closure in a type-inferred variable outside a '
+ 'function body. Workaround: add a type annotation for `{0}`. See '
+ 'dartbug.com/26947';
+
static const String _typeCheckMessage =
'Type check failed: {0} is not of type {1}';
@@ -6041,6 +6058,12 @@
"Missing type arguments for calling generic function type '{0}'"
"$_implicitDynamicTip");
+ static const StrongModeCode UNSAFE_BLOCK_CLOSURE_INFERENCE =
+ const StrongModeCode(
+ ErrorType.STATIC_WARNING,
+ 'UNSAFE_BLOCK_CLOSURE_INFERENCE',
+ _unsafeBlockClosureInferenceMessage);
+
@override
final ErrorType type;
diff --git a/pkg/analyzer/lib/src/generated/error_verifier.dart b/pkg/analyzer/lib/src/generated/error_verifier.dart
index 6d4177b..0a54caa 100644
--- a/pkg/analyzer/lib/src/generated/error_verifier.dart
+++ b/pkg/analyzer/lib/src/generated/error_verifier.dart
@@ -3399,29 +3399,34 @@
*/
void _checkForFieldInitializingFormalRedirectingConstructor(
FieldFormalParameter parameter) {
- ConstructorDeclaration constructor =
- parameter.getAncestor((node) => node is ConstructorDeclaration);
- if (constructor == null) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR,
- parameter);
- return;
+ // prepare the node that should be a ConstructorDeclaration
+ AstNode formalParameterList = parameter.parent;
+ if (formalParameterList is! FormalParameterList) {
+ formalParameterList = formalParameterList?.parent;
}
- // constructor cannot be a factory
- if (constructor.factoryKeyword != null) {
- _errorReporter.reportErrorForNode(
- CompileTimeErrorCode.FIELD_INITIALIZER_FACTORY_CONSTRUCTOR,
- parameter);
- return;
- }
- // constructor cannot have a redirection
- for (ConstructorInitializer initializer in constructor.initializers) {
- if (initializer is RedirectingConstructorInvocation) {
+ AstNode constructor = formalParameterList?.parent;
+ // now check whether the node is actually a ConstructorDeclaration
+ if (constructor is ConstructorDeclaration) {
+ // constructor cannot be a factory
+ if (constructor.factoryKeyword != null) {
_errorReporter.reportErrorForNode(
- CompileTimeErrorCode.FIELD_INITIALIZER_REDIRECTING_CONSTRUCTOR,
+ CompileTimeErrorCode.FIELD_INITIALIZER_FACTORY_CONSTRUCTOR,
parameter);
return;
}
+ // constructor cannot have a redirection
+ for (ConstructorInitializer initializer in constructor.initializers) {
+ if (initializer is RedirectingConstructorInvocation) {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.FIELD_INITIALIZER_REDIRECTING_CONSTRUCTOR,
+ parameter);
+ return;
+ }
+ }
+ } else {
+ _errorReporter.reportErrorForNode(
+ CompileTimeErrorCode.FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR,
+ parameter);
}
}
@@ -4065,18 +4070,8 @@
if (lhs == null) {
return;
}
- VariableElement leftVariableElement = getVariableElement(lhs);
- DartType leftType = (leftVariableElement == null)
- ? getStaticType(lhs)
- : leftVariableElement.type;
- MethodElement invokedMethod = assignment.staticElement;
- if (invokedMethod == null) {
- return;
- }
- DartType rightType = invokedMethod.type.returnType;
- if (leftType == null || rightType == null) {
- return;
- }
+ DartType leftType = getStaticType(lhs);
+ DartType rightType = getStaticType(assignment);
if (!_typeSystem.isAssignableTo(rightType, leftType)) {
_errorReporter.reportTypeErrorForNode(
StaticTypeWarningCode.INVALID_ASSIGNMENT, rhs, [rightType, leftType]);
diff --git a/pkg/analyzer/lib/src/generated/incremental_resolver.dart b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
index 77907db..1194f5f 100644
--- a/pkg/analyzer/lib/src/generated/incremental_resolver.dart
+++ b/pkg/analyzer/lib/src/generated/incremental_resolver.dart
@@ -95,6 +95,7 @@
isByTask(BuildSourceExportClosureTask.DESCRIPTOR) ||
isByTask(ComputeConstantDependenciesTask.DESCRIPTOR) ||
isByTask(ComputeConstantValueTask.DESCRIPTOR) ||
+ isByTask(ComputeInferableStaticVariableDependenciesTask.DESCRIPTOR) ||
isByTask(ComputeLibraryCycleTask.DESCRIPTOR) ||
isByTask(ComputePropagableVariableDependenciesTask.DESCRIPTOR) ||
isByTask(DartErrorsTask.DESCRIPTOR) ||
@@ -106,6 +107,7 @@
isByTask(GenerateHintsTask.DESCRIPTOR) ||
isByTask(InferInstanceMembersInUnitTask.DESCRIPTOR) ||
isByTask(InferStaticVariableTypesInUnitTask.DESCRIPTOR) ||
+ isByTask(InferStaticVariableTypeTask.DESCRIPTOR) ||
isByTask(LibraryErrorsReadyTask.DESCRIPTOR) ||
isByTask(LibraryUnitErrorsTask.DESCRIPTOR) ||
isByTask(ParseDartTask.DESCRIPTOR) ||
@@ -295,9 +297,9 @@
// compute values
{
CompilationUnit unit = node.getAncestor((n) => n is CompilationUnit);
- ConstantValueComputer computer = new ConstantValueComputer(_context,
+ ConstantValueComputer computer = new ConstantValueComputer(
_typeProvider, _context.declaredVariables, null, _typeSystem);
- computer.add(unit, _source, _librarySource);
+ computer.add(unit);
computer.computeValues();
}
// validate
@@ -740,6 +742,7 @@
RecordingErrorListener errorListener = new RecordingErrorListener();
Parser parser = new Parser(_unitSource, errorListener);
AnalysisOptions options = _unitElement.context.analysisOptions;
+ parser.parseGenericMethodComments = options.strongMode;
parser.parseGenericMethods = options.enableGenericMethods;
CompilationUnit unit = parser.parseCompilationUnit(token);
_newParseErrors = errorListener.errors;
@@ -819,6 +822,8 @@
RecordingErrorListener errorListener = new RecordingErrorListener();
CharSequenceReader reader = new CharSequenceReader(code);
Scanner scanner = new Scanner(_unitSource, reader, errorListener);
+ AnalysisOptions options = _unitElement.context.analysisOptions;
+ scanner.scanGenericMethodComments = options.strongMode;
Token token = scanner.tokenize();
_newLineInfo = new LineInfo(scanner.lineStarts);
_newScanErrors = errorListener.errors;
@@ -870,6 +875,10 @@
// parse results
_sourceEntry.setValueIncremental(PARSE_ERRORS, _newParseErrors, true);
_sourceEntry.setValueIncremental(PARSED_UNIT, _oldUnit, false);
+ // referenced names
+ ReferencedNames referencedNames = new ReferencedNames(_unitSource);
+ new ReferencedNamesBuilder(referencedNames).build(_oldUnit);
+ _sourceEntry.setValueIncremental(REFERENCED_NAMES, referencedNames, false);
}
/**
@@ -1196,19 +1205,13 @@
// name offset
int nameOffset = element.nameOffset;
if (nameOffset > updateOffset) {
- // TODO(scheglov) make sure that we don't put local variables
- // and functions into the cache at all.
- try {
- (element as ElementImpl).nameOffset = nameOffset + updateDelta;
- } on FrozenHashCodeException {
- cache.remove(element);
- (element as ElementImpl).nameOffset = nameOffset + updateDelta;
- }
+ (element as ElementImpl).nameOffset = nameOffset + updateDelta;
if (element is ConstVariableElement) {
Expression initializer = element.constantInitializer;
if (initializer != null) {
_shiftTokens(initializer.beginToken);
}
+ _shiftErrors(element.evaluationResult?.errors);
}
}
// code range
@@ -1251,6 +1254,17 @@
super.visitElement(element);
}
+ void _shiftErrors(List<AnalysisError> errors) {
+ if (errors != null) {
+ for (AnalysisError error in errors) {
+ int errorOffset = error.offset;
+ if (errorOffset > updateOffset) {
+ error.offset += updateDelta;
+ }
+ }
+ }
+ }
+
void _shiftTokens(Token token) {
while (token != null) {
if (token.offset > updateOffset) {
diff --git a/pkg/analyzer/lib/src/generated/parser.dart b/pkg/analyzer/lib/src/generated/parser.dart
index ab3b05e..f63bb70 100644
--- a/pkg/analyzer/lib/src/generated/parser.dart
+++ b/pkg/analyzer/lib/src/generated/parser.dart
@@ -4357,25 +4357,12 @@
* This method assumes that the current token matches `Keyword.ASSERT`.
*
* assertStatement ::=
- * 'assert' '(' conditionalExpression ')' ';'
+ * 'assert' '(' expression [',' expression] ')' ';'
*/
AssertStatement _parseAssertStatement() {
Token keyword = getAndAdvance();
Token leftParen = _expect(TokenType.OPEN_PAREN);
Expression expression = parseExpression2();
- if (expression is AssignmentExpression) {
- _reportErrorForNode(
- ParserErrorCode.ASSERT_DOES_NOT_TAKE_ASSIGNMENT, expression);
- } else if (expression is CascadeExpression) {
- _reportErrorForNode(
- ParserErrorCode.ASSERT_DOES_NOT_TAKE_CASCADE, expression);
- } else if (expression is ThrowExpression) {
- _reportErrorForNode(
- ParserErrorCode.ASSERT_DOES_NOT_TAKE_THROW, expression);
- } else if (expression is RethrowExpression) {
- _reportErrorForNode(
- ParserErrorCode.ASSERT_DOES_NOT_TAKE_RETHROW, expression);
- }
Token comma;
Expression message;
if (_matches(TokenType.COMMA)) {
@@ -5062,16 +5049,52 @@
newKeyword = firstToken;
firstToken = firstToken.next;
}
- if (_tokenMatchesIdentifier(firstToken)) {
+ if (firstToken.isUserDefinableOperator) {
+ if (firstToken.next.type != TokenType.EOF) {
+ return null;
+ }
+ Identifier identifier = new SimpleIdentifier(firstToken);
+ return new CommentReference(null, identifier);
+ } else if (_tokenMatchesKeyword(firstToken, Keyword.OPERATOR)) {
+ Token secondToken = firstToken.next;
+ if (secondToken.isUserDefinableOperator) {
+ if (secondToken.next.type != TokenType.EOF) {
+ return null;
+ }
+ Identifier identifier = new SimpleIdentifier(secondToken);
+ return new CommentReference(null, identifier);
+ }
+ return null;
+ } else if (_tokenMatchesIdentifier(firstToken)) {
Token secondToken = firstToken.next;
Token thirdToken = secondToken.next;
Token nextToken;
Identifier identifier;
- if (_tokenMatches(secondToken, TokenType.PERIOD) &&
- _tokenMatchesIdentifier(thirdToken)) {
- identifier = new PrefixedIdentifier(new SimpleIdentifier(firstToken),
- secondToken, new SimpleIdentifier(thirdToken));
- nextToken = thirdToken.next;
+ if (_tokenMatches(secondToken, TokenType.PERIOD)) {
+ if (thirdToken.isUserDefinableOperator) {
+ identifier = new PrefixedIdentifier(
+ new SimpleIdentifier(firstToken),
+ secondToken,
+ new SimpleIdentifier(thirdToken));
+ nextToken = thirdToken.next;
+ } else if (_tokenMatchesKeyword(thirdToken, Keyword.OPERATOR)) {
+ Token fourthToken = thirdToken.next;
+ if (fourthToken.isUserDefinableOperator) {
+ identifier = new PrefixedIdentifier(
+ new SimpleIdentifier(firstToken),
+ secondToken,
+ new SimpleIdentifier(fourthToken));
+ nextToken = fourthToken.next;
+ } else {
+ return null;
+ }
+ } else if (_tokenMatchesIdentifier(thirdToken)) {
+ identifier = new PrefixedIdentifier(
+ new SimpleIdentifier(firstToken),
+ secondToken,
+ new SimpleIdentifier(thirdToken));
+ nextToken = thirdToken.next;
+ }
} else {
identifier = new SimpleIdentifier(firstToken);
nextToken = firstToken.next;
@@ -9896,22 +9919,6 @@
const ParserErrorCode('ANNOTATION_ON_ENUM_CONSTANT',
"Enum constants cannot have annotations");
- static const ParserErrorCode ASSERT_DOES_NOT_TAKE_ASSIGNMENT =
- const ParserErrorCode('ASSERT_DOES_NOT_TAKE_ASSIGNMENT',
- "Assert cannot be called on an assignment");
-
- static const ParserErrorCode ASSERT_DOES_NOT_TAKE_CASCADE =
- const ParserErrorCode(
- 'ASSERT_DOES_NOT_TAKE_CASCADE', "Assert cannot be called on cascade");
-
- static const ParserErrorCode ASSERT_DOES_NOT_TAKE_THROW =
- const ParserErrorCode(
- 'ASSERT_DOES_NOT_TAKE_THROW', "Assert cannot be called on throws");
-
- static const ParserErrorCode ASSERT_DOES_NOT_TAKE_RETHROW =
- const ParserErrorCode('ASSERT_DOES_NOT_TAKE_RETHROW',
- "Assert cannot be called on rethrows");
-
/**
* 16.32 Identifier Reference: It is a compile-time error if any of the
* identifiers async, await, or yield is used as an identifier in a function
diff --git a/pkg/analyzer/lib/src/generated/resolver.dart b/pkg/analyzer/lib/src/generated/resolver.dart
index 15c41d6..b662891 100644
--- a/pkg/analyzer/lib/src/generated/resolver.dart
+++ b/pkg/analyzer/lib/src/generated/resolver.dart
@@ -4655,7 +4655,9 @@
for (Combinator combinator in importDirective.combinators) {
if (combinator is ShowCombinator) {
for (SimpleIdentifier name in combinator.shownNames) {
- identifiers.add(name);
+ if (name.staticElement != null) {
+ identifiers.add(name);
+ }
}
}
}
@@ -5141,7 +5143,7 @@
* Instances of the class `OverrideVerifier` visit all of the declarations in a compilation
* unit to verify that if they have an override annotation it is being used correctly.
*/
-class OverrideVerifier extends RecursiveAstVisitor<Object> {
+class OverrideVerifier extends RecursiveAstVisitor {
/**
* The error reporter used to report errors.
*/
@@ -5161,7 +5163,23 @@
OverrideVerifier(this._errorReporter, this._manager);
@override
- Object visitMethodDeclaration(MethodDeclaration node) {
+ visitFieldDeclaration(FieldDeclaration node) {
+ for (VariableDeclaration field in node.fields.variables) {
+ VariableElement fieldElement = field.element;
+ if (fieldElement is FieldElement && _isOverride(fieldElement)) {
+ PropertyAccessorElement getter = fieldElement.getter;
+ PropertyAccessorElement setter = fieldElement.setter;
+ if (!(getter != null && _getOverriddenMember(getter) != null ||
+ setter != null && _getOverriddenMember(setter) != null)) {
+ _errorReporter.reportErrorForNode(
+ HintCode.OVERRIDE_ON_NON_OVERRIDING_FIELD, field.name);
+ }
+ }
+ }
+ }
+
+ @override
+ visitMethodDeclaration(MethodDeclaration node) {
ExecutableElement element = node.element;
if (_isOverride(element)) {
if (_getOverriddenMember(element) == null) {
@@ -5179,7 +5197,6 @@
}
}
}
- return super.visitMethodDeclaration(node);
}
/**
@@ -5658,6 +5675,11 @@
FunctionBody _currentFunctionBody;
/**
+ * Are we running in strong mode or not.
+ */
+ bool strongMode;
+
+ /**
* Initialize a newly created visitor to resolve the nodes in an AST node.
*
* The [definingLibrary] is the element for the library containing the node
@@ -5679,10 +5701,11 @@
{Scope nameScope})
: super(definingLibrary, source, typeProvider, errorListener,
nameScope: nameScope) {
+ AnalysisOptions options = definingLibrary.context.analysisOptions;
+ this.strongMode = options.strongMode;
this.elementResolver = new ElementResolver(this);
this.typeSystem = definingLibrary.context.typeSystem;
bool strongModeHints = false;
- AnalysisOptions options = definingLibrary.context.analysisOptions;
if (options is AnalysisOptionsImpl) {
strongModeHints = options.strongModeHints;
}
@@ -6621,7 +6644,6 @@
Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
node.function?.accept(this);
node.accept(elementResolver);
- _inferFunctionExpressionsParametersTypes(node.argumentList);
_inferArgumentTypesFromContext(node);
node.argumentList?.accept(this);
node.accept(typeAnalyzer);
@@ -6723,6 +6745,16 @@
if (contextType is InterfaceType &&
contextType.typeArguments != null &&
contextType.typeArguments.length > 0) {
+ // TODO(jmesserly): for generic methods we use the
+ // StrongTypeSystemImpl.inferGenericFunctionCall, which appears to
+ // be a tad more powerful than matchTypes.
+ //
+ // For example it can infer this case:
+ //
+ // class E<S, T> extends A<C<S>, T> { ... }
+ // A<C<int>, String> a0 = /*infer<int, String>*/new E("hello");
+ //
+ // See _inferArgumentTypesFromContext in this file for use of it.
List<DartType> targs =
inferenceContext.matchTypes(classTypeName.type, contextType);
if (targs != null && targs.any((t) => !t.isDynamic)) {
@@ -6838,7 +6870,6 @@
node.target?.accept(this);
node.typeArguments?.accept(this);
node.accept(elementResolver);
- _inferFunctionExpressionsParametersTypes(node.argumentList);
_inferArgumentTypesFromContext(node);
node.argumentList?.accept(this);
node.accept(typeAnalyzer);
@@ -7201,6 +7232,12 @@
}
void _inferArgumentTypesFromContext(InvocationExpression node) {
+ if (!strongMode) {
+ // Use propagated type inference for lambdas if not in strong mode.
+ _inferFunctionExpressionsParametersTypes(node.argumentList);
+ return;
+ }
+
DartType contextType = node.staticInvokeType;
if (contextType is FunctionType) {
DartType originalType = node.function.staticType;
@@ -10144,6 +10181,20 @@
}
@override
+ Object visitFunctionExpression(FunctionExpression node) {
+ // Clear the static element return type of closures.
+ // We need this to restore the state when closure parameter types can
+ // be propagated from invocation parameter types.
+ if (node is! FunctionDeclaration) {
+ ExecutableElement element = node.element;
+ if (element is FunctionElementImpl) {
+ element.returnType = null;
+ }
+ }
+ return super.visitFunctionExpression(node);
+ }
+
+ @override
Object visitFunctionTypeAlias(FunctionTypeAlias node) {
FunctionTypeAliasElementImpl element =
node.element as FunctionTypeAliasElementImpl;
diff --git a/pkg/analyzer/lib/src/generated/sdk_io.dart b/pkg/analyzer/lib/src/generated/sdk_io.dart
index be7c27a..50cb9d0 100644
--- a/pkg/analyzer/lib/src/generated/sdk_io.dart
+++ b/pkg/analyzer/lib/src/generated/sdk_io.dart
@@ -108,6 +108,20 @@
_useSummary = use;
}
+ /**
+ * Add the extensions from one or more sdk extension files to this sdk. The
+ * [extensions] should be a table mapping the names of extensions to the paths
+ * where those extensions can be found.
+ */
+ void addExtensions(Map<String, String> extensions) {
+ extensions.forEach((String uri, String path) {
+ String shortName = uri.substring(uri.indexOf(':') + 1);
+ SdkLibraryImpl library = new SdkLibraryImpl(shortName);
+ library.path = path;
+ libraryMap.setLibrary(uri, library);
+ });
+ }
+
@override
Source fromFileUri(Uri uri) {
JavaFile file = new JavaFile.fromUri(uri);
diff --git a/pkg/analyzer/lib/src/generated/source.dart b/pkg/analyzer/lib/src/generated/source.dart
index 6412de3..bdaf9d9 100644
--- a/pkg/analyzer/lib/src/generated/source.dart
+++ b/pkg/analyzer/lib/src/generated/source.dart
@@ -265,7 +265,8 @@
*/
int getOffsetOfLine(int lineNumber) {
if (lineNumber < 0 || lineNumber >= lineCount) {
- throw new ArgumentError('Invalid line number: $lineNumber');
+ throw new ArgumentError(
+ 'Invalid line number: $lineNumber; must be between 0 and ${lineCount - 1}');
}
return _lineStarts[lineNumber];
}
diff --git a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
index 5c57bb8..19019da 100644
--- a/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
+++ b/pkg/analyzer/lib/src/generated/static_type_analyzer.dart
@@ -12,6 +12,7 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/element/element.dart';
+import 'package:analyzer/src/dart/element/member.dart' show ConstructorMember;
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/resolver.dart';
@@ -92,7 +93,7 @@
_dynamicType = _typeProvider.dynamicType;
_overrideManager = _resolver.overrideManager;
_promoteManager = _resolver.promoteManager;
- _strongMode = _resolver.definingLibrary.context.analysisOptions.strongMode;
+ _strongMode = _resolver.strongMode;
}
/**
@@ -257,13 +258,23 @@
} else {
ExecutableElement staticMethodElement = node.staticElement;
DartType staticType = _computeStaticReturnType(staticMethodElement);
- staticType =
- _refineAssignmentExpressionType(node, staticType, _getStaticType);
+ staticType = _typeSystem.refineBinaryExpressionType(
+ _typeProvider,
+ node.leftHandSide.staticType,
+ operator,
+ node.rightHandSide.staticType,
+ staticType);
_recordStaticType(node, staticType);
MethodElement propagatedMethodElement = node.propagatedElement;
if (!identical(propagatedMethodElement, staticMethodElement)) {
DartType propagatedType =
_computeStaticReturnType(propagatedMethodElement);
+ propagatedType = _typeSystem.refineBinaryExpressionType(
+ _typeProvider,
+ node.leftHandSide.propagatedType,
+ operator,
+ node.rightHandSide.propagatedType,
+ propagatedType);
_resolver.recordPropagatedTypeIfBetter(node, propagatedType);
}
}
@@ -521,7 +532,7 @@
@override
Object visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
if (_strongMode) {
- _inferGenericInvoke(node);
+ _inferGenericInvocationExpression(node);
}
DartType staticType = _computeInvokeReturnType(node.staticInvokeType);
_recordStaticType(node, staticType);
@@ -574,6 +585,10 @@
*/
@override
Object visitInstanceCreationExpression(InstanceCreationExpression node) {
+ if (_strongMode) {
+ _inferInstanceCreationExpression(node);
+ }
+
_recordStaticType(node, node.constructorName.type.type);
ConstructorElement element = node.staticElement;
if (element != null && "Element" == element.enclosingElement.name) {
@@ -812,7 +827,7 @@
SimpleIdentifier methodNameNode = node.methodName;
Element staticMethodElement = methodNameNode.staticElement;
if (_strongMode) {
- _inferGenericInvoke(node);
+ _inferGenericInvocationExpression(node);
}
// Record types of the variable invoked as a function.
if (staticMethodElement is VariableElement) {
@@ -1605,6 +1620,33 @@
return returnType.type;
}
+ /**
+ * Given a constructor for a generic type, returns the equivalent generic
+ * function type that we could use to forward to the constructor, or for a
+ * non-generic type simply returns the constructor type.
+ *
+ * For example given the type `class C<T> { C(T arg); }`, the generic function
+ * type is `<T>(T) -> C<T>`.
+ */
+ FunctionType _constructorToGenericFunctionType(
+ ConstructorElement constructor) {
+ // TODO(jmesserly): it may be worth making this available from the
+ // constructor. It's nice if our inference code can operate uniformly on
+ // function types.
+ ClassElement cls = constructor.enclosingElement;
+ FunctionType type = constructor.type;
+ if (cls.typeParameters.isEmpty) {
+ return type;
+ }
+
+ FunctionElementImpl function = new FunctionElementImpl("", -1);
+ function.synthetic = true;
+ function.returnType = type.returnType;
+ function.shareTypeParameters(cls.typeParameters);
+ function.shareParameters(type.parameters);
+ return function.type = new FunctionTypeImpl(function);
+ }
+
DartType _findIteratedType(DartType type, DartType targetType) {
// TODO(vsm): Use leafp's matchType here?
// Set by _find if match is found
@@ -1864,8 +1906,8 @@
}
/**
- * Given an uninstantiated generic type, try to infer the instantiated generic
- * type from the surrounding context.
+ * Given an uninstantiated generic function type, try to infer the
+ * instantiated generic function type from the surrounding context.
*/
DartType _inferGenericInstantiationFromContext(
DartType context, DartType type) {
@@ -1878,14 +1920,40 @@
return type;
}
- bool _inferGenericInvoke(InvocationExpression node) {
+ /**
+ * Given a possibly generic invocation like `o.m(args)` or `(f)(args)` try to
+ * infer the instantiated generic function type.
+ *
+ * This takes into account both the context type, as well as information from
+ * the argument types.
+ */
+ void _inferGenericInvocationExpression(InvocationExpression node) {
+ ArgumentList arguments = node.argumentList;
+ FunctionType inferred = _inferGenericInvoke(
+ node, node.function.staticType, node.typeArguments, arguments);
+ if (inferred != null && inferred != node.staticInvokeType) {
+ // Fix up the parameter elements based on inferred method.
+ arguments.correspondingStaticParameters = ResolverVisitor
+ .resolveArgumentsToParameters(arguments, inferred.parameters, null);
+ node.staticInvokeType = inferred;
+ }
+ }
+
+ /**
+ * Given a possibly generic invocation or instance creation, such as
+ * `o.m(args)` or `(f)(args)` or `new T(args)` try to infer the instantiated
+ * generic function type.
+ *
+ * This takes into account both the context type, as well as information from
+ * the argument types.
+ */
+ FunctionType _inferGenericInvoke(Expression node, DartType fnType,
+ TypeArgumentList typeArguments, ArgumentList argumentList) {
TypeSystem ts = _typeSystem;
- DartType fnType = node.function.staticType;
- if (node.typeArguments == null &&
+ if (typeArguments == null &&
fnType is FunctionType &&
fnType.typeFormals.isNotEmpty &&
ts is StrongTypeSystemImpl) {
- ArgumentList argumentList = node.argumentList;
// Get the parameters that correspond to the uninstantiated generic.
List<ParameterElement> rawParameters = ResolverVisitor
.resolveArgumentsToParameters(argumentList, fnType.parameters, null);
@@ -1900,20 +1968,48 @@
}
}
- FunctionType inferred = ts.inferGenericFunctionCall(_typeProvider, fnType,
- paramTypes, argTypes, InferenceContext.getType(node));
-
- if (inferred != node.staticInvokeType) {
- // Fix up the parameter elements based on inferred method.
- List<ParameterElement> inferredParameters =
- ResolverVisitor.resolveArgumentsToParameters(
- argumentList, inferred.parameters, null);
- argumentList.correspondingStaticParameters = inferredParameters;
- node.staticInvokeType = inferred;
- return true;
- }
+ return ts.inferGenericFunctionCall(_typeProvider, fnType, paramTypes,
+ argTypes, InferenceContext.getType(node));
}
- return false;
+ return null;
+ }
+
+ /**
+ * Given an instance creation of a possibly generic type, infer the type
+ * arguments using the current context type as well as the argument types.
+ */
+ void _inferInstanceCreationExpression(InstanceCreationExpression node) {
+ ConstructorName constructor = node.constructorName;
+ ConstructorElement originalElement = constructor.staticElement;
+ // If the constructor is generic, we'll have a ConstructorMember that
+ // substitutes in type arguments (possibly `dynamic`) from earlier in
+ // resolution.
+ //
+ // Otherwise we'll have a ConstructorElement, and we can skip inference
+ // because there's nothing to infer in a non-generic type.
+ if (originalElement is! ConstructorMember) {
+ return;
+ }
+
+ // Get back to the uninstantiated generic constructor.
+ // TODO(jmesserly): should we store this earlier in resolution?
+ // Or look it up, instead of jumping backwards through the Member?
+ var rawElement = (originalElement as ConstructorMember).baseElement;
+
+ FunctionType constructorType =
+ _constructorToGenericFunctionType(rawElement);
+
+ ArgumentList arguments = node.argumentList;
+ FunctionType inferred = _inferGenericInvoke(
+ node, constructorType, constructor.type.typeArguments, arguments);
+
+ if (inferred != null && inferred != originalElement.type) {
+ // Fix up the parameter elements based on inferred method.
+ arguments.correspondingStaticParameters = ResolverVisitor
+ .resolveArgumentsToParameters(arguments, inferred.parameters, null);
+ inferConstructorName(constructor, inferred.returnType);
+ // TODO(jmesserly): should we fix up the staticElement as well?
+ }
}
/**
@@ -2146,44 +2242,6 @@
}
/**
- * Attempts to make a better guess for the type of the given assignment
- * [expression], given that resolution has so far produced the [currentType].
- * The [typeAccessor] is used to access the corresponding type of the left
- * and right operands.
- */
- DartType _refineAssignmentExpressionType(AssignmentExpression expression,
- DartType currentType, DartType typeAccessor(Expression node)) {
- Expression leftHandSize = expression.leftHandSide;
- Expression rightHandSide = expression.rightHandSide;
- TokenType operator = expression.operator.type;
- DartType intType = _typeProvider.intType;
- if (typeAccessor(leftHandSize) == intType) {
- // int op= double
- if (operator == TokenType.MINUS_EQ ||
- operator == TokenType.PERCENT_EQ ||
- operator == TokenType.PLUS_EQ ||
- operator == TokenType.STAR_EQ) {
- DartType doubleType = _typeProvider.doubleType;
- if (typeAccessor(rightHandSide) == doubleType) {
- return doubleType;
- }
- }
- // int op= int
- if (operator == TokenType.MINUS_EQ ||
- operator == TokenType.PERCENT_EQ ||
- operator == TokenType.PLUS_EQ ||
- operator == TokenType.STAR_EQ ||
- operator == TokenType.TILDE_SLASH_EQ) {
- if (typeAccessor(rightHandSide) == intType) {
- return intType;
- }
- }
- }
- // default
- return currentType;
- }
-
- /**
* Create a table mapping HTML tag names to the names of the classes (in 'dart:html') that
* implement those tags.
*
diff --git a/pkg/analyzer/lib/src/generated/type_system.dart b/pkg/analyzer/lib/src/generated/type_system.dart
index 74e3fd2..f7efd79 100644
--- a/pkg/analyzer/lib/src/generated/type_system.dart
+++ b/pkg/analyzer/lib/src/generated/type_system.dart
@@ -167,8 +167,7 @@
}
// Try to infer and instantiate the resulting type.
- var resultType =
- inferringTypeSystem._infer(fnType, allowPartialSolution: false);
+ var resultType = inferringTypeSystem._infer(fnType);
// If the instantiation failed (because some type variable constraints
// could not be solved, in other words, we could not find a valid subtype),
@@ -240,14 +239,7 @@
argumentTypes[i], correspondingParameterTypes[i]);
}
- // We are okay inferring some type variables and not others.
- //
- // This lets our return type be as precise as possible, which will help
- // make any type information resulting from it more precise.
- //
- // This is simply a heuristic: the code is incorrect, and we'll issue an
- // error on this call, to indicate that types don't match.
- return inferringTypeSystem._infer(fnType, allowPartialSolution: true);
+ return inferringTypeSystem._infer(fnType);
}
/**
@@ -1282,7 +1274,7 @@
/// Given the constraints that were given by calling [isSubtypeOf], find the
/// instantiation of the generic function that satisfies these constraints.
- FunctionType _infer(FunctionType fnType, {bool allowPartialSolution: false}) {
+ FunctionType _infer(FunctionType fnType) {
List<TypeParameterType> fnTypeParams =
TypeParameterTypeImpl.getTypes(fnType.typeFormals);
@@ -1335,16 +1327,8 @@
bound.upper.substitute2(inferredTypes, fnTypeParams)) ||
!isSubtypeOf(bound.lower.substitute2(inferredTypes, fnTypeParams),
inferredTypes[i])) {
- // Unless a partial solution was requested, bail.
- if (!allowPartialSolution) {
- return null;
- }
-
- inferredTypes[i] = DynamicTypeImpl.instance;
- if (typeParam.element.bound != null) {
- inferredTypes[i] =
- typeParam.element.bound.substitute2(inferredTypes, fnTypeParams);
- }
+ // Inference failed. Bail.
+ return null;
}
}
diff --git a/pkg/analyzer/lib/src/summary/link.dart b/pkg/analyzer/lib/src/summary/link.dart
index 57dccf1..08cbde1 100644
--- a/pkg/analyzer/lib/src/summary/link.dart
+++ b/pkg/analyzer/lib/src/summary/link.dart
@@ -593,6 +593,9 @@
}
@override
+ int get version => 0;
+
+ @override
DartType buildType(
DartType getTypeArgument(int i), List<int> implicitFunctionTypeIndices) {
int numTypeParameters = _unlinkedClass.typeParameters.length;
diff --git a/pkg/analyzer/lib/src/summary/summary_sdk.dart b/pkg/analyzer/lib/src/summary/summary_sdk.dart
index 987a187..1ac305e 100644
--- a/pkg/analyzer/lib/src/summary/summary_sdk.dart
+++ b/pkg/analyzer/lib/src/summary/summary_sdk.dart
@@ -20,6 +20,7 @@
import 'package:analyzer/src/summary/resynthesize.dart';
import 'package:analyzer/src/task/dart.dart';
import 'package:analyzer/task/model.dart' show ResultDescriptor, TargetedResult;
+import 'package:analyzer/file_system/file_system.dart' show ResourceProvider;
class SdkSummaryResultProvider extends ResynthesizerResultProvider {
final SummaryTypeProvider typeProvider = new SummaryTypeProvider();
@@ -106,6 +107,7 @@
SummaryDataStore _dataStore;
InSummaryPackageUriResolver _uriResolver;
PackageBundle _bundle;
+ ResourceProvider resourceProvider;
/**
* The [AnalysisContext] which is used for all of the sources in this sdk.
@@ -118,6 +120,14 @@
_bundle = _dataStore.bundles.single;
}
+ SummaryBasedDartSdk.fromBundle(
+ this.strongMode, PackageBundle bundle, this.resourceProvider) {
+ _dataStore = new SummaryDataStore([]);
+ _dataStore.addBundle('dart_sdk.sum', bundle);
+ _uriResolver = new InSummaryPackageUriResolver(_dataStore);
+ _bundle = bundle;
+ }
+
/**
* Return the [PackageBundle] for this SDK, not `null`.
*/
@@ -129,7 +139,8 @@
AnalysisOptionsImpl analysisOptions = new AnalysisOptionsImpl()
..strongMode = strongMode;
_analysisContext = new SdkAnalysisContext(analysisOptions);
- SourceFactory factory = new SourceFactory([new DartUriResolver(this)]);
+ SourceFactory factory = new SourceFactory(
+ [new DartUriResolver(this)], null, resourceProvider);
_analysisContext.sourceFactory = factory;
_analysisContext.resultProvider =
new SdkSummaryResultProvider(_analysisContext, _bundle, strongMode);
diff --git a/pkg/analyzer/lib/src/task/dart.dart b/pkg/analyzer/lib/src/task/dart.dart
index 25e74ec..6860903 100644
--- a/pkg/analyzer/lib/src/task/dart.dart
+++ b/pkg/analyzer/lib/src/task/dart.dart
@@ -327,6 +327,33 @@
new ResultDescriptor<bool>('CREATED_RESOLVED_UNIT9', false);
/**
+ * All [AnalysisError]s results for [Source]s.
+ */
+final List<ListResultDescriptor<AnalysisError>> ERROR_SOURCE_RESULTS =
+ <ListResultDescriptor<AnalysisError>>[
+ BUILD_DIRECTIVES_ERRORS,
+ BUILD_LIBRARY_ERRORS,
+ PARSE_ERRORS,
+ SCAN_ERRORS,
+];
+
+/**
+ * All [AnalysisError]s results in for [LibrarySpecificUnit]s.
+ */
+final List<ListResultDescriptor<AnalysisError>> ERROR_UNIT_RESULTS =
+ <ListResultDescriptor<AnalysisError>>[
+ HINTS,
+ LIBRARY_UNIT_ERRORS,
+ LINTS,
+ RESOLVE_TYPE_BOUNDS_ERRORS,
+ RESOLVE_TYPE_NAMES_ERRORS,
+ RESOLVE_UNIT_ERRORS,
+ STRONG_MODE_ERRORS,
+ VARIABLE_REFERENCE_ERRORS,
+ VERIFY_ERRORS
+];
+
+/**
* The sources representing the export closure of a library.
* The [Source]s include only library sources, not their units.
*
@@ -1075,12 +1102,10 @@
//
// Prepare constants.
//
- ConstantFinder constantFinder =
- new ConstantFinder(context, source, librarySpecificUnit.library);
+ ConstantFinder constantFinder = new ConstantFinder();
unit.accept(constantFinder);
List<ConstantEvaluationTarget> constants =
- new List<ConstantEvaluationTarget>.from(
- constantFinder.constantsToCompute);
+ constantFinder.constantsToCompute.toList();
//
// Record outputs.
//
@@ -1450,8 +1475,7 @@
'BuildLibraryElementTask', createTask, buildInputs, <ResultDescriptor>[
BUILD_LIBRARY_ERRORS,
LIBRARY_ELEMENT1,
- IS_LAUNCHABLE,
- REFERENCED_NAMES
+ IS_LAUNCHABLE
]);
/**
@@ -1623,19 +1647,12 @@
Directive directive = directivesToResolve[i];
directive.element = libraryElement;
}
- // Compute referenced names.
- ReferencedNames referencedNames = new ReferencedNames(librarySource);
- new ReferencedNamesBuilder(referencedNames).build(definingCompilationUnit);
- for (CompilationUnit partUnit in partUnits) {
- new ReferencedNamesBuilder(referencedNames).build(partUnit);
- }
//
// Record outputs.
//
outputs[BUILD_LIBRARY_ERRORS] = errors;
outputs[LIBRARY_ELEMENT1] = libraryElement;
outputs[IS_LAUNCHABLE] = entryPoint != null;
- outputs[REFERENCED_NAMES] = referencedNames;
}
/**
@@ -2484,8 +2501,6 @@
* The description for a change in a Dart source.
*/
class DartDelta extends Delta {
- bool hasDirectiveChange = false;
-
final Set<String> changedNames = new Set<String>();
final Map<Source, Set<String>> changedPrivateNames = <Source, Set<String>>{};
@@ -2495,23 +2510,36 @@
/**
* The cache of libraries in which all results are invalid.
*/
- final Set<Source> librariesWithInvalidResults = new Set<Source>();
+ final Set<Source> librariesWithAllInvalidResults = new Set<Source>();
/**
* The cache of libraries in which all results are valid.
*/
- final Set<Source> librariesWithValidResults = new Set<Source>();
+ final Set<Source> librariesWithAllValidResults = new Set<Source>();
+
+ /**
+ * The cache of libraries with all, but [HINTS] and [VERIFY_ERRORS] results
+ * are valid.
+ */
+ final Set<Source> libraryWithInvalidErrors = new Set<Source>();
+
+ /**
+ * This set is cleared in every [gatherEnd], and [gatherChanges] uses it
+ * to find changes in every source only once per visit process.
+ */
+ final Set<Source> currentVisitUnits = new Set<Source>();
DartDelta(Source source) : super(source);
/**
* Add names that are changed in the given [references].
+ * Return `true` if any change was added.
*/
- void addChangedElements(ReferencedNames references) {
- Source refLibrary = references.librarySource;
- bool hasProgress = true;
- while (hasProgress) {
- hasProgress = false;
+ bool addChangedElements(ReferencedNames references, Source refLibrary) {
+ int numberOfChanges = 0;
+ int lastNumberOfChange = -1;
+ while (numberOfChanges != lastNumberOfChange) {
+ lastNumberOfChange = numberOfChanges;
// Classes that extend changed classes are also changed.
// If there is a delta for a superclass, use it for the subclass.
// Otherwise mark the subclass as "general name change".
@@ -2524,13 +2552,13 @@
_log(() => '$subName in $refLibrary has delta because of its '
'superclass $superName has delta');
if (subDelta.superDeltas.add(superDelta)) {
- hasProgress = true;
+ numberOfChanges++;
}
} else if (isChanged(refLibrary, superName)) {
if (nameChanged(refLibrary, subName)) {
_log(() => '$subName in $refLibrary is changed because its '
'superclass $superName is changed');
- hasProgress = true;
+ numberOfChanges++;
}
}
}
@@ -2545,12 +2573,13 @@
if (nameChanged(refLibrary, user)) {
_log(() => '$user in $refLibrary is changed because '
'of $dependency in $dependencies');
- hasProgress = true;
+ numberOfChanges++;
}
}
}
});
}
+ return numberOfChanges != 0;
}
void classChanged(ClassElementDelta classDelta) {
@@ -2562,23 +2591,52 @@
nameChanged(librarySource, element.name);
}
- bool hasAffectedReferences(ReferencedNames references) {
- Source refLibrary = references.librarySource;
- // Verify errors must be recomputed when a superclass changes.
+ @override
+ bool gatherChanges(InternalAnalysisContext context, AnalysisTarget target,
+ ResultDescriptor descriptor, Object value) {
+ // Prepare target source.
+ Source targetUnit = target.source;
+ Source targetLibrary = target.librarySource;
+ if (target is Source) {
+ if (context.getKindOf(target) == SourceKind.LIBRARY) {
+ targetLibrary = target;
+ }
+ }
+ // We don't know what to do with the given target.
+ if (targetUnit == null || targetUnit != targetLibrary) {
+ return false;
+ }
+ // Attempt to find new changed names for the unit only once.
+ if (!currentVisitUnits.add(targetUnit)) {
+ return false;
+ }
+ // Add changes.
+ ReferencedNames referencedNames =
+ context.getResult(targetUnit, REFERENCED_NAMES);
+ if (referencedNames == null) {
+ return false;
+ }
+ return addChangedElements(referencedNames, targetLibrary);
+ }
+
+ @override
+ void gatherEnd() {
+ currentVisitUnits.clear();
+ }
+
+ bool hasAffectedHintsVerifyErrors(
+ ReferencedNames references, Source refLibrary) {
for (String superName in references.superToSubs.keys) {
if (isChangedOrClass(refLibrary, superName)) {
- _log(() => '$refLibrary is affected because '
+ _log(() => '$refLibrary hints/verify errors are affected because '
'${references.superToSubs[superName]} subclasses $superName');
return true;
}
}
- // Verify errors must be recomputed when an instantiated class changes.
- for (String name in references.instantiatedNames) {
- if (isChangedOrClass(refLibrary, name)) {
- _log(() => '$refLibrary is affected because $name is instantiated');
- return true;
- }
- }
+ return false;
+ }
+
+ bool hasAffectedReferences(ReferencedNames references, Source refLibrary) {
// Resolution must be performed when a referenced element changes.
for (String name in references.names) {
if (isChangedOrClassMember(refLibrary, name)) {
@@ -2586,6 +2644,18 @@
return true;
}
}
+ // Resolution must be performed when the unnamed constructor of
+ // an instantiated class is added/changed/removed.
+ // TODO(scheglov) Use only instantiations with default constructor.
+ for (String name in references.instantiatedNames) {
+ for (ClassElementDelta classDelta in changedClasses.values) {
+ if (classDelta.name == name && classDelta.hasUnnamedConstructorChange) {
+ _log(() =>
+ '$refLibrary is affected by the default constructor of $name');
+ return true;
+ }
+ }
+ }
return false;
}
@@ -2647,23 +2717,23 @@
@override
DeltaResult validate(InternalAnalysisContext context, AnalysisTarget target,
ResultDescriptor descriptor, Object value) {
- if (hasDirectiveChange) {
- return DeltaResult.INVALIDATE;
- }
// Prepare target source.
- Source targetSource = target.source;
- Source librarySource = target.librarySource;
+ Source targetUnit = target.source;
+ Source targetLibrary = target.librarySource;
if (target is Source) {
if (context.getKindOf(target) == SourceKind.LIBRARY) {
- librarySource = target;
+ targetLibrary = target;
}
}
// We don't know what to do with the given target, invalidate it.
- if (targetSource == null) {
+ if (targetUnit == null || targetUnit != targetLibrary) {
return DeltaResult.INVALIDATE;
}
// Keep results that don't change: any library.
- if (_isTaskResult(BuildLibraryElementTask.DESCRIPTOR, descriptor) ||
+ if (_isTaskResult(ScanDartTask.DESCRIPTOR, descriptor) ||
+ _isTaskResult(ParseDartTask.DESCRIPTOR, descriptor) ||
+ _isTaskResult(BuildCompilationUnitElementTask.DESCRIPTOR, descriptor) ||
+ _isTaskResult(BuildLibraryElementTask.DESCRIPTOR, descriptor) ||
_isTaskResult(BuildDirectiveElementsTask.DESCRIPTOR, descriptor) ||
_isTaskResult(ResolveDirectiveElementsTask.DESCRIPTOR, descriptor) ||
_isTaskResult(BuildEnumMemberElementsTask.DESCRIPTOR, descriptor) ||
@@ -2673,43 +2743,47 @@
return DeltaResult.KEEP_CONTINUE;
}
// Keep results that don't change: changed library.
- if (targetSource == source) {
- if (_isTaskResult(ScanDartTask.DESCRIPTOR, descriptor) ||
- _isTaskResult(ParseDartTask.DESCRIPTOR, descriptor) ||
- _isTaskResult(
- BuildCompilationUnitElementTask.DESCRIPTOR, descriptor) ||
- _isTaskResult(BuildLibraryElementTask.DESCRIPTOR, descriptor)) {
- return DeltaResult.KEEP_CONTINUE;
- }
+ if (targetUnit == source) {
return DeltaResult.INVALIDATE;
}
// Keep results that don't change: dependent library.
- if (targetSource != source) {
+ if (targetUnit != source) {
if (_isTaskResult(BuildPublicNamespaceTask.DESCRIPTOR, descriptor)) {
return DeltaResult.KEEP_CONTINUE;
}
}
// Handle in-library results only for now.
- if (librarySource != null) {
+ if (targetLibrary != null) {
// Use cached library results.
- if (librariesWithInvalidResults.contains(librarySource)) {
+ if (librariesWithAllInvalidResults.contains(targetLibrary)) {
return DeltaResult.INVALIDATE;
}
- if (librariesWithValidResults.contains(librarySource)) {
+ if (librariesWithAllValidResults.contains(targetLibrary)) {
return DeltaResult.STOP;
}
+ // The library is almost, but not completely valid.
+ // Some error results are invalid.
+ if (libraryWithInvalidErrors.contains(targetLibrary)) {
+ if (descriptor == HINTS || descriptor == VERIFY_ERRORS) {
+ return DeltaResult.INVALIDATE_NO_DELTA;
+ }
+ return DeltaResult.KEEP_CONTINUE;
+ }
// Compute the library result.
ReferencedNames referencedNames =
- context.getResult(librarySource, REFERENCED_NAMES);
+ context.getResult(targetUnit, REFERENCED_NAMES);
if (referencedNames == null) {
return DeltaResult.INVALIDATE_NO_DELTA;
}
- addChangedElements(referencedNames);
- if (hasAffectedReferences(referencedNames)) {
- librariesWithInvalidResults.add(librarySource);
+ if (hasAffectedReferences(referencedNames, targetLibrary)) {
+ librariesWithAllInvalidResults.add(targetLibrary);
return DeltaResult.INVALIDATE;
}
- librariesWithValidResults.add(librarySource);
+ if (hasAffectedHintsVerifyErrors(referencedNames, targetLibrary)) {
+ libraryWithInvalidErrors.add(targetLibrary);
+ return DeltaResult.KEEP_CONTINUE;
+ }
+ librariesWithAllValidResults.add(targetLibrary);
return DeltaResult.STOP;
}
// We don't know what to do with the given target, invalidate it.
@@ -3943,9 +4017,10 @@
LIBRARY_SPECIFIC_UNITS,
PARSE_ERRORS,
PARSED_UNIT,
+ REFERENCED_NAMES,
+ REFERENCED_SOURCES,
SOURCE_KIND,
UNITS,
- REFERENCED_SOURCES
]);
/**
@@ -4034,6 +4109,11 @@
sourceKind = SourceKind.PART;
}
//
+ // Compute referenced names.
+ //
+ ReferencedNames referencedNames = new ReferencedNames(source);
+ new ReferencedNamesBuilder(referencedNames).build(unit);
+ //
// Record outputs.
//
List<Source> explicitlyImportedSources =
@@ -4057,9 +4137,10 @@
outputs[LIBRARY_SPECIFIC_UNITS] = librarySpecificUnits;
outputs[PARSE_ERRORS] = parseErrors;
outputs[PARSED_UNIT] = unit;
+ outputs[REFERENCED_NAMES] = referencedNames;
+ outputs[REFERENCED_SOURCES] = referencedSources;
outputs[SOURCE_KIND] = sourceKind;
outputs[UNITS] = unitSources;
- outputs[REFERENCED_SOURCES] = referencedSources;
}
/**
@@ -4684,11 +4765,11 @@
}
/**
- * Information about a library - which names it uses, which names it defines
- * with their externally visible dependencies.
+ * Information about a Dart [source] - which names it uses, which names it
+ * defines with their externally visible dependencies.
*/
class ReferencedNames {
- final Source librarySource;
+ final Source source;
/**
* The mapping from the name of a class to the set of names of other classes
@@ -4723,7 +4804,7 @@
*/
final Map<String, Set<String>> userToDependsOn = <String, Set<String>>{};
- ReferencedNames(this.librarySource);
+ ReferencedNames(this.source);
void addSubclass(String subName, String superName) {
superToSubs.putIfAbsent(superName, () => new Set<String>()).add(subName);
@@ -5632,6 +5713,8 @@
return <String, TaskInput>{
'importsExportNamespace':
IMPORTED_LIBRARIES.of(unit.library).toMapOf(LIBRARY_ELEMENT4),
+ 'dependOnAllExportedSources':
+ IMPORTED_LIBRARIES.of(unit.library).toMapOf(EXPORT_SOURCE_CLOSURE),
LIBRARY_INPUT: LIBRARY_ELEMENT4.of(unit.library),
UNIT_INPUT: RESOLVED_UNIT3.of(unit),
TYPE_PROVIDER_INPUT: TYPE_PROVIDER.of(AnalysisContextTarget.request)
diff --git a/pkg/analyzer/lib/src/task/dart_work_manager.dart b/pkg/analyzer/lib/src/task/dart_work_manager.dart
index 3d6dc33..6b2a96e 100644
--- a/pkg/analyzer/lib/src/task/dart_work_manager.dart
+++ b/pkg/analyzer/lib/src/task/dart_work_manager.dart
@@ -117,7 +117,10 @@
void applyChange(List<Source> addedSources, List<Source> changedSources,
List<Source> removedSources) {
addedSources = addedSources.where(_isDartSource).toList();
- changedSources = changedSources.where(_isDartSource).toList();
+ changedSources = changedSources
+ .where(_isDartSource)
+ .where((source) => _needsComputing(source, SOURCE_KIND))
+ .toList();
removedSources = removedSources.where(_isDartSource).toList();
// unknown queue
unknownSourceQueue.addAll(addedSources);
diff --git a/pkg/analyzer/lib/src/task/incremental_element_builder.dart b/pkg/analyzer/lib/src/task/incremental_element_builder.dart
index 9bc30f8..7e5444d 100644
--- a/pkg/analyzer/lib/src/task/incremental_element_builder.dart
+++ b/pkg/analyzer/lib/src/task/incremental_element_builder.dart
@@ -12,10 +12,12 @@
import 'package:analyzer/dart/element/visitor.dart';
import 'package:analyzer/src/dart/ast/token.dart';
import 'package:analyzer/src/dart/ast/utilities.dart';
+import 'package:analyzer/src/dart/constant/utilities.dart';
import 'package:analyzer/src/dart/element/builder.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/generated/resolver.dart';
import 'package:analyzer/src/generated/source.dart';
+import 'package:analyzer/src/task/dart.dart';
/**
* The change of a single [ClassElement].
@@ -34,6 +36,7 @@
final List<ConstructorElement> addedConstructors = <ConstructorElement>[];
final List<ConstructorElement> removedConstructors = <ConstructorElement>[];
+ bool hasUnnamedConstructorChange = false;
final List<MethodElement> addedMethods = <MethodElement>[];
final List<MethodElement> removedMethods = <MethodElement>[];
@@ -99,6 +102,9 @@
final CompilationUnit newUnit;
final ElementHolder unitElementHolder = new ElementHolder();
+ final List<ConstantEvaluationTarget> unitConstants =
+ <ConstantEvaluationTarget>[];
+
/**
* The change between element models of [oldUnit] and [newUnit].
*/
@@ -124,11 +130,14 @@
* Fills [unitDelta] with added/remove elements.
*/
void build() {
+ _materializeLazyElements();
new CompilationUnitBuilder()
.buildCompilationUnit(unitSource, newUnit, librarySource);
+ newUnit.accept(new EnumMemberBuilder(unitElement.context.typeProvider));
_processDirectives();
_processUnitMembers();
_replaceUnitContents(oldUnit, newUnit);
+ _findConstants();
newUnit.element = unitElement;
unitElement.setCodeRange(0, newUnit.endToken.end);
}
@@ -151,11 +160,29 @@
}
}
+ void _findConstants() {
+ ConstantFinder finder = new ConstantFinder();
+ oldUnit.accept(finder);
+ unitConstants.addAll(finder.constantsToCompute);
+ // Update annotation constants to using the old unit element.
+ for (ConstantEvaluationTarget constant in unitConstants) {
+ if (constant is ElementAnnotationImpl) {
+ constant.compilationUnit = unitElement;
+ }
+ }
+ }
+
+ void _materializeLazyElements() {
+ unitElement.accept(new RecursiveElementVisitor());
+ }
+
ClassElementDelta _processClassMembers(
ClassDeclaration oldClass, ClassDeclaration newClass) {
// If the class hierarchy or type parameters are changed,
// then the class changed too much - don't compute the delta.
- if (TokenUtils.getFullCode(newClass.typeParameters) !=
+ if (newClass.abstractKeyword != null && oldClass.abstractKeyword == null ||
+ newClass.abstractKeyword == null && oldClass.abstractKeyword != null ||
+ TokenUtils.getFullCode(newClass.typeParameters) !=
TokenUtils.getFullCode(oldClass.typeParameters) ||
TokenUtils.getFullCode(newClass.extendsClause) !=
TokenUtils.getFullCode(oldClass.extendsClause) ||
@@ -334,6 +361,7 @@
classElement.constructors = classElementHolder.constructors;
classElement.fields = newFields.values.toList();
classElement.methods = classElementHolder.methods;
+ classElement.version++;
classElementHolder.validate();
// Ensure at least a default synthetic constructor.
if (classElement.constructors.isEmpty) {
@@ -341,7 +369,11 @@
new ConstructorElementImpl.forNode(null);
constructor.synthetic = true;
classElement.constructors = <ConstructorElement>[constructor];
+ classDelta.addedConstructors.add(constructor);
}
+ classDelta.hasUnnamedConstructorChange =
+ classDelta.addedConstructors.any((c) => c.name == '') ||
+ classDelta.removedConstructors.any((c) => c.name == '');
// OK
return classDelta;
}
@@ -538,22 +570,35 @@
static void copyTokenOffsets(Map<int, int> offsetMap, Token oldToken,
Token newToken, Token oldEndToken, Token newEndToken) {
if (oldToken is CommentToken && newToken is CommentToken) {
- // Update (otherwise unlinked) reference tokens in documentation.
- if (oldToken is DocumentationCommentToken &&
- newToken is DocumentationCommentToken) {
- List<Token> oldReferences = oldToken.references;
- List<Token> newReferences = newToken.references;
- assert(oldReferences.length == newReferences.length);
- for (int i = 0; i < oldReferences.length; i++) {
- copyTokenOffsets(offsetMap, oldReferences[i], newReferences[i],
- oldEndToken, newEndToken);
- }
- }
// Update documentation tokens.
while (oldToken != null) {
offsetMap[oldToken.offset] = newToken.offset;
offsetMap[oldToken.end] = newToken.end;
oldToken.offset = newToken.offset;
+ // Update (otherwise unlinked) reference tokens in documentation.
+ if (oldToken is DocumentationCommentToken &&
+ newToken is DocumentationCommentToken) {
+ List<Token> oldReferences = oldToken.references;
+ List<Token> newReferences = newToken.references;
+ assert(oldReferences.length == newReferences.length);
+ for (int i = 0; i < oldReferences.length; i++) {
+ Token oldToken = oldReferences[i];
+ Token newToken = newReferences[i];
+ // For [new Name] the 'Name' token is the reference.
+ // But we need to process all tokens, including 'new'.
+ while (oldToken.previous != null &&
+ oldToken.previous.type != TokenType.EOF) {
+ oldToken = oldToken.previous;
+ }
+ while (newToken.previous != null &&
+ newToken.previous.type != TokenType.EOF) {
+ newToken = newToken.previous;
+ }
+ copyTokenOffsets(
+ offsetMap, oldToken, newToken, oldEndToken, newEndToken);
+ }
+ }
+ // Next tokens.
oldToken = oldToken.next;
newToken = newToken.next;
}
@@ -644,15 +689,18 @@
if (element is LibraryElement) {
return;
}
- if (element.isSynthetic && !_isVariableInitializer(element)) {
- return;
- }
if (element is ElementImpl) {
// name offset
{
int oldOffset = element.nameOffset;
int newOffset = map[oldOffset];
- assert(newOffset != null);
+ // Some synthetic elements have new offsets, e.g. synthetic accessors
+ // of property inducing elements. But some are purely synthetic, e.g.
+ // synthetic enum fields and their accessors.
+ if (newOffset == null) {
+ assert(element.isSynthetic);
+ return;
+ }
element.nameOffset = newOffset;
}
// code range
@@ -694,9 +742,4 @@
}
super.visitElement(element);
}
-
- static bool _isVariableInitializer(Element element) {
- return element is FunctionElement &&
- element.enclosingElement is VariableElement;
- }
}
diff --git a/pkg/analyzer/lib/src/task/options.dart b/pkg/analyzer/lib/src/task/options.dart
index a25d146..a101147 100644
--- a/pkg/analyzer/lib/src/task/options.dart
+++ b/pkg/analyzer/lib/src/task/options.dart
@@ -10,11 +10,13 @@
import 'package:analyzer/plugin/options.dart';
import 'package:analyzer/source/analysis_options_provider.dart';
import 'package:analyzer/source/error_processor.dart';
+import 'package:analyzer/src/context/context.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/java_engine.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/utilities_general.dart';
import 'package:analyzer/src/task/general.dart';
+import 'package:analyzer/src/util/yaml.dart';
import 'package:analyzer/task/general.dart';
import 'package:analyzer/task/model.dart';
import 'package:source_span/source_span.dart';
@@ -49,15 +51,16 @@
static const String enableSuperMixins = 'enableSuperMixins';
static const String enableTrailingCommas = 'enableTrailingCommas';
- /// This option is deprecated.
- static const String enableConditionalDirectives =
- "enableConditionalDirectives";
static const String errors = 'errors';
static const String exclude = 'exclude';
static const String language = 'language';
static const String plugins = 'plugins';
static const String strong_mode = 'strong-mode';
+ // Strong mode options, see AnalysisOptionsImpl for documentation.
+ static const String implicitCasts = 'implicit-casts';
+ static const String implicitDynamic = 'implicit-dynamic';
+
/// Ways to say `ignore`.
static const List<String> ignoreSynonyms = const ['ignore', 'false'];
@@ -83,10 +86,10 @@
/// Supported `analyzer` language configuration options.
static const List<String> languageOptions = const [
enableAsync,
- enableConditionalDirectives,
enableGenericMethods,
enableStrictCallChecks,
- enableSuperMixins
+ enableSuperMixins,
+ enableTrailingCommas
];
}
@@ -431,9 +434,8 @@
if (analyzer is Map) {
// Process strong mode option.
var strongMode = analyzer[AnalyzerOptions.strong_mode];
- if (strongMode is bool) {
- options.strongMode = strongMode;
- }
+ _applyStrongOptions(options, strongMode);
+
// Process language options.
var language = analyzer[AnalyzerOptions.language];
_applyLanguageOptions(options, language);
@@ -460,6 +462,19 @@
// Process language options.
var language = analyzer[AnalyzerOptions.language];
setLanguageOptions(context, language);
+
+ // Process excludes.
+ var excludes = analyzer[AnalyzerOptions.exclude];
+ setExcludes(context, excludes);
+ }
+ }
+
+ void setExcludes(AnalysisContext context, Object excludes) {
+ if (excludes is YamlList) {
+ List<String> excludeList = toStringList(excludes);
+ if (excludeList != null) {
+ context.setConfigurationData(CONTEXT_EXCLUDES, excludeList);
+ }
}
}
@@ -527,12 +542,19 @@
}
void setStrongMode(AnalysisContext context, Object strongMode) {
- bool strong = strongMode is bool ? strongMode : false;
- if (context.analysisOptions.strongMode != strong) {
+ if (strongMode is Map) {
AnalysisOptionsImpl options =
new AnalysisOptionsImpl.from(context.analysisOptions);
- options.strongMode = strong;
+ _applyStrongOptions(options, strongMode);
context.analysisOptions = options;
+ } else {
+ strongMode = strongMode is bool ? strongMode : false;
+ if (context.analysisOptions.strongMode != strongMode) {
+ AnalysisOptionsImpl options =
+ new AnalysisOptionsImpl.from(context.analysisOptions);
+ options.strongMode = strongMode;
+ context.analysisOptions = options;
+ }
}
}
@@ -565,4 +587,33 @@
.forEach((key, value) => _applyLanguageOption(options, key, value));
}
}
+
+ void _applyStrongModeOption(
+ AnalysisOptionsImpl options, Object feature, Object value) {
+ bool boolValue = toBool(value);
+ if (boolValue != null) {
+ if (feature == AnalyzerOptions.implicitCasts) {
+ options.implicitCasts = boolValue;
+ }
+ if (feature == AnalyzerOptions.implicitDynamic) {
+ options.implicitDynamic = boolValue;
+ }
+ }
+ }
+
+ void _applyStrongOptions(AnalysisOptionsImpl options, Object config) {
+ if (config is YamlMap) {
+ options.strongMode = true;
+ config.nodes.forEach((k, v) {
+ if (k is YamlScalar && v is YamlScalar) {
+ _applyStrongModeOption(options, k.value?.toString(), v.value);
+ }
+ });
+ } else if (config is Map) {
+ options.strongMode = true;
+ config.forEach((k, v) => _applyStrongModeOption(options, k, v));
+ } else {
+ options.strongMode = config is bool ? config : false;
+ }
+ }
}
diff --git a/pkg/analyzer/lib/src/task/strong/checker.dart b/pkg/analyzer/lib/src/task/strong/checker.dart
index 783cdf0..98c4aa6 100644
--- a/pkg/analyzer/lib/src/task/strong/checker.dart
+++ b/pkg/analyzer/lib/src/task/strong/checker.dart
@@ -380,6 +380,12 @@
}
@override
+ void visitFunctionExpression(FunctionExpression node) {
+ _checkForUnsafeBlockClosureInference(node);
+ super.visitFunctionExpression(node);
+ }
+
+ @override
void visitFunctionExpressionInvocation(FunctionExpressionInvocation node) {
checkFunctionApplication(node, node.function, node.argumentList);
node.visitChildren(this);
@@ -633,6 +639,7 @@
if (!rules.isSubtypeOf(returnType, lhsType)) {
final numType = typeProvider.numType;
+ // TODO(jmesserly): this seems to duplicate logic in StaticTypeAnalyzer.
// Try to fix up the numerical case if possible.
if (rules.isSubtypeOf(lhsType, numType) &&
rules.isSubtypeOf(lhsType, rhsType)) {
@@ -640,6 +647,8 @@
// compound operators in the int += num and num += dynamic cases.
_recordImplicitCast(expr.rightHandSide, rhsType, lhsType);
} else {
+ // TODO(jmesserly): this results in a duplicate error, because
+ // ErrorVerifier also reports it.
_recordMessage(expr, StrongModeCode.STATIC_TYPE_ERROR,
[expr, returnType, lhsType]);
}
@@ -710,6 +719,105 @@
node.visitChildren(this);
}
+ /**
+ * Check if the closure [node] is unsafe due to dartbug.com/26947. If so,
+ * issue a warning.
+ *
+ * TODO(paulberry): eliminate this once dartbug.com/26947 is fixed.
+ */
+ void _checkForUnsafeBlockClosureInference(FunctionExpression node) {
+ if (node.body is! BlockFunctionBody) {
+ return;
+ }
+ if (node.element.returnType.isDynamic) {
+ return;
+ }
+ // Find the enclosing variable declaration whose inferred type might depend
+ // on the inferred return type of the block closure (if any).
+ AstNode prevAncestor = node;
+ AstNode ancestor = node.parent;
+ while (ancestor != null && ancestor is! VariableDeclaration) {
+ if (ancestor is BlockFunctionBody) {
+ // node is inside another block function body; if that block
+ // function body is unsafe, we've already warned about it.
+ return;
+ }
+ if (ancestor is InstanceCreationExpression) {
+ // node appears inside an instance creation expression; we may be safe
+ // if the type of the instance creation expression requires no
+ // inference.
+ TypeName typeName = ancestor.constructorName.type;
+ if (typeName.typeArguments != null) {
+ // Type arguments were explicitly specified. We are safe.
+ return;
+ }
+ DartType type = typeName.type;
+ if (!(type is ParameterizedType && type.typeParameters.isNotEmpty)) {
+ // Type is not generic. We are safe.
+ return;
+ }
+ }
+ if (ancestor is MethodInvocation) {
+ // node appears inside a method or function invocation; we may be safe
+ // if the type of the method or function requires no inference.
+ if (ancestor.typeArguments != null) {
+ // Type arguments were explicitly specified. We are safe.
+ return;
+ }
+ Element methodElement = ancestor.methodName.staticElement;
+ if (!(methodElement is ExecutableElement &&
+ methodElement.typeParameters.isNotEmpty)) {
+ // Method is not generic. We are safe.
+ return;
+ }
+ }
+ if (ancestor is FunctionExpressionInvocation &&
+ !identical(prevAncestor, ancestor.function)) {
+ // node appears inside an argument to a function expression invocation;
+ // we may be safe if the type of the function expression requires no
+ // inference.
+ if (ancestor.typeArguments != null) {
+ // Type arguments were explicitly specified. We are safe.
+ return;
+ }
+ DartType type = ancestor.function.staticType;
+ if (!(type is FunctionTypeImpl && type.typeFormals.isNotEmpty)) {
+ // Type is not generic or has had its type parameters instantiated.
+ // We are safe.
+ return;
+ }
+ }
+ if ((ancestor is ListLiteral && ancestor.typeArguments != null) ||
+ (ancestor is MapLiteral && ancestor.typeArguments != null)) {
+ // node appears inside a list or map literal with an explicit type. We
+ // are safe because no type inference is required.
+ return;
+ }
+ prevAncestor = ancestor;
+ ancestor = ancestor.parent;
+ }
+ if (ancestor == null) {
+ // node is not inside a variable declaration, so it is safe.
+ return;
+ }
+ VariableDeclaration decl = ancestor;
+ VariableElement declElement = decl.element;
+ if (!declElement.hasImplicitType) {
+ // Variable declaration has an explicit type, so it's safe.
+ return;
+ }
+ if (declElement.type.isDynamic) {
+ // No type was successfully inferred for this variable, so it's safe.
+ return;
+ }
+ if (declElement.enclosingElement is ExecutableElement) {
+ // Variable declaration is inside a function or method, so it's safe.
+ return;
+ }
+ _recordMessage(node, StrongModeCode.UNSAFE_BLOCK_CLOSURE_INFERENCE,
+ [declElement.name]);
+ }
+
void _checkReturnOrYield(Expression expression, AstNode node,
{bool yieldStar: false}) {
FunctionBody body = node.getAncestor((n) => n is FunctionBody);
@@ -720,14 +828,6 @@
// analyzer error in this case.
return;
}
- InterfaceType futureType = typeProvider.futureType;
- DartType actualType = expression?.staticType;
- if (body.isAsynchronous &&
- !body.isGenerator &&
- actualType is InterfaceType &&
- actualType.element == futureType.element) {
- type = futureType.instantiate([type]);
- }
// TODO(vsm): Enforce void or dynamic (to void?) when expression is null.
if (expression != null) checkAssignment(expression, type);
}
@@ -858,9 +958,9 @@
// Stream<T> -> T
expectedType = typeProvider.streamType;
} else {
- // Future<T> -> T
- // TODO(vsm): Revisit with issue #228.
- expectedType = typeProvider.futureType;
+ // Don't validate return type of async methods.
+ // They're handled by the runtime implementation.
+ return null;
}
} else {
if (body.isGenerator) {
diff --git a/pkg/analyzer/lib/src/util/yaml.dart b/pkg/analyzer/lib/src/util/yaml.dart
index 4f71bd7..aa988e6 100644
--- a/pkg/analyzer/lib/src/util/yaml.dart
+++ b/pkg/analyzer/lib/src/util/yaml.dart
@@ -6,9 +6,28 @@
import 'dart:collection';
+import 'package:yaml/yaml.dart';
+
+/// If all of the elements of [list] are strings, return a list of strings
+/// containing the same elements. Otherwise, return `null`.
+List<String> toStringList(YamlList list) {
+ if (list == null) {
+ return null;
+ }
+ List<String> stringList = <String>[];
+ for (var element in list) {
+ if (element is String) {
+ stringList.add(element);
+ } else {
+ return null;
+ }
+ }
+ return stringList;
+}
+
/// Merges two maps (of yaml) with simple override semantics, suitable for
/// merging two maps where one map defines default values that are added to
-/// (and possibly overriden) by an overriding map.
+/// (and possibly overridden) by an overriding map.
class Merger {
/// Merges a default [o1] with an overriding object [o2].
///
diff --git a/pkg/analyzer/pubspec.yaml b/pkg/analyzer/pubspec.yaml
index 42066a8..1eccd93 100644
--- a/pkg/analyzer/pubspec.yaml
+++ b/pkg/analyzer/pubspec.yaml
@@ -1,5 +1,5 @@
name: analyzer
-version: 0.27.4-alpha.15
+version: 0.27.4-alpha.19
author: Dart Team <misc@dartlang.org>
description: Static analyzer for Dart.
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/analyzer
@@ -9,6 +9,7 @@
args: '>=0.12.1 <0.14.0'
crypto: '>=1.1.1 <3.0.0'
glob: ^1.0.3
+ isolate: ^0.2.2
html: ^0.12.0
package_config: ^0.1.5
path: '>=0.9.0 <2.0.0'
diff --git a/pkg/analyzer/test/file_system/memory_file_system_test.dart b/pkg/analyzer/test/file_system/memory_file_system_test.dart
index a6adddd..5c931b1 100644
--- a/pkg/analyzer/test/file_system/memory_file_system_test.dart
+++ b/pkg/analyzer/test/file_system/memory_file_system_test.dart
@@ -204,6 +204,12 @@
expect(file.toString(), '/foo/bar/file.txt');
}
+ void test_toUri() {
+ String path = '/foo/file.txt';
+ File file = provider.newFile(path, '');
+ expect(file.toUri(), new Uri.file(path, windows: false));
+ }
+
void test_writeAsBytesSync_existing() {
File file = provider.newFileWithBytes('/foo/file.bin', <int>[1, 2]);
expect(file.readAsBytesSync(), <int>[1, 2]);
@@ -387,6 +393,12 @@
expect(parent2.path, equals('/'));
expect(parent2.parent, isNull);
}
+
+ void test_toUri() {
+ String path = '/foo/directory';
+ Folder folder = provider.newFolder(path);
+ expect(folder.toUri(), new Uri.directory(path, windows: false));
+ }
}
@reflectiveTest
@@ -539,6 +551,13 @@
expect(file.exists, isFalse);
}
+ test_getModificationTimes() async {
+ File file = provider.newFile('/test.dart', '');
+ Source source = file.createSource();
+ List<int> times = await provider.getModificationTimes([source]);
+ expect(times, [source.modificationStamp]);
+ }
+
void test_getStateLocation_uniqueness() {
String idOne = 'one';
Folder folderOne = provider.getStateLocation(idOne);
diff --git a/pkg/analyzer/test/file_system/physical_resource_provider_test.dart b/pkg/analyzer/test/file_system/physical_resource_provider_test.dart
index 790eff7..e1f4a00 100644
--- a/pkg/analyzer/test/file_system/physical_resource_provider_test.dart
+++ b/pkg/analyzer/test/file_system/physical_resource_provider_test.dart
@@ -180,6 +180,12 @@
expect(file.exists, isTrue);
}
+ void test_toUri() {
+ String path = '/foo/file.txt';
+ File file = PhysicalResourceProvider.INSTANCE.getFile(path);
+ expect(file.toUri(), new Uri.file(path));
+ }
+
void test_shortName() {
expect(file.shortName, 'file.txt');
}
@@ -373,10 +379,25 @@
parent = grandParent;
}
}
+
+ void test_toUri() {
+ String path = '/foo/directory';
+ Folder folder = PhysicalResourceProvider.INSTANCE.getFolder(path);
+ expect(folder.toUri(), new Uri.directory(path));
+ }
}
@reflectiveTest
class PhysicalResourceProviderTest extends _BaseTest {
+ test_getModificationTimes() async {
+ PhysicalResourceProvider provider = PhysicalResourceProvider.INSTANCE;
+ String path = join(tempPath, 'file1.txt');
+ new io.File(path).writeAsStringSync('');
+ Source source = provider.getFile(path).createSource();
+ List<int> times = await provider.getModificationTimes([source]);
+ expect(times, [source.modificationStamp]);
+ }
+
void test_getStateLocation_uniqueness() {
PhysicalResourceProvider provider = PhysicalResourceProvider.INSTANCE;
String idOne = 'one';
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 5bd95e5..f3e477a 100644
--- a/pkg/analyzer/test/generated/compile_time_error_code_test.dart
+++ b/pkg/analyzer/test/generated/compile_time_error_code_test.dart
@@ -2244,6 +2244,18 @@
verify([source]);
}
+ void test_fieldInitializerOutsideConstructor_inFunctionTypeParameter() {
+ Source source = addSource(r'''
+class A {
+ int x;
+ A(int p(this.x));
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(
+ source, [CompileTimeErrorCode.FIELD_INITIALIZER_OUTSIDE_CONSTRUCTOR]);
+ verify([source]);
+ }
+
void test_fieldInitializerRedirectingConstructor_afterRedirection() {
Source source = addSource(r'''
class A {
diff --git a/pkg/analyzer/test/generated/element_resolver_test.dart b/pkg/analyzer/test/generated/element_resolver_test.dart
index da95f04..7ddd33b 100644
--- a/pkg/analyzer/test/generated/element_resolver_test.dart
+++ b/pkg/analyzer/test/generated/element_resolver_test.dart
@@ -301,6 +301,25 @@
_listener.assertNoErrors();
}
+ void test_visitCommentReference_prefixedIdentifier_class_operator() {
+ ClassElementImpl classA = ElementFactory.classElement2("A");
+ // set method
+ MethodElement method =
+ ElementFactory.methodElement("==", _typeProvider.boolType);
+ classA.methods = <MethodElement>[method];
+ // set name scope
+ _visitor.nameScope = new EnclosedScope(null)
+ ..defineNameWithoutChecking('A', classA);
+ // prepare "A.=="
+ PrefixedIdentifier prefixed = AstFactory.identifier5('A', '==');
+ CommentReference commentReference = new CommentReference(null, prefixed);
+ // resolve
+ _resolveNode(commentReference);
+ expect(prefixed.prefix.staticElement, classA);
+ expect(prefixed.identifier.staticElement, method);
+ _listener.assertNoErrors();
+ }
+
void test_visitConstructorName_named() {
ClassElementImpl classA = ElementFactory.classElement2("A");
String constructorName = "a";
diff --git a/pkg/analyzer/test/generated/engine_test.dart b/pkg/analyzer/test/generated/engine_test.dart
index b3ceaa5..1d0871d 100644
--- a/pkg/analyzer/test/generated/engine_test.dart
+++ b/pkg/analyzer/test/generated/engine_test.dart
@@ -702,13 +702,13 @@
}
@override
- bool validateCacheConsistency() {
- fail("Unexpected invocation of validateCacheConsistency");
- return false;
+ void visitContentCache(ContentCacheVisitor visitor) {
+ fail("Unexpected invocation of visitContentCache");
}
@override
- void visitContentCache(ContentCacheVisitor visitor) {
- fail("Unexpected invocation of visitContentCache");
+ CacheConsistencyValidator get cacheConsistencyValidator {
+ fail("Unexpected invocation of cacheConsistencyValidator");
+ return null;
}
}
diff --git a/pkg/analyzer/test/generated/hint_code_test.dart b/pkg/analyzer/test/generated/hint_code_test.dart
index 6644ccd..e5563a5 100644
--- a/pkg/analyzer/test/generated/hint_code_test.dart
+++ b/pkg/analyzer/test/generated/hint_code_test.dart
@@ -1359,21 +1359,6 @@
verify([source, source2]);
}
- void test_invalidUseOfProtectedMember_function_OK2() {
- Source source = addSource(r'''
-import 'package:meta/meta.dart';
-class A {
- @protected
- void a(){ }
-}
-main() {
- new A().a();
-}''');
- computeLibrarySourceErrors(source);
- assertNoErrors(source);
- verify([source]);
- }
-
void test_invalidUseOfProtectedMember_function_OK() {
Source source = addSource(r'''
import 'package:meta/meta.dart';
@@ -1390,6 +1375,21 @@
verify([source]);
}
+ void test_invalidUseOfProtectedMember_function_OK2() {
+ Source source = addSource(r'''
+import 'package:meta/meta.dart';
+class A {
+ @protected
+ void a(){ }
+}
+main() {
+ new A().a();
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
void test_invalidUseOfProtectedMember_getter() {
Source source = addNamedSource(
'/lib1.dart',
@@ -2047,6 +2047,21 @@
verify([source]);
}
+ void test_overrideOnNonOverridingField_invalid() {
+ Source source = addSource(r'''
+library dart.core;
+const override = null;
+class A {
+}
+class B extends A {
+ @override
+ final int m = 1;
+}''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.OVERRIDE_ON_NON_OVERRIDING_FIELD]);
+ verify([source]);
+ }
+
void test_overrideOnNonOverridingGetter_invalid() {
Source source = addSource(r'''
library dart.core;
diff --git a/pkg/analyzer/test/generated/incremental_resolver_test.dart b/pkg/analyzer/test/generated/incremental_resolver_test.dart
index f0b0107..fa0ad49 100644
--- a/pkg/analyzer/test/generated/incremental_resolver_test.dart
+++ b/pkg/analyzer/test/generated/incremental_resolver_test.dart
@@ -520,6 +520,19 @@
CompilationUnit oldUnit;
CompilationUnitElement oldUnitElement;
+ void assertSameReferencedNames(
+ ReferencedNames incNames, ReferencedNames fullNames) {
+ expectEqualSets(Iterable actual, Iterable expected) {
+ expect(actual, unorderedEquals(expected));
+ }
+ expectEqualSets(incNames.names, fullNames.names);
+ expectEqualSets(incNames.instantiatedNames, fullNames.instantiatedNames);
+ expectEqualSets(incNames.superToSubs.keys, fullNames.superToSubs.keys);
+ for (String key in fullNames.superToSubs.keys) {
+ expectEqualSets(incNames.superToSubs[key], fullNames.superToSubs[key]);
+ }
+ }
+
@override
void setUp() {
super.setUp();
@@ -1300,6 +1313,25 @@
}
}
+ void test_strongMode_typeComments_insertWhitespace() {
+ _resolveUnit(r'''
+import 'dart:async';
+
+void fadeIn(int milliseconds) {
+ Future<String> f;
+ f.then/*<String>*/((e) {print("hello");});
+}
+''');
+ _updateAndValidate(r'''
+import 'dart:async';
+
+void fadeIn(int milliseconds) {
+ Future<String> f;
+ f.then/*<String>*/((e) {print("hello") ;});
+}
+''');
+ }
+
void test_true_emptyLine_betweenClassMembers_insert() {
_resolveUnit(r'''
class A {
@@ -1870,6 +1902,7 @@
*/
void _resetWithIncremental(bool enable) {
AnalysisOptionsImpl analysisOptions = new AnalysisOptionsImpl();
+ analysisOptions.strongMode = true;
analysisOptions.incremental = enable;
analysisOptions.incrementalApi = enable;
logging.logger = logger;
@@ -1909,6 +1942,8 @@
logger.expectNoErrors();
List<AnalysisError> newErrors = analysisContext.computeErrors(source);
LineInfo newLineInfo = analysisContext.getLineInfo(source);
+ ReferencedNames newReferencedNames =
+ analysisContext.getResult(source, REFERENCED_NAMES);
// check for expected failure
if (!expectedSuccess) {
expect(newUnit.element, isNot(same(oldUnitElement)));
@@ -1941,6 +1976,10 @@
_assertEqualTokens(newUnit, fullNewUnit);
// Validate LineInfo
_assertEqualLineInfo(newLineInfo, analysisContext.getLineInfo(source));
+ // Validate referenced names.
+ ReferencedNames fullReferencedNames =
+ analysisContext.getResult(source, REFERENCED_NAMES);
+ assertSameReferencedNames(newReferencedNames, fullReferencedNames);
// Validate that "incremental" and "full" units have the same resolution.
try {
assertSameResolution(newUnit, fullNewUnit, validateTypes: true);
diff --git a/pkg/analyzer/test/generated/non_error_resolver_test.dart b/pkg/analyzer/test/generated/non_error_resolver_test.dart
index 1be8c5b..6156487 100644
--- a/pkg/analyzer/test/generated/non_error_resolver_test.dart
+++ b/pkg/analyzer/test/generated/non_error_resolver_test.dart
@@ -5770,6 +5770,17 @@
verify([source]);
}
+ void test_unusedShownName_unresolved() {
+ Source source = addSource(r'''
+import 'dart:math' show max, FooBar;
+main() {
+ print(max(1, 2));
+}
+''');
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [HintCode.UNDEFINED_SHOWN_NAME]);
+ }
+
void test_uriDoesNotExist_dll() {
addNamedSource("/lib.dll", "");
Source source = addSource("import 'dart-ext:lib';");
diff --git a/pkg/analyzer/test/generated/non_hint_code_test.dart b/pkg/analyzer/test/generated/non_hint_code_test.dart
index 13abb03..4ec1640 100644
--- a/pkg/analyzer/test/generated/non_hint_code_test.dart
+++ b/pkg/analyzer/test/generated/non_hint_code_test.dart
@@ -155,6 +155,26 @@
verify([source]);
}
+ void test_deadCode_deadFinalBreakInCase() {
+ Source source = addSource(r'''
+f() {
+ switch (true) {
+ case true:
+ try {
+ int a = 1;
+ } finally {
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
void test_deadCode_deadOperandLHS_and_debugConst() {
Source source = addSource(r'''
const bool DEBUG = false;
@@ -190,26 +210,6 @@
verify([source]);
}
- void test_deadCode_deadFinalBreakInCase() {
- Source source = addSource(r'''
-f() {
- switch (true) {
- case true:
- try {
- int a = 1;
- } finally {
- return;
- }
- break;
- default:
- break;
- }
-}''');
- computeLibrarySourceErrors(source);
- assertNoErrors(source);
- verify([source]);
- }
-
void test_deprecatedMemberUse_inDeprecatedClass() {
Source source = addSource(r'''
@deprecated
@@ -486,6 +486,50 @@
verify([source]);
}
+ void test_overrideOnNonOverridingField_inInterface() {
+ Source source = addSource(r'''
+library dart.core;
+const override = null;
+class A {
+ int get a => 0;
+ void set b(_) {}
+ int c;
+}
+class B implements A {
+ @override
+ final int a = 1;
+ @override
+ int b;
+ @override
+ int c;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
+ void test_overrideOnNonOverridingField_inSuperclass() {
+ Source source = addSource(r'''
+library dart.core;
+const override = null;
+class A {
+ int get a => 0;
+ void set b(_) {}
+ int c;
+}
+class B extends A {
+ @override
+ final int a = 1;
+ @override
+ int b;
+ @override
+ int c;
+}''');
+ computeLibrarySourceErrors(source);
+ assertNoErrors(source);
+ verify([source]);
+ }
+
void test_overrideOnNonOverridingGetter_inInterface() {
Source source = addSource(r'''
library dart.core;
diff --git a/pkg/analyzer/test/generated/parser_test.dart b/pkg/analyzer/test/generated/parser_test.dart
index 58c7c6f..e74309d 100644
--- a/pkg/analyzer/test/generated/parser_test.dart
+++ b/pkg/analyzer/test/generated/parser_test.dart
@@ -717,26 +717,6 @@
[ParserErrorCode.ANNOTATION_ON_ENUM_CONSTANT]);
}
- void test_assertDoesNotTakeAssignment() {
- parse4("parseAssertStatement", "assert(b = true);",
- [ParserErrorCode.ASSERT_DOES_NOT_TAKE_ASSIGNMENT]);
- }
-
- void test_assertDoesNotTakeCascades() {
- parse4("parseAssertStatement", "assert(new A()..m());",
- [ParserErrorCode.ASSERT_DOES_NOT_TAKE_CASCADE]);
- }
-
- void test_assertDoesNotTakeRethrow() {
- parse4("parseAssertStatement", "assert(rethrow);",
- [ParserErrorCode.ASSERT_DOES_NOT_TAKE_RETHROW]);
- }
-
- void test_assertDoesNotTakeThrow() {
- parse4("parseAssertStatement", "assert(throw x);",
- [ParserErrorCode.ASSERT_DOES_NOT_TAKE_THROW]);
- }
-
void test_breakOutsideOfLoop_breakInDoStatement() {
parse4("parseDoStatement", "do {break;} while (x);");
}
@@ -6301,6 +6281,66 @@
expect(identifier.offset, 9);
}
+ void test_parseCommentReference_operator_withKeyword_notPrefixed() {
+ CommentReference reference =
+ parse("parseCommentReference", <Object>["operator ==", 5], "");
+ SimpleIdentifier identifier = EngineTestCase.assertInstanceOf(
+ (obj) => obj is SimpleIdentifier,
+ SimpleIdentifier,
+ reference.identifier);
+ expect(identifier.token, isNotNull);
+ expect(identifier.name, "==");
+ expect(identifier.offset, 14);
+ }
+
+ void test_parseCommentReference_operator_withKeyword_prefixed() {
+ CommentReference reference =
+ parse("parseCommentReference", <Object>["Object.operator==", 7], "");
+ PrefixedIdentifier prefixedIdentifier = EngineTestCase.assertInstanceOf(
+ (obj) => obj is PrefixedIdentifier,
+ PrefixedIdentifier,
+ reference.identifier);
+ SimpleIdentifier prefix = prefixedIdentifier.prefix;
+ expect(prefix.token, isNotNull);
+ expect(prefix.name, "Object");
+ expect(prefix.offset, 7);
+ expect(prefixedIdentifier.period, isNotNull);
+ SimpleIdentifier identifier = prefixedIdentifier.identifier;
+ expect(identifier.token, isNotNull);
+ expect(identifier.name, "==");
+ expect(identifier.offset, 22);
+ }
+
+ void test_parseCommentReference_operator_withoutKeyword_notPrefixed() {
+ CommentReference reference =
+ parse("parseCommentReference", <Object>["==", 5], "");
+ SimpleIdentifier identifier = EngineTestCase.assertInstanceOf(
+ (obj) => obj is SimpleIdentifier,
+ SimpleIdentifier,
+ reference.identifier);
+ expect(identifier.token, isNotNull);
+ expect(identifier.name, "==");
+ expect(identifier.offset, 5);
+ }
+
+ void test_parseCommentReference_operator_withoutKeyword_prefixed() {
+ CommentReference reference =
+ parse("parseCommentReference", <Object>["Object.==", 7], "");
+ PrefixedIdentifier prefixedIdentifier = EngineTestCase.assertInstanceOf(
+ (obj) => obj is PrefixedIdentifier,
+ PrefixedIdentifier,
+ reference.identifier);
+ SimpleIdentifier prefix = prefixedIdentifier.prefix;
+ expect(prefix.token, isNotNull);
+ expect(prefix.name, "Object");
+ expect(prefix.offset, 7);
+ expect(prefixedIdentifier.period, isNotNull);
+ SimpleIdentifier identifier = prefixedIdentifier.identifier;
+ expect(identifier.token, isNotNull);
+ expect(identifier.name, "==");
+ expect(identifier.offset, 14);
+ }
+
void test_parseCommentReference_prefixed() {
CommentReference reference =
parse("parseCommentReference", <Object>["a.b", 7], "");
diff --git a/pkg/analyzer/test/generated/sdk_test.dart b/pkg/analyzer/test/generated/sdk_test.dart
index 8976b9c..7038f4d 100644
--- a/pkg/analyzer/test/generated/sdk_test.dart
+++ b/pkg/analyzer/test/generated/sdk_test.dart
@@ -4,14 +4,8 @@
library analyzer.test.generated.sdk_test;
-import 'package:analyzer/dart/ast/token.dart';
-import 'package:analyzer/src/dart/ast/token.dart';
-import 'package:analyzer/src/dart/scanner/reader.dart';
-import 'package:analyzer/src/dart/scanner/scanner.dart';
import 'package:analyzer/src/generated/engine.dart';
-import 'package:analyzer/src/generated/error.dart';
import 'package:analyzer/src/generated/sdk.dart';
-import 'package:analyzer/src/generated/source.dart';
import 'package:unittest/unittest.dart';
import '../reflective_tests.dart';
diff --git a/pkg/analyzer/test/generated/static_warning_code_test.dart b/pkg/analyzer/test/generated/static_warning_code_test.dart
index 9eb44ab..21c3778 100644
--- a/pkg/analyzer/test/generated/static_warning_code_test.dart
+++ b/pkg/analyzer/test/generated/static_warning_code_test.dart
@@ -3527,6 +3527,12 @@
assertErrors(source, [StaticWarningCode.UNDEFINED_IDENTIFIER]);
}
+ void test_undefinedIdentifierAwait_function() {
+ Source source = addSource("void a() { await; }");
+ computeLibrarySourceErrors(source);
+ assertErrors(source, [StaticWarningCode.UNDEFINED_IDENTIFIER_AWAIT]);
+ }
+
void test_undefinedIdentifier_importCore_withShow() {
Source source = addSource(r'''
import 'dart:core' show List;
diff --git a/pkg/analyzer/test/generated/strong_mode_test.dart b/pkg/analyzer/test/generated/strong_mode_test.dart
index 277f8bb..be5ee6b 100644
--- a/pkg/analyzer/test/generated/strong_mode_test.dart
+++ b/pkg/analyzer/test/generated/strong_mode_test.dart
@@ -798,7 +798,6 @@
A<int, String> a1 = new D.named(3);
}
void test8() {
- // Currently we only allow variable constraints. Test that we reject.
A<C<int>, String> a0 = new E("hello");
}
void test9() { // Check named and optional arguments
@@ -921,7 +920,7 @@
{
List<Statement> statements =
AstFinder.getStatementsInTopLevelFunction(unit, "test8");
- hasType(assertEOf([_isDynamic, _isDynamic]), rhs(statements[0]));
+ hasType(assertEOf([_isInt, _isString]), rhs(statements[0]));
}
{
diff --git a/pkg/analyzer/test/generated/type_system_test.dart b/pkg/analyzer/test/generated/type_system_test.dart
index c164540..d82d135 100644
--- a/pkg/analyzer/test/generated/type_system_test.dart
+++ b/pkg/analyzer/test/generated/type_system_test.dart
@@ -891,9 +891,7 @@
expect(_inferCall(clone, [foo.type, foo.type]), [foo.type]);
// Something invalid...
- expect(_inferCall(clone, [stringType, numType]), [
- clonable.type.instantiate([dynamicType])
- ]);
+ expect(_inferCall(clone, [stringType, numType]), null);
}
void test_genericCastFunction() {
@@ -1007,7 +1005,7 @@
// <T extends num>() -> T
var t = TypeBuilder.variable('T', bound: numType);
var f = TypeBuilder.function(types: [t], required: [], result: t);
- expect(_inferCall(f, [], stringType), [numType]);
+ expect(_inferCall(f, [], stringType), null);
}
void test_unifyParametersToFunctionParam() {
@@ -1024,7 +1022,7 @@
TypeBuilder.function(required: [intType], result: dynamicType),
TypeBuilder.function(required: [doubleType], result: dynamicType)
]),
- [dynamicType]);
+ null);
}
void test_unusedReturnTypeIsDynamic() {
@@ -1045,7 +1043,7 @@
[DartType returnType]) {
FunctionType inferred = typeSystem.inferGenericFunctionCall(typeProvider,
ft, ft.parameters.map((p) => p.type).toList(), arguments, returnType);
- return inferred.typeArguments;
+ return inferred?.typeArguments;
}
}
diff --git a/pkg/analyzer/test/resource_utils.dart b/pkg/analyzer/test/resource_utils.dart
index 5936144..65f7069 100644
--- a/pkg/analyzer/test/resource_utils.dart
+++ b/pkg/analyzer/test/resource_utils.dart
@@ -4,10 +4,12 @@
library analyzer.test.resource_utils;
+import 'dart:async';
import 'dart:core' hide Resource;
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
+import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/util/absolute_path.dart';
import 'package:path/path.dart' as path;
import 'package:unittest/unittest.dart';
@@ -104,6 +106,11 @@
Folder getFolder(String path) => _provider.getFolder(_assertPath(path));
@override
+ Future<List<int>> getModificationTimes(List<Source> sources) async {
+ return sources.map((source) => 0).toList();
+ }
+
+ @override
Resource getResource(String path) => _provider.getResource(_assertPath(path));
@override
diff --git a/pkg/analyzer/test/src/context/builder_test.dart b/pkg/analyzer/test/src/context/builder_test.dart
index 758a03c..50489e4 100644
--- a/pkg/analyzer/test/src/context/builder_test.dart
+++ b/pkg/analyzer/test/src/context/builder_test.dart
@@ -9,7 +9,9 @@
import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:analyzer/file_system/physical_file_system.dart';
+import 'package:analyzer/source/package_map_resolver.dart';
import 'package:analyzer/src/context/builder.dart';
+import 'package:analyzer/src/context/source.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/sdk.dart';
import 'package:analyzer/src/generated/source.dart';
@@ -51,12 +53,56 @@
*/
ContentCache contentCache;
+ /**
+ * The context builder to be used in the test.
+ */
+ ContextBuilder builder;
+
+ /**
+ * The path to the default SDK, or `null` if the test has not explicitly
+ * invoked [createDefaultSdk].
+ */
+ String defaultSdkPath = null;
+
+ void createDefaultSdk(io.Directory tempDir) {
+ defaultSdkPath = pathContext.join(tempDir.path, 'default', 'sdk');
+ String librariesFilePath = pathContext.join(defaultSdkPath, 'lib',
+ '_internal', 'sdk_library_metadata', 'lib', 'libraries.dart');
+ createFile(
+ librariesFilePath,
+ r'''
+const Map<String, LibraryInfo> libraries = const {
+ "async": const LibraryInfo("async/async.dart"),
+ "core": const LibraryInfo("core/core.dart"),
+};
+''');
+ sdkManager =
+ new DartSdkManager(defaultSdkPath, false, (_) => new MockSdk());
+ builder = new ContextBuilder(resourceProvider, sdkManager, contentCache);
+ }
+
+ void createDirectory(String path) {
+ new io.Directory(path).createSync(recursive: true);
+ }
+
+ void createFile(String path, String content) {
+ new io.File(path)
+ ..createSync(recursive: true)
+ ..writeAsStringSync(content);
+ }
+
@override
void setUp() {
resourceProvider = PhysicalResourceProvider.INSTANCE;
pathContext = resourceProvider.pathContext;
sdkManager = new DartSdkManager('', false, (_) => new MockSdk());
contentCache = new ContentCache();
+ builder = new ContextBuilder(resourceProvider, sdkManager, contentCache);
+ }
+
+ @failingTest
+ void test_buildContext() {
+ fail('Incomplete test');
}
void test_createPackageMap_fromPackageDirectory_explicit() {
@@ -69,12 +115,10 @@
String fooPath = pathContext.join(packageDirPath, fooName);
String barName = 'bar';
String barPath = pathContext.join(packageDirPath, barName);
- new io.Directory(projectPath).createSync(recursive: true);
- new io.Directory(fooPath).createSync(recursive: true);
- new io.Directory(barPath).createSync(recursive: true);
+ createDirectory(projectPath);
+ createDirectory(fooPath);
+ createDirectory(barPath);
- ContextBuilder builder =
- new ContextBuilder(resourceProvider, sdkManager, contentCache);
builder.defaultPackagesDirectoryPath = packageDirPath;
Packages packages = builder.createPackageMap(projectPath);
@@ -95,11 +139,9 @@
String fooPath = pathContext.join(packageDirPath, fooName);
String barName = 'bar';
String barPath = pathContext.join(packageDirPath, barName);
- new io.Directory(fooPath).createSync(recursive: true);
- new io.Directory(barPath).createSync(recursive: true);
+ createDirectory(fooPath);
+ createDirectory(barPath);
- ContextBuilder builder =
- new ContextBuilder(resourceProvider, sdkManager, contentCache);
Packages packages = builder.createPackageMap(projectPath);
expect(packages, isNotNull);
Map<String, Uri> map = packages.asMap();
@@ -115,16 +157,14 @@
String rootPath = tempDir.path;
String projectPath = pathContext.join(rootPath, 'project');
String packageFilePath = pathContext.join(rootPath, 'child', '.packages');
- new io.Directory(projectPath).createSync(recursive: true);
- new io.File(packageFilePath)
- ..createSync(recursive: true)
- ..writeAsStringSync(r'''
+ createDirectory(projectPath);
+ createFile(
+ packageFilePath,
+ r'''
foo:/pkg/foo
bar:/pkg/bar
''');
- ContextBuilder builder =
- new ContextBuilder(resourceProvider, sdkManager, contentCache);
builder.defaultPackageFilePath = packageFilePath;
Packages packages = builder.createPackageMap(projectPath);
expect(packages, isNotNull);
@@ -141,16 +181,14 @@
String rootPath = tempDir.path;
String projectPath = pathContext.join(rootPath, 'project');
String packageFilePath = pathContext.join(rootPath, '.packages');
- new io.Directory(projectPath).createSync(recursive: true);
- new io.File(packageFilePath)
- ..createSync(recursive: true)
- ..writeAsStringSync(r'''
+ createDirectory(projectPath);
+ createFile(
+ packageFilePath,
+ r'''
foo:/pkg/foo
bar:/pkg/bar
''');
- ContextBuilder builder =
- new ContextBuilder(resourceProvider, sdkManager, contentCache);
Packages packages = builder.createPackageMap(projectPath);
expect(packages, isNotNull);
Map<String, Uri> map = packages.asMap();
@@ -166,16 +204,14 @@
String rootPath = tempDir.path;
String projectPath = pathContext.join(rootPath, 'project');
String packageFilePath = pathContext.join(projectPath, '.packages');
- new io.Directory(projectPath).createSync(recursive: true);
- new io.File(packageFilePath)
- ..createSync(recursive: true)
- ..writeAsStringSync(r'''
+ createDirectory(projectPath);
+ createFile(
+ packageFilePath,
+ r'''
foo:/pkg/foo
bar:/pkg/bar
''');
- ContextBuilder builder =
- new ContextBuilder(resourceProvider, sdkManager, contentCache);
Packages packages = builder.createPackageMap(projectPath);
expect(packages, isNotNull);
Map<String, Uri> map = packages.asMap();
@@ -187,13 +223,192 @@
void test_createPackageMap_none() {
withTempDir((io.Directory tempDir) {
- ContextBuilder builder =
- new ContextBuilder(resourceProvider, sdkManager, contentCache);
Packages packages = builder.createPackageMap(tempDir.path);
expect(packages, same(Packages.noPackages));
});
}
+ void test_createSourceFactory_fileProvider() {
+ withTempDir((io.Directory tempDir) {
+ createDefaultSdk(tempDir);
+ String rootPath = tempDir.path;
+ String projectPath = pathContext.join(rootPath, 'project');
+ String packageFilePath = pathContext.join(projectPath, '.packages');
+ String packageA = pathContext.join(rootPath, 'pkgs', 'a');
+ String packageB = pathContext.join(rootPath, 'pkgs', 'b');
+ createFile(
+ packageFilePath,
+ '''
+a:${pathContext.toUri(packageA)}
+b:${pathContext.toUri(packageB)}
+''');
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+ UriResolver resolver = new ResourceUriResolver(resourceProvider);
+ builder.fileResolverProvider = (folder) => resolver;
+ SourceFactoryImpl factory =
+ builder.createSourceFactory(projectPath, options);
+ expect(factory.resolvers, contains(same(resolver)));
+ });
+ }
+
+ void test_createSourceFactory_noProvider_packages_embedder_extensions() {
+ withTempDir((io.Directory tempDir) {
+ createDefaultSdk(tempDir);
+ String rootPath = tempDir.path;
+ String projectPath = pathContext.join(rootPath, 'project');
+ String packageFilePath = pathContext.join(projectPath, '.packages');
+ String packageA = pathContext.join(rootPath, 'pkgs', 'a');
+ String embedderPath = pathContext.join(packageA, '_embedder.yaml');
+ String packageB = pathContext.join(rootPath, 'pkgs', 'b');
+ String extensionPath = pathContext.join(packageB, '_sdkext');
+ createFile(
+ packageFilePath,
+ '''
+a:${pathContext.toUri(packageA)}
+b:${pathContext.toUri(packageB)}
+''');
+ String asyncPath = pathContext.join(packageA, 'sdk', 'async.dart');
+ String corePath = pathContext.join(packageA, 'sdk', 'core.dart');
+ createFile(
+ embedderPath,
+ '''
+embedded_libs:
+ "dart:async": ${_relativeUri(asyncPath, from: packageA)}
+ "dart:core": ${_relativeUri(corePath, from: packageA)}
+''');
+ String fooPath = pathContext.join(packageB, 'ext', 'foo.dart');
+ createFile(
+ extensionPath,
+ '''{
+"dart:foo": "${_relativeUri(fooPath, from: packageB)}"
+}''');
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+
+ SourceFactory factory = builder.createSourceFactory(projectPath, options);
+
+ Source asyncSource = factory.forUri('dart:async');
+ expect(asyncSource, isNotNull);
+ expect(asyncSource.fullName, asyncPath);
+
+ Source fooSource = factory.forUri('dart:foo');
+ expect(fooSource, isNotNull);
+ expect(fooSource.fullName, fooPath);
+
+ Source packageSource = factory.forUri('package:b/b.dart');
+ expect(packageSource, isNotNull);
+ expect(packageSource.fullName, pathContext.join(packageB, 'b.dart'));
+ });
+ }
+
+ void test_createSourceFactory_noProvider_packages_embedder_noExtensions() {
+ withTempDir((io.Directory tempDir) {
+ createDefaultSdk(tempDir);
+ String rootPath = tempDir.path;
+ String projectPath = pathContext.join(rootPath, 'project');
+ String packageFilePath = pathContext.join(projectPath, '.packages');
+ String packageA = pathContext.join(rootPath, 'pkgs', 'a');
+ String embedderPath = pathContext.join(packageA, '_embedder.yaml');
+ String packageB = pathContext.join(rootPath, 'pkgs', 'b');
+ createFile(
+ packageFilePath,
+ '''
+a:${pathContext.toUri(packageA)}
+b:${pathContext.toUri(packageB)}
+''');
+ String asyncPath = pathContext.join(packageA, 'sdk', 'async.dart');
+ String corePath = pathContext.join(packageA, 'sdk', 'core.dart');
+ createFile(
+ embedderPath,
+ '''
+embedded_libs:
+ "dart:async": ${_relativeUri(asyncPath, from: packageA)}
+ "dart:core": ${_relativeUri(corePath, from: packageA)}
+''');
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+
+ SourceFactory factory = builder.createSourceFactory(projectPath, options);
+
+ Source dartSource = factory.forUri('dart:async');
+ expect(dartSource, isNotNull);
+ expect(dartSource.fullName, asyncPath);
+
+ Source packageSource = factory.forUri('package:b/b.dart');
+ expect(packageSource, isNotNull);
+ expect(packageSource.fullName, pathContext.join(packageB, 'b.dart'));
+ });
+ }
+
+ @failingTest
+ void test_createSourceFactory_noProvider_packages_noEmbedder_extensions() {
+ fail('Incomplete test');
+ }
+
+ void test_createSourceFactory_noProvider_packages_noEmbedder_noExtensions() {
+ withTempDir((io.Directory tempDir) {
+ createDefaultSdk(tempDir);
+ String rootPath = tempDir.path;
+ String projectPath = pathContext.join(rootPath, 'project');
+ String packageFilePath = pathContext.join(projectPath, '.packages');
+ String packageA = pathContext.join(rootPath, 'pkgs', 'a');
+ String packageB = pathContext.join(rootPath, 'pkgs', 'b');
+ createFile(
+ packageFilePath,
+ '''
+a:${pathContext.toUri(packageA)}
+b:${pathContext.toUri(packageB)}
+''');
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+
+ SourceFactory factory = builder.createSourceFactory(projectPath, options);
+
+ Source dartSource = factory.forUri('dart:core');
+ expect(dartSource, isNotNull);
+ expect(dartSource.fullName, '$defaultSdkPath/lib/core/core.dart');
+
+ Source packageSource = factory.forUri('package:a/a.dart');
+ expect(packageSource, isNotNull);
+ expect(packageSource.fullName, pathContext.join(packageA, 'a.dart'));
+ });
+ }
+
+ void test_createSourceFactory_packageProvider() {
+ withTempDir((io.Directory tempDir) {
+ createDefaultSdk(tempDir);
+ String rootPath = tempDir.path;
+ String projectPath = pathContext.join(rootPath, 'project');
+ AnalysisOptionsImpl options = new AnalysisOptionsImpl();
+ UriResolver resolver = new PackageMapUriResolver(resourceProvider, {});
+ builder.packageResolverProvider = (folder) => resolver;
+ SourceFactoryImpl factory =
+ builder.createSourceFactory(projectPath, options);
+ expect(factory.resolvers, contains(same(resolver)));
+ });
+ }
+
+ @failingTest
+ void test_findSdk_embedder_extensions() {
+ // See test_createSourceFactory_noProvider_packages_embedder_extensions
+ fail('Incomplete test');
+ }
+
+ @failingTest
+ void test_findSdk_embedder_noExtensions() {
+ // See test_createSourceFactory_noProvider_packages_embedder_noExtensions
+ fail('Incomplete test');
+ }
+
+ @failingTest
+ void test_findSdk_noEmbedder_extensions() {
+ // See test_createSourceFactory_noProvider_packages_noEmbedder_extensions
+ fail('Incomplete test');
+ }
+
+ @failingTest
+ void test_findSdk_noEmbedder_noExtensions() {
+ // See test_createSourceFactory_noProvider_packages_noEmbedder_noExtensions
+ fail('Incomplete test');
+ }
+
/**
* Execute the [test] function with a temporary [directory]. The test function
* can perform any disk operations within the directory and the directory (and
@@ -208,6 +423,11 @@
directory.deleteSync(recursive: true);
}
}
+
+ Uri _relativeUri(String path, {String from}) {
+ String relativePath = pathContext.relative(path, from: from);
+ return pathContext.toUri(relativePath);
+ }
}
@reflectiveTest
@@ -227,30 +447,24 @@
*/
ContentCache contentCache;
- void fail_createSourceFactory() {
- fail('Incomplete test');
- }
-
- void fail_findSdkResolver() {
- fail('Incomplete test');
- }
+ /**
+ * The context builder to be used in the test.
+ */
+ ContextBuilder builder;
@override
void setUp() {
resourceProvider = new MemoryResourceProvider();
sdkManager = new DartSdkManager('', false, (_) => new MockSdk());
contentCache = new ContentCache();
+ builder = new ContextBuilder(resourceProvider, sdkManager, contentCache);
}
void test_convertPackagesToMap_noPackages() {
- ContextBuilder builder =
- new ContextBuilder(resourceProvider, sdkManager, contentCache);
expect(builder.convertPackagesToMap(Packages.noPackages), isNull);
}
void test_convertPackagesToMap_null() {
- ContextBuilder builder =
- new ContextBuilder(resourceProvider, sdkManager, contentCache);
expect(builder.convertPackagesToMap(null), isNull);
}
@@ -262,8 +476,6 @@
String barPath = '/pkg/bar';
Uri barUri = new Uri.directory(barPath);
- ContextBuilder builder =
- new ContextBuilder(resourceProvider, sdkManager, contentCache);
MapPackages packages = new MapPackages({fooName: fooUri, barName: barUri});
Map<String, List<Folder>> result = builder.convertPackagesToMap(packages);
expect(result, isNotNull);
@@ -274,13 +486,137 @@
expect(result[barName][0].path, barPath);
}
+ void test_createDefaultOptions_default() {
+ // Invert a subset of the options to ensure that the default options are
+ // being returned.
+ AnalysisOptionsImpl defaultOptions = new AnalysisOptionsImpl();
+ defaultOptions.dart2jsHint = !defaultOptions.dart2jsHint;
+ defaultOptions.enableAssertMessage = !defaultOptions.enableAssertMessage;
+ defaultOptions.enableAsync = !defaultOptions.enableAsync;
+ defaultOptions.enableGenericMethods = !defaultOptions.enableGenericMethods;
+ defaultOptions.enableStrictCallChecks =
+ !defaultOptions.enableStrictCallChecks;
+ defaultOptions.enableSuperMixins = !defaultOptions.enableSuperMixins;
+ builder.defaultOptions = defaultOptions;
+ AnalysisOptions options = builder.createDefaultOptions();
+ _expectEqualOptions(options, defaultOptions);
+ }
+
+ void test_createDefaultOptions_noDefault() {
+ AnalysisOptions options = builder.createDefaultOptions();
+ _expectEqualOptions(options, new AnalysisOptionsImpl());
+ }
+
+ void test_declareVariables_emptyMap() {
+ AnalysisContext context = AnalysisEngine.instance.createAnalysisContext();
+ Iterable<String> expected = context.declaredVariables.variableNames;
+ builder.declaredVariables = <String, String>{};
+
+ builder.declareVariables(context);
+ expect(context.declaredVariables.variableNames, unorderedEquals(expected));
+ }
+
+ void test_declareVariables_nonEmptyMap() {
+ AnalysisContext context = AnalysisEngine.instance.createAnalysisContext();
+ List<String> expected = context.declaredVariables.variableNames.toList();
+ expect(expected, isNot(contains('a')));
+ expect(expected, isNot(contains('b')));
+ expected.addAll(['a', 'b']);
+ builder.declaredVariables = <String, String>{'a': 'a', 'b': 'b'};
+
+ builder.declareVariables(context);
+ expect(context.declaredVariables.variableNames, unorderedEquals(expected));
+ }
+
+ void test_declareVariables_null() {
+ AnalysisContext context = AnalysisEngine.instance.createAnalysisContext();
+ Iterable<String> expected = context.declaredVariables.variableNames;
+
+ builder.declareVariables(context);
+ expect(context.declaredVariables.variableNames, unorderedEquals(expected));
+ }
+
+ void test_findSdk_noPackageMap() {
+ DartSdk sdk = builder.findSdk(null, new AnalysisOptionsImpl());
+ expect(sdk, isNotNull);
+ }
+
+ void test_getAnalysisOptions_default_noOverrides() {
+ AnalysisOptionsImpl defaultOptions = new AnalysisOptionsImpl();
+ defaultOptions.enableGenericMethods = true;
+ builder.defaultOptions = defaultOptions;
+ AnalysisOptionsImpl expected = new AnalysisOptionsImpl();
+ expected.enableGenericMethods = true;
+ String path = '/some/directory/path';
+ String filePath = '$path/${AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE}';
+ resourceProvider.newFile(
+ filePath,
+ '''
+linter:
+ rules:
+ - empty_constructor_bodies
+''');
+
+ AnalysisOptions options = builder.getAnalysisOptions(path);
+ _expectEqualOptions(options, expected);
+ }
+
+ void test_getAnalysisOptions_default_overrides() {
+ AnalysisOptionsImpl defaultOptions = new AnalysisOptionsImpl();
+ defaultOptions.enableGenericMethods = true;
+ builder.defaultOptions = defaultOptions;
+ AnalysisOptionsImpl expected = new AnalysisOptionsImpl();
+ expected.enableAsync = true;
+ expected.enableGenericMethods = true;
+ String path = '/some/directory/path';
+ String filePath = '$path/${AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE}';
+ resourceProvider.newFile(
+ filePath,
+ '''
+analyzer:
+ enableAsync : true
+''');
+
+ AnalysisOptions options = builder.getAnalysisOptions(path);
+ _expectEqualOptions(options, expected);
+ }
+
+ void test_getAnalysisOptions_noDefault_noOverrides() {
+ String path = '/some/directory/path';
+ String filePath = '$path/${AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE}';
+ resourceProvider.newFile(
+ filePath,
+ '''
+linter:
+ rules:
+ - empty_constructor_bodies
+''');
+
+ AnalysisOptions options = builder.getAnalysisOptions(path);
+ _expectEqualOptions(options, new AnalysisOptionsImpl());
+ }
+
+ void test_getAnalysisOptions_noDefault_overrides() {
+ AnalysisOptionsImpl expected = new AnalysisOptionsImpl();
+ expected.enableAsync = true;
+ String path = '/some/directory/path';
+ String filePath = '$path/${AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE}';
+ resourceProvider.newFile(
+ filePath,
+ '''
+analyzer:
+ enableAsync : true
+''');
+
+ AnalysisOptions options = builder.getAnalysisOptions(path);
+ _expectEqualOptions(options, expected);
+ }
+
void test_getOptionsFile_explicit() {
String path = '/some/directory/path';
String filePath = '/options/analysis.yaml';
resourceProvider.newFile(filePath, '');
- ContextBuilder builder =
- new ContextBuilder(resourceProvider, sdkManager, contentCache);
builder.defaultAnalysisOptionsFilePath = filePath;
File result = builder.getOptionsFile(path);
expect(result, isNotNull);
@@ -294,8 +630,6 @@
'$parentPath/${AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE}';
resourceProvider.newFile(filePath, '');
- ContextBuilder builder =
- new ContextBuilder(resourceProvider, sdkManager, contentCache);
File result = builder.getOptionsFile(path);
expect(result, isNotNull);
expect(result.path, filePath);
@@ -307,8 +641,6 @@
String filePath = '$parentPath/${AnalysisEngine.ANALYSIS_OPTIONS_FILE}';
resourceProvider.newFile(filePath, '');
- ContextBuilder builder =
- new ContextBuilder(resourceProvider, sdkManager, contentCache);
File result = builder.getOptionsFile(path);
expect(result, isNotNull);
expect(result.path, filePath);
@@ -319,8 +651,6 @@
String filePath = '$path/${AnalysisEngine.ANALYSIS_OPTIONS_YAML_FILE}';
resourceProvider.newFile(filePath, '');
- ContextBuilder builder =
- new ContextBuilder(resourceProvider, sdkManager, contentCache);
File result = builder.getOptionsFile(path);
expect(result, isNotNull);
expect(result.path, filePath);
@@ -331,10 +661,38 @@
String filePath = '$path/${AnalysisEngine.ANALYSIS_OPTIONS_FILE}';
resourceProvider.newFile(filePath, '');
- ContextBuilder builder =
- new ContextBuilder(resourceProvider, sdkManager, contentCache);
File result = builder.getOptionsFile(path);
expect(result, isNotNull);
expect(result.path, filePath);
}
+
+ void _expectEqualOptions(
+ AnalysisOptionsImpl actual, AnalysisOptionsImpl expected) {
+ // TODO(brianwilkerson) Consider moving this to AnalysisOptionsImpl.==.
+ expect(actual.analyzeFunctionBodiesPredicate,
+ same(expected.analyzeFunctionBodiesPredicate));
+ expect(actual.cacheSize, expected.cacheSize);
+ expect(actual.dart2jsHint, expected.dart2jsHint);
+ expect(actual.enableAssertMessage, expected.enableAssertMessage);
+ expect(actual.enableAsync, expected.enableAsync);
+ expect(actual.enableStrictCallChecks, expected.enableStrictCallChecks);
+ expect(actual.enableGenericMethods, expected.enableGenericMethods);
+ expect(actual.enableSuperMixins, expected.enableSuperMixins);
+ expect(actual.enableTiming, expected.enableTiming);
+ expect(actual.enableTrailingCommas, expected.enableTrailingCommas);
+ expect(actual.generateImplicitErrors, expected.generateImplicitErrors);
+ expect(actual.generateSdkErrors, expected.generateSdkErrors);
+ expect(actual.hint, expected.hint);
+ expect(actual.incremental, expected.incremental);
+ expect(actual.incrementalApi, expected.incrementalApi);
+ expect(actual.incrementalValidation, expected.incrementalValidation);
+ expect(actual.lint, expected.lint);
+ expect(actual.preserveComments, expected.preserveComments);
+ expect(actual.strongMode, expected.strongMode);
+ expect(actual.strongModeHints, expected.strongModeHints);
+ expect(actual.implicitCasts, expected.implicitCasts);
+ expect(actual.implicitDynamic, expected.implicitDynamic);
+ expect(actual.trackCacheDependencies, expected.trackCacheDependencies);
+ expect(actual.finerGrainedInvalidation, expected.finerGrainedInvalidation);
+ }
}
diff --git a/pkg/analyzer/test/src/context/cache_test.dart b/pkg/analyzer/test/src/context/cache_test.dart
index b03791a..ab35ffb 100644
--- a/pkg/analyzer/test/src/context/cache_test.dart
+++ b/pkg/analyzer/test/src/context/cache_test.dart
@@ -4,6 +4,9 @@
library analyzer.test.src.context.cache_test;
+import 'package:analyzer/file_system/file_system.dart';
+import 'package:analyzer/file_system/memory_file_system.dart';
+import 'package:analyzer/source/package_map_resolver.dart';
import 'package:analyzer/src/context/cache.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/java_engine.dart';
@@ -778,6 +781,28 @@
expect(entry.getValue(result2), 222);
}
+ test_setValue_userBeforeProvider_invalidateProvider_alsoUser() {
+ AnalysisTarget target1 = new TestSource('/a.dart');
+ AnalysisTarget target2 = new TestSource('/b.dart');
+ CacheEntry entry1 = new CacheEntry(target1);
+ CacheEntry entry2 = new CacheEntry(target2);
+ cache.put(entry1);
+ cache.put(entry2);
+ ResultDescriptor result1 = new ResultDescriptor('result1', -1);
+ ResultDescriptor result2 = new ResultDescriptor('result2', -2);
+ // set results, all of them are VALID
+ entry2.setValue(result2, 222, [new TargetedResult(target1, result1)]);
+ entry1.setValue(result1, 111, TargetedResult.EMPTY_LIST);
+ expect(entry1.getState(result1), CacheState.VALID);
+ expect(entry2.getState(result2), CacheState.VALID);
+ expect(entry1.getValue(result1), 111);
+ expect(entry2.getValue(result2), 222);
+ // invalidate result1, should invalidate also result2
+ entry1.setState(result1, CacheState.INVALID);
+ expect(entry1.getState(result1), CacheState.INVALID);
+ expect(entry2.getState(result2), CacheState.INVALID);
+ }
+
test_setValueIncremental() {
AnalysisTarget target = new TestSource();
CacheEntry entry = new CacheEntry(target);
@@ -1079,6 +1104,35 @@
}
@reflectiveTest
+class PackageCachePartitionTest extends CachePartitionTest {
+ MemoryResourceProvider resourceProvider;
+ Folder rootFolder;
+
+ CachePartition createPartition() {
+ resourceProvider = new MemoryResourceProvider();
+ rootFolder = resourceProvider.newFolder('/package/root');
+ return new PackageCachePartition(null, rootFolder);
+ }
+
+ void test_contains_false() {
+ CachePartition partition = createPartition();
+ AnalysisTarget target = new TestSource();
+ expect(partition.isResponsibleFor(target), isFalse);
+ }
+
+ void test_contains_true() {
+ SdkCachePartition partition = new SdkCachePartition(null);
+ SourceFactory factory = new SourceFactory([
+ new PackageMapUriResolver(resourceProvider, <String, List<Folder>>{
+ 'root': <Folder>[rootFolder]
+ })
+ ]);
+ AnalysisTarget target = factory.forUri("package:root/root.dart");
+ expect(partition.isResponsibleFor(target), isTrue);
+ }
+}
+
+@reflectiveTest
class ResultDataTest extends EngineTestCase {
test_creation() {
String value = 'value';
@@ -1177,6 +1231,15 @@
_KeepContinueDelta(this.source, this.keepDescriptor);
@override
+ bool gatherChanges(InternalAnalysisContext context, AnalysisTarget target,
+ ResultDescriptor descriptor, Object value) {
+ return false;
+ }
+
+ @override
+ void gatherEnd() {}
+
+ @override
DeltaResult validate(InternalAnalysisContext context, AnalysisTarget target,
ResultDescriptor descriptor, Object value) {
if (descriptor == keepDescriptor) {
diff --git a/pkg/analyzer/test/src/context/context_factory_test.dart b/pkg/analyzer/test/src/context/context_factory_test.dart
deleted file mode 100644
index a116d29..0000000
--- a/pkg/analyzer/test/src/context/context_factory_test.dart
+++ /dev/null
@@ -1,159 +0,0 @@
-// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library analyzer.test.src.context.context_factory_test;
-
-import 'package:analyzer/file_system/file_system.dart';
-import 'package:analyzer/file_system/memory_file_system.dart';
-import 'package:analyzer/src/context/context_factory.dart';
-import 'package:unittest/unittest.dart';
-
-import '../../reflective_tests.dart';
-import '../../utils.dart';
-
-main() {
- initializeTestEnvironment();
- runReflectiveTests(PackageMapProcessorTest);
-}
-
-@reflectiveTest
-class PackageMapProcessorTest {
- MemoryResourceProvider resourceProvider;
-
- Folder empty;
- Folder tmp_sdk_ext;
- Folder tmp_embedder;
- Map<String, List<Folder>> packageMap;
-
- void setUp() {
- resourceProvider = new MemoryResourceProvider();
- empty = resourceProvider.newFolder('/empty');
- tmp_sdk_ext = resourceProvider.newFolder('/tmp_sdk_ext');
- tmp_embedder = resourceProvider.newFolder('/tmp_embedder');
- packageMap = <String, List<Folder>>{
- 'empty': [empty],
- 'tmp_embedder': [tmp_embedder],
- 'tmp_sdk_ext': [tmp_sdk_ext]
- };
- }
-
- void test_basic_processing() {
- resourceProvider.newFile(
- '/tmp_sdk_ext/_sdkext',
- r'''
- {
- "dart:ui": "ui.dart"
- }''');
- resourceProvider.newFile(
- '/tmp_embedder/_embedder.yaml',
- r'''
-embedded_libs:
- "dart:core" : "core.dart"
- "dart:fox": "slippy.dart"
- "dart:bear": "grizzly.dart"
- "dart:relative": "../relative.dart"
- "dart:deep": "deep/directory/file.dart"
-''');
-
- PackageMapProcessor proc = new PackageMapProcessor(packageMap);
- expect(proc.embeddedLibraries.size(), 5);
- expect(proc.embeddedLibraries.getLibrary('dart:core').path,
- '/tmp_embedder/core.dart');
- expect(proc.extendedLibraries.size(), 1);
- expect(proc.extendedLibraries.getLibrary('dart:ui').path,
- '/tmp_sdk_ext/ui.dart');
- }
-
- void test_empty_package_map() {
- PackageMapProcessor proc =
- new PackageMapProcessor(<String, List<Folder>>{});
- expect(proc.embeddedLibraries.size(), 0);
- expect(proc.extendedLibraries.size(), 0);
- expect(proc.libraryMap.size(), 0);
- }
-
- void test_extenders_do_not_override() {
- resourceProvider.newFile(
- '/tmp_sdk_ext/_sdkext',
- r'''
- {
- "dart:ui": "ui2.dart"
- }''');
- resourceProvider.newFile(
- '/tmp_embedder/_embedder.yaml',
- r'''
-embedded_libs:
- "dart:core" : "core.dart"
- "dart:ui": "ui.dart"
-''');
-
- PackageMapProcessor proc = new PackageMapProcessor(packageMap);
- expect(proc.embeddedLibraries.size(), 2);
- expect(proc.extendedLibraries.size(), 1);
- expect(proc.libraryMap.size(), 2);
- expect(proc.libraryMap.getLibrary('dart:ui').path, '/tmp_embedder/ui.dart');
- }
-
- void test_invalid_embedder() {
- resourceProvider.newFile(
- '/tmp_embedder/_embedder.yaml',
- r'''
-invalid contents, will not parse
-''');
-
- PackageMapProcessor proc = new PackageMapProcessor(packageMap);
- expect(proc.embeddedLibraries.size(), 0);
- expect(proc.extendedLibraries.size(), 0);
- expect(proc.libraryMap.size(), 0);
- }
-
- void test_invalid_extender() {
- resourceProvider.newFile(
- '/tmp_sdk_ext/_sdkext',
- r'''
-invalid contents, will not parse
-''');
-
- PackageMapProcessor proc = new PackageMapProcessor(packageMap);
- expect(proc.embeddedLibraries.size(), 0);
- expect(proc.extendedLibraries.size(), 0);
- expect(proc.libraryMap.size(), 0);
- }
-
- void test_no_embedder() {
- resourceProvider.newFile(
- '/tmp_sdk_ext/_sdkext',
- r'''
- {
- "dart:ui": "ui2.dart"
- }''');
-
- PackageMapProcessor proc = new PackageMapProcessor(packageMap);
- expect(proc.embeddedLibraries.size(), 0);
- expect(proc.extendedLibraries.size(), 1);
- expect(proc.libraryMap.size(), 1);
- }
-
- void test_no_embedder_or_extender() {
- PackageMapProcessor proc = new PackageMapProcessor(packageMap);
- expect(proc.embeddedLibraries.size(), 0);
- expect(proc.extendedLibraries.size(), 0);
- expect(proc.libraryMap.size(), 0);
- }
-
- void test_no_extender() {
- resourceProvider.newFile(
- '/tmp_embedder/_embedder.yaml',
- r'''
-embedded_libs:
- "dart:core" : "core.dart"
- "dart:ui": "ui.dart"
-''');
-
- PackageMapProcessor proc = new PackageMapProcessor(packageMap);
- expect(proc.embeddedLibraries.size(), 2);
- expect(proc.extendedLibraries.size(), 0);
- expect(proc.libraryMap.size(), 2);
- }
-}
diff --git a/pkg/analyzer/test/src/context/context_test.dart b/pkg/analyzer/test/src/context/context_test.dart
index a2f3cb3..28dceb7 100644
--- a/pkg/analyzer/test/src/context/context_test.dart
+++ b/pkg/analyzer/test/src/context/context_test.dart
@@ -11,11 +11,13 @@
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/dart/element/visitor.dart';
+import 'package:analyzer/file_system/file_system.dart';
import 'package:analyzer/file_system/memory_file_system.dart';
import 'package:analyzer/source/package_map_resolver.dart';
import 'package:analyzer/src/cancelable_future.dart';
import 'package:analyzer/src/context/cache.dart';
import 'package:analyzer/src/context/context.dart';
+import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/scanner/scanner.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
@@ -279,6 +281,26 @@
});
}
+ void test_applyChanges_changedSource_updateModificationTime() {
+ String path = '/test.dart';
+ File file = resourceProvider.newFile(path, 'var V = 1;');
+ Source source = file.createSource();
+ context.applyChanges(new ChangeSet()..addedSource(source));
+ // Analyze all.
+ _analyzeAll_assertFinished();
+ expect(context.analysisCache.getState(source, RESOLVED_UNIT),
+ CacheState.INVALID);
+ // Update the file and notify the context about the change.
+ resourceProvider.updateFile(path, 'var V = 2;');
+ context.applyChanges(new ChangeSet()..changedSource(source));
+ // The analysis results are invalidated.
+ // We have seen the new contents, so 'modificationTime' is also updated.
+ expect(context.analysisCache.getState(source, RESOLVED_UNIT),
+ CacheState.INVALID);
+ expect(
+ context.getCacheEntry(source).modificationTime, file.modificationStamp);
+ }
+
void test_applyChanges_empty() {
context.applyChanges(new ChangeSet());
expect(context.performAnalysisTask().changeNotices, isNull);
@@ -401,7 +423,6 @@
expect(context.getResolvedCompilationUnit2(source, source), unit);
// remove overlay
context.setContents(source, null);
- context.validateCacheConsistency();
_analyzeAll_assertFinished();
expect(context.getResolvedCompilationUnit2(source, source), unit);
}
@@ -434,6 +455,50 @@
});
}
+ void test_cacheConsistencyValidator_computed() {
+ CacheConsistencyValidator validator = context.cacheConsistencyValidator;
+ // Add sources.
+ MemoryResourceProvider resourceProvider = new MemoryResourceProvider();
+ String path1 = '/test1.dart';
+ String path2 = '/test2.dart';
+ Source source1 = resourceProvider.newFile(path1, '// 1-1').createSource();
+ Source source2 = resourceProvider.newFile(path2, '// 2-1').createSource();
+ context.applyChanges(
+ new ChangeSet()..addedSource(source1)..addedSource(source2));
+ // Same modification times.
+ expect(
+ validator.sourceModificationTimesComputed([source1, source2],
+ [source1.modificationStamp, source2.modificationStamp]),
+ isFalse);
+ // Add overlay
+ context.setContents(source1, '// 1-2');
+ expect(
+ validator.sourceModificationTimesComputed([source1, source2],
+ [source1.modificationStamp + 1, source2.modificationStamp]),
+ isFalse);
+ context.setContents(source1, null);
+ // Different modification times.
+ expect(
+ validator.sourceModificationTimesComputed([source1, source2],
+ [source1.modificationStamp + 1, source2.modificationStamp]),
+ isTrue);
+ }
+
+ void test_cacheConsistencyValidator_getSources() {
+ CacheConsistencyValidator validator = context.cacheConsistencyValidator;
+ // Add sources.
+ MemoryResourceProvider resourceProvider = new MemoryResourceProvider();
+ String path1 = '/test1.dart';
+ String path2 = '/test2.dart';
+ Source source1 = resourceProvider.newFile(path1, '// 1-1').createSource();
+ Source source2 = resourceProvider.newFile(path2, '// 2-1').createSource();
+ context.applyChanges(
+ new ChangeSet()..addedSource(source1)..addedSource(source2));
+ // Verify.
+ expect(validator.getSourcesToComputeModificationTimes(),
+ unorderedEquals([source1, source2]));
+ }
+
void test_computeDocumentationComment_class_block() {
String comment = "/** Comment */";
Source source = addSource(
@@ -2079,7 +2144,7 @@
if (context.analysisOptions.finerGrainedInvalidation) {
expect(source.readCount, 7);
} else {
- expect(source.readCount, 4);
+ expect(source.readCount, 5);
}
}
@@ -2561,24 +2626,13 @@
* Perform analysis tasks up to 512 times and assert that it was enough.
*/
void _analyzeAll_assertFinished([int maxIterations = 512]) {
- bool finishedAnalyzing = false;
for (int i = 0; i < maxIterations; i++) {
List<ChangeNotice> notice = context.performAnalysisTask().changeNotices;
if (notice == null) {
- finishedAnalyzing = true;
- bool inconsistent = context.validateCacheConsistency();
- if (!inconsistent) {
- return;
- }
+ return;
}
}
- if (finishedAnalyzing) {
- fail(
- "performAnalysisTask failed to finish analyzing all sources after $maxIterations iterations");
- } else {
- fail(
- "performAnalysisTask failed to terminate after analyzing all sources");
- }
+ fail("performAnalysisTask failed to terminate after analyzing all sources");
}
void _assertNoExceptions() {
@@ -2675,6 +2729,49 @@
context.analysisOptions = options;
}
+ void test_class_addMethod_useAsHole_inTopLevelVariable() {
+ Source a = addSource(
+ '/a.dart',
+ r'''
+class A {
+}
+''');
+ Source b = addSource(
+ '/b.dart',
+ r'''
+import 'a.dart';
+var B = A.foo;
+''');
+ Source c = addSource(
+ '/c.dart',
+ r'''
+import 'b.dart';
+var C = B;
+''');
+ _performPendingAnalysisTasks();
+ expect(context.getErrors(b).errors, hasLength(1));
+ // Update a.dart: add A.foo.
+ // 'B' in b.dart is invalid, because 'B' references 'foo'
+ // c.dart is invalid, because 'C' references 'B'
+ context.setContents(
+ a,
+ r'''
+class A {
+ static void foo(int p) {}
+}
+''');
+ _assertValidForChangedLibrary(a);
+ _assertInvalid(a, LIBRARY_ERRORS_READY);
+
+ _assertValidForDependentLibrary(b);
+ _assertInvalid(b, LIBRARY_ERRORS_READY);
+ _assertInvalidUnits(b, RESOLVED_UNIT4);
+
+ _assertValidForDependentLibrary(c);
+ _assertInvalid(c, LIBRARY_ERRORS_READY);
+ _assertInvalidUnits(c, RESOLVED_UNIT4);
+ }
+
void test_class_addMethod_useClass() {
Source a = addSource(
'/a.dart',
@@ -2709,6 +2806,182 @@
_assertValid(b, LIBRARY_ERRORS_READY);
}
+ void test_class_constructor_named_changeName() {
+ // Update a.dart: change A.named() to A.named2().
+ // b.dart is invalid, because it references A.named().
+ _verifyTwoLibrariesInvalidatesResolution(
+ r'''
+class A {
+ A.named();
+}
+''',
+ r'''
+class A {
+ A.named2();
+}
+''',
+ r'''
+import 'a.dart';
+main() {
+ new A.named();
+}
+''');
+ }
+
+ void test_class_constructor_named_parameters_add() {
+ // Update a.dart: add a new parameter to A.named().
+ // b.dart is invalid, because it references A.named().
+ _verifyTwoLibrariesInvalidatesResolution(
+ r'''
+class A {
+ A.named();
+}
+''',
+ r'''
+class A {
+ A.named(int p);
+}
+''',
+ r'''
+import 'a.dart';
+main() {
+ new A.named();
+}
+''');
+ }
+
+ void test_class_constructor_named_parameters_remove() {
+ // Update a.dart: remove a new parameter of A.named().
+ // b.dart is invalid, because it references A.named().
+ _verifyTwoLibrariesInvalidatesResolution(
+ r'''
+class A {
+ A.named(int p);
+}
+''',
+ r'''
+class A {
+ A.named();
+}
+''',
+ r'''
+import 'a.dart';
+main() {
+ new A.named();
+}
+''');
+ }
+
+ void test_class_constructor_named_remove_notUsed() {
+ // Update a.dart: remove A.foo().
+ // b.dart is valid, because it does not reference A.foo().
+ _verifyTwoLibrariesAllValid(
+ r'''
+class A {
+ A.foo();
+ A.bar();
+}
+''',
+ r'''
+class A {
+ A.bar();
+}
+''',
+ r'''
+import 'a.dart';
+main() {
+ new A.bar();
+}
+''');
+ }
+
+ void test_class_constructor_named_remove_used() {
+ // Update a.dart: remove A.named().
+ // b.dart is invalid, because it references A.named().
+ _verifyTwoLibrariesInvalidatesResolution(
+ r'''
+class A {
+ A.named();
+}
+''',
+ r'''
+class A {
+}
+''',
+ r'''
+import 'a.dart';
+main() {
+ new A.named();
+}
+''');
+ }
+
+ void test_class_constructor_unnamed_parameters_remove() {
+ // Update a.dart: change A().
+ // b.dart is invalid, because it references A().
+ _verifyTwoLibrariesInvalidatesResolution(
+ r'''
+class A {
+ A(int a, int b);
+}
+''',
+ r'''
+class A {
+ A(int a);
+}
+''',
+ r'''
+import 'a.dart';
+main() {
+ new A(1, 2);
+}
+''');
+ }
+
+ void test_class_constructor_unnamed_remove_notUsed() {
+ // Update a.dart: remove A().
+ // b.dart is invalid, because it instantiates A.
+ _verifyTwoLibrariesInvalidatesResolution(
+ r'''
+class A {
+ A();
+ A.named();
+}
+''',
+ r'''
+class A {
+ A.named();
+}
+''',
+ r'''
+import 'a.dart';
+main() {
+ new A.named();
+}
+''');
+ }
+
+ void test_class_constructor_unnamed_remove_used() {
+ // Update a.dart: remove A.named().
+ // b.dart is invalid, because it references A.named().
+ _verifyTwoLibrariesInvalidatesResolution(
+ r'''
+class A {
+ A();
+}
+''',
+ r'''
+class A {
+}
+''',
+ r'''
+import 'a.dart';
+main() {
+ new A();
+}
+''');
+ }
+
void test_class_method_change_notUsed() {
Source a = addSource(
'/a.dart',
@@ -2816,6 +3089,88 @@
_assertInvalid(b, LIBRARY_ERRORS_READY);
}
+ void test_class_method_remove_notUsed_instantiated() {
+ Source a = addSource(
+ '/a.dart',
+ r'''
+abstract class I {
+ void foo();
+}
+class A implements I {
+ void foo() {}
+}
+''');
+ Source b = addSource(
+ '/b.dart',
+ r'''
+import 'a.dart';
+main() {
+ new A();
+}
+''');
+ _performPendingAnalysisTasks();
+ // Update a.dart: remove 'A.foo'.
+ // b.dart is valid because it does not reference 'foo'.
+ // The class 'A' has a warning, but it is still not abstract.
+ context.setContents(
+ a,
+ r'''
+abstract class I {
+ void fo();
+}
+class A implements I {
+}
+''');
+ _assertValidForChangedLibrary(a);
+ _assertInvalid(a, LIBRARY_ERRORS_READY);
+
+ _assertValidForDependentLibrary(b);
+ _assertValidAllLibraryUnitResults(b);
+ _assertValidAllResolution(b);
+ _assertValidAllErrors(b);
+ }
+
+ void test_class_method_remove_subclass() {
+ Source a = addSource(
+ '/a.dart',
+ r'''
+abstract class I {
+ void foo();
+}
+class A implements I {
+ void foo() {}
+}
+''');
+ Source b = addSource(
+ '/b.dart',
+ r'''
+import 'a.dart';
+class B extends A {}
+''');
+ _performPendingAnalysisTasks();
+ // Update a.dart: remove A.bar, add A.bar2.
+ // b.dart
+ // Resolution is valid because 'foo' is not referenced.
+ // HINTS are invalid because 'B' might have invalid @override.
+ // VERIFY_ERRORS are invalid because 'B' might not implement something.
+ // Other errors are also invalid.
+ context.setContents(
+ a,
+ r'''
+abstract class I {
+ void foo();
+}
+class A implements I {
+}
+''');
+ _assertValidForChangedLibrary(a);
+ _assertInvalid(a, LIBRARY_ERRORS_READY);
+
+ _assertValidForDependentLibrary(b);
+ _assertValidAllResolution(b);
+ _assertInvalidHintsVerifyErrors(b);
+ }
+
void test_class_private_member() {
Source a = addSource(
'/a.dart',
@@ -2865,52 +3220,27 @@
_assertValid(b, LIBRARY_ERRORS_READY);
}
- void test_class_super_makeAbstract_instantiate() {
+ void test_enum_add() {
Source a = addSource(
'/a.dart',
r'''
-abstract class I {
- void m();
-}
-class A implements I {
- void m() {}
-}
-''');
- Source b = addSource(
- '/b.dart',
- r'''
-import 'a.dart';
-class B extends A {}
-''');
- Source c = addSource(
- '/c.dart',
- r'''
-import 'b.dart';
main() {
- new B();
+ print(MyEnum.A);
}
''');
_performPendingAnalysisTasks();
- // Update a.dart: remove A.bar, add A.bar2.
- // b.dart is valid, because it doesn't references 'bar' or 'bar2'.
+ // Insert a new enum declaration.
+ // No errors expected.
context.setContents(
a,
r'''
-abstract class I {
- void m();
+main() {
+ print(MyEnum.A);
}
-class A implements I {
- void m2() {}
-}
+enum MyEnum { A, B, C }
''');
- _assertValidForChangedLibrary(a);
- _assertInvalid(a, LIBRARY_ERRORS_READY);
-
- _assertValidForDependentLibrary(b);
- _assertInvalid(b, LIBRARY_ERRORS_READY);
-
- _assertValidForDependentLibrary(c);
- _assertInvalid(c, LIBRARY_ERRORS_READY);
+ _performPendingAnalysisTasks();
+ expect(context.getErrors(a).errors, isEmpty);
}
void test_private_class() {
@@ -3005,6 +3335,72 @@
_assertInvalid(b, LIBRARY_ERRORS_READY);
}
+ void test_sequence_add_annotation() {
+ Source a = addSource(
+ '/a.dart',
+ r'''
+const myAnnotation = const Object();
+class A {}
+''');
+ _performPendingAnalysisTasks();
+ // Add a new annotation.
+ context.setContents(
+ a,
+ r'''
+const myAnnotation = const Object();
+@myAnnotation
+class A {}
+''');
+ _assertValidForChangedLibrary(a);
+ _assertInvalid(a, LIBRARY_ERRORS_READY);
+ // Analysis is done successfully.
+ _performPendingAnalysisTasks();
+ _assertValid(a, LIBRARY_ERRORS_READY);
+ _assertValid(a, READY_RESOLVED_UNIT);
+ }
+
+ void test_sequence_applyChanges_changedSource() {
+ Source a = addSource(
+ '/a.dart',
+ r'''
+class A {}
+class B {}
+''');
+ Source b = addSource(
+ '/b.dart',
+ r'''
+import 'a.dart';
+main() {
+ new A();
+ new B();
+}
+''');
+ _performPendingAnalysisTasks();
+ resourceProvider.updateFile(
+ '/a.dart',
+ r'''
+class A2 {}
+class B {}
+''');
+ // Update a.dart: remove A, add A2.
+ // b.dart is invalid, because it references A.
+ var changeSet = new ChangeSet()..changedSource(a);
+ context.applyChanges(changeSet);
+ _assertValidForChangedLibrary(a);
+ _assertInvalid(a, LIBRARY_ERRORS_READY);
+ _assertValidForDependentLibrary(b);
+ _assertInvalid(b, LIBRARY_ERRORS_READY);
+ _assertInvalidUnits(b, RESOLVED_UNIT4);
+ // Analyze.
+ _performPendingAnalysisTasks();
+ expect(context.getErrors(a).errors, hasLength(0));
+ expect(context.getErrors(b).errors, hasLength(1));
+ _assertValid(a, READY_RESOLVED_UNIT);
+ _assertValid(b, READY_RESOLVED_UNIT);
+ _assertValidAllLibraryUnitResults(a);
+ _assertValidAllLibraryUnitResults(b);
+ }
+
void test_sequence_class_give_take() {
Source a = addSource(
'/a.dart',
@@ -3060,6 +3456,252 @@
expect(context.getErrors(b).errors, hasLength(1));
}
+ void test_sequence_class_removeMethod_overridden() {
+ Source a = addSource(
+ '/a.dart',
+ r'''
+class A {
+ void foo() {}
+}
+''');
+ Source b = addSource(
+ '/b.dart',
+ r'''
+import 'a.dart';
+class B extends A {
+ @override
+ void foo() {}
+}
+''');
+ _performPendingAnalysisTasks();
+ expect(context.getErrors(b).errors, hasLength(0));
+ // Update a.dart: remove add A.foo.
+ // b.dart has a new hint, because B.foo does not override anything
+ context.setContents(
+ a,
+ r'''
+class A {
+}
+''');
+ _assertValidForChangedLibrary(a);
+ _assertInvalid(a, LIBRARY_ERRORS_READY);
+ _assertValidForDependentLibrary(b);
+ _assertValidAllResolution(b);
+ _assertInvalidHintsVerifyErrors(b);
+
+ _performPendingAnalysisTasks();
+ expect(context.getErrors(b).errors, hasLength(1));
+ }
+
+ void test_sequence_closureParameterTypesPropagation() {
+ Source a = addSource(
+ '/a.dart',
+ r'''
+main() {
+ f((p) => 4.2);
+}
+f(c(int p)) {}
+''');
+ _performPendingAnalysisTasks();
+ LibrarySpecificUnit targetA = new LibrarySpecificUnit(a, a);
+ // Update and analyze.
+ String newCode = r'''
+newFunction() {}
+main() {
+ f((p) => 4.2);
+}
+f(c(int p)) {}
+''';
+ context.setContents(a, newCode);
+ _performPendingAnalysisTasks();
+ // Validate "(p) => 4.2" types.
+ CompilationUnit unit = context.getResult(targetA, RESOLVED_UNIT2);
+ SimpleIdentifier parameterName =
+ EngineTestCase.findSimpleIdentifier(unit, newCode, 'p) => 4.2);');
+ expect(parameterName.staticType, context.typeProvider.dynamicType);
+ expect(parameterName.propagatedType, context.typeProvider.intType);
+ }
+
+ void test_sequence_dependenciesWithCycles() {
+ Source a = addSource(
+ '/a.dart',
+ r'''
+const A = 1;
+''');
+ Source b = addSource(
+ '/b.dart',
+ r'''
+import 'c.dart';
+const B = C1 + 1;
+''');
+ Source c = addSource(
+ '/c.dart',
+ r'''
+import 'a.dart';
+import 'b.dart';
+const C1 = A + 1;
+const C2 = B + 2;
+''');
+ Source d = addSource(
+ '/d.dart',
+ r'''
+import 'c.dart';
+const D = C2 + 1;
+''');
+ _performPendingAnalysisTasks();
+ // Update "A" constant.
+ // This should invalidate results in all sources.
+ context.setContents(
+ a,
+ r'''
+const A = 2;
+''');
+ _assertInvalid(a, LIBRARY_ERRORS_READY);
+ _assertInvalid(b, LIBRARY_ERRORS_READY);
+ _assertInvalid(c, LIBRARY_ERRORS_READY);
+ _assertInvalid(d, LIBRARY_ERRORS_READY);
+ }
+
+ void test_sequence_inBodyChange_addRef_deltaChange() {
+ Source a = addSource(
+ '/a.dart',
+ r'''
+class A {
+}
+''');
+ Source b = addSource(
+ '/b.dart',
+ r'''
+import 'a.dart';
+main(A a) {
+}
+''');
+ _performPendingAnalysisTasks();
+ expect(context.getErrors(b).errors, hasLength(0));
+ // Update b.dart: in-body incremental change - start referencing 'foo'.
+ // Should update referenced names.
+ context.setContents(
+ b,
+ r'''
+import 'a.dart';
+main(A a) {
+ a.foo;
+}
+''');
+ _performPendingAnalysisTasks();
+ expect(context.getErrors(b).errors, hasLength(1));
+ // Update a.dart: add A.foo
+ // b.dart is invalid, because it references 'foo'.
+ context.setContents(
+ a,
+ r'''
+class A {
+ int foo;
+}
+''');
+ _assertValidForChangedLibrary(a);
+ _assertInvalid(a, LIBRARY_ERRORS_READY);
+ _assertValidForDependentLibrary(b);
+ _assertInvalid(b, LIBRARY_ERRORS_READY);
+ _assertInvalidUnits(b, RESOLVED_UNIT4);
+ // No errors after analysis.
+ _performPendingAnalysisTasks();
+ expect(context.getErrors(b).errors, hasLength(0));
+ }
+
+ void test_sequence_inBodyChange_removeRef_deltaChange() {
+ Source a = addSource(
+ '/a.dart',
+ r'''
+class A {
+}
+''');
+ Source b = addSource(
+ '/b.dart',
+ r'''
+import 'a.dart';
+main(A a) {
+ a.foo;
+}
+''');
+ _performPendingAnalysisTasks();
+ expect(context.getErrors(b).errors, hasLength(1));
+ // Update b.dart: in-body incremental change - stop referencing 'foo'.
+ // Should update referenced names.
+ context.setContents(
+ b,
+ r'''
+import 'a.dart';
+main(A a) {
+}
+''');
+ _performPendingAnalysisTasks();
+ expect(context.getErrors(b).errors, hasLength(0));
+ // Update a.dart: add A.foo
+ // b.dart is still valid, because it does references 'foo' anymore.
+ context.setContents(
+ a,
+ r'''
+class A {
+ int foo;
+}
+''');
+ _assertValidForChangedLibrary(a);
+ _assertInvalid(a, LIBRARY_ERRORS_READY);
+ _assertValidForDependentLibrary(b);
+ _assertValidAllLibraryUnitResults(b);
+ _assertValid(b, LIBRARY_ERRORS_READY);
+ }
+
+ void test_sequence_middleLimited_thenFirstFull() {
+ Source a = addSource(
+ '/a.dart',
+ r'''
+class A {}
+''');
+ Source b = addSource(
+ '/b.dart',
+ r'''
+export 'a.dart';
+''');
+ Source c = addSource(
+ '/c.dart',
+ r'''
+import 'b.dart';
+A a;
+''');
+ _performPendingAnalysisTasks();
+ // Update b.dart: limited invalidation.
+ // Results in c.dart are valid, because the change in b.dart does not
+ // affect anything in c.dart.
+ context.setContents(
+ b,
+ r'''
+export 'a.dart';
+class B {}
+''');
+ _assertValid(a, LIBRARY_ERRORS_READY);
+ _assertInvalid(b, LIBRARY_ERRORS_READY);
+ _assertValid(c, LIBRARY_ERRORS_READY);
+ _assertUnitValid(c, RESOLVED_UNIT4);
+ _assertUnitValid(c, RESOLVED_UNIT5);
+ // Update a.dart: unlimited invalidation.
+ // Results RESOLVED_UNIT4, RESOLVED_UNIT5, and RESOLVED_UNIT6 in c.dart
+ // are invalid, because after unlimited change to a.dart everything
+ // should be invalidated.
+ // This fixes the problem that c.dart was not re-resolving type names.
+ context.setContents(
+ a,
+ r'''
+import 'dart:async';
+class A {}
+''');
+ _assertInvalid(a, LIBRARY_ERRORS_READY);
+ _assertInvalid(b, LIBRARY_ERRORS_READY);
+ _assertInvalid(c, LIBRARY_ERRORS_READY);
+ _assertInvalidUnits(c, RESOLVED_UNIT4);
+ }
+
void test_sequence_noChange_thenChange() {
Source a = addSource(
'/a.dart',
@@ -3138,8 +3780,8 @@
_assertValidForChangedLibrary(a);
_assertInvalid(a, LIBRARY_ERRORS_READY);
_assertValidForDependentLibrary(b);
- _assertInvalid(b, LIBRARY_ERRORS_READY);
- _assertInvalidUnits(b, RESOLVED_UNIT4);
+ _assertValidAllResolution(b);
+ _assertValidAllErrors(b);
// The a.dart's unit and element are the same.
{
LibrarySpecificUnit target = new LibrarySpecificUnit(a, a);
@@ -3153,6 +3795,136 @@
expect(context.getErrors(b).errors, hasLength(0));
}
+ void test_sequence_reorder_localFunctions() {
+ Source a = addSource(
+ '/a.dart',
+ r'''
+f1() {
+ localFunction() {
+ const C = 1;
+ }
+}
+f2() {}
+''');
+ _performPendingAnalysisTasks();
+ // Update a.dart: reorder functions.
+ // This should not fail with FrozenHashCodeException, because identifiers
+ // of local elements should be relative to the enclosing top-level elements.
+ context.setContents(
+ a,
+ r'''
+f2() {}
+f1() {
+ localFunction() {
+ const C = 1;
+ }
+}
+''');
+ _assertValidForChangedLibrary(a);
+ _assertInvalid(a, LIBRARY_ERRORS_READY);
+ }
+
+ void test_sequence_unitConstants_addRemove() {
+ Source a = addSource(
+ '/a.dart',
+ r'''
+const A = 1;
+const B = 2;
+const C = 3;
+foo() {
+ const V1 = 10;
+}
+bar() {
+ const V2 = 20;
+}
+''');
+ _performPendingAnalysisTasks();
+ LibrarySpecificUnit unitA = new LibrarySpecificUnit(a, a);
+ List<ConstantEvaluationTarget> oldConstants =
+ context.getResult(unitA, COMPILATION_UNIT_CONSTANTS);
+ expect(oldConstants, hasLength(5));
+ ConstVariableElement oldA = _findConstVariable(oldConstants, 'A');
+ ConstVariableElement oldB = _findConstVariable(oldConstants, 'B');
+ ConstVariableElement oldC = _findConstVariable(oldConstants, 'C');
+ ConstVariableElement oldV1 = _findConstVariable(oldConstants, 'V1');
+ ConstVariableElement oldV2 = _findConstVariable(oldConstants, 'V2');
+ expect(context.analysisCache.get(oldA), isNotNull);
+ expect(context.analysisCache.get(oldB), isNotNull);
+ expect(context.analysisCache.get(oldC), isNotNull);
+ expect(context.analysisCache.get(oldV1), isNotNull);
+ // Update and validate new constants.
+ context.setContents(
+ a,
+ r'''
+const A = 1;
+const B = 2;
+const D = 4;
+foo() {
+ const V1 = 10;
+}
+baz() {
+ const V3 = 30;
+}
+''');
+ List<ConstantEvaluationTarget> newConstants =
+ context.getResult(unitA, COMPILATION_UNIT_CONSTANTS);
+ expect(newConstants, hasLength(5));
+ expect(newConstants, contains(same(oldA)));
+ expect(newConstants, contains(same(oldB)));
+ expect(newConstants, contains(same(oldV1)));
+ ConstVariableElement newD = _findConstVariable(newConstants, 'D');
+ ConstVariableElement newV3 = _findConstVariable(newConstants, 'V3');
+ // Perform analysis, compute constant values.
+ _performPendingAnalysisTasks();
+ // Validate const variable values.
+ expect(context.analysisCache.get(oldA), isNotNull);
+ expect(context.analysisCache.get(oldB), isNotNull);
+ expect(context.analysisCache.get(oldV1), isNotNull);
+ expect(context.analysisCache.get(oldC), isNull);
+ expect(context.analysisCache.get(oldV2), isNull);
+ expect(context.analysisCache.get(newD), isNotNull);
+ expect(context.analysisCache.get(newV3), isNotNull);
+ expect(oldA.evaluationResult.value.toIntValue(), 1);
+ expect(oldB.evaluationResult.value.toIntValue(), 2);
+ expect(newD.evaluationResult.value.toIntValue(), 4);
+ expect(oldV1.evaluationResult.value.toIntValue(), 10);
+ expect(newV3.evaluationResult.value.toIntValue(), 30);
+ }
+
+ void test_sequence_unitConstants_local_insertSpace() {
+ Source a = addSource(
+ '/a.dart',
+ r'''
+main() {
+ const C = 1;
+}
+''');
+ _performPendingAnalysisTasks();
+ LibrarySpecificUnit unitA = new LibrarySpecificUnit(a, a);
+ List<ConstantEvaluationTarget> oldConstants =
+ context.getResult(unitA, COMPILATION_UNIT_CONSTANTS);
+ expect(oldConstants, hasLength(1));
+ ConstVariableElement C = _findConstVariable(oldConstants, 'C');
+ expect(context.analysisCache.get(C), isNotNull);
+ // Insert a space before the name.
+ context.setContents(
+ a,
+ r'''
+main() {
+ const C = 1;
+}
+''');
+ List<ConstantEvaluationTarget> newConstants =
+ context.getResult(unitA, COMPILATION_UNIT_CONSTANTS);
+ expect(newConstants, hasLength(1));
+ expect(newConstants, contains(same(C)));
+ // Perform analysis, compute constant values.
+ _performPendingAnalysisTasks();
+ // Validate const variable values.
+ expect(context.analysisCache.get(C), isNotNull);
+ expect(C.evaluationResult.value.toIntValue(), 1);
+ }
+
void test_sequence_useAnyResolvedUnit() {
Source a = addSource(
'/a.dart',
@@ -3408,8 +4180,8 @@
''');
_performPendingAnalysisTasks();
// Update a.dart: remove A.m, add A.m2.
- // b.dart is invalid, because B extends A.
- // c.dart is invalid, because 'main' references B.
+ // b.dart has valid resolution, and invalid errors.
+ // c.dart is invalid, because 'main' references 'm'.
context.setContents(
a,
r'''
@@ -3421,9 +4193,8 @@
_assertInvalid(a, LIBRARY_ERRORS_READY);
_assertValidForDependentLibrary(b);
- _assertInvalidLibraryElements(b, LIBRARY_ELEMENT4);
- _assertInvalidUnits(b, RESOLVED_UNIT4);
- _assertInvalid(b, LIBRARY_ERRORS_READY);
+ _assertValidAllResolution(b);
+ _assertInvalidHintsVerifyErrors(b);
_assertValidForDependentLibrary(c);
_assertInvalidLibraryElements(c, LIBRARY_ELEMENT5);
@@ -3471,12 +4242,9 @@
''');
_assertInvalid(a, LIBRARY_ERRORS_READY);
- // TODO(scheglov) In theory b.dart is not affected, because it does not
- // call A.m, does not override it, etc.
_assertValidForDependentLibrary(b);
- _assertInvalidLibraryElements(b, LIBRARY_ELEMENT4);
- _assertInvalidUnits(b, RESOLVED_UNIT4);
- _assertInvalid(b, LIBRARY_ERRORS_READY);
+ _assertValidAllResolution(b);
+ _assertInvalidHintsVerifyErrors(b);
_assertValidForDependentLibrary(c);
_assertInvalidLibraryElements(c, LIBRARY_ELEMENT5);
@@ -3492,6 +4260,18 @@
}
/**
+ * Assert that [VERIFY_ERRORS] and other error results that include it,
+ * are invalid.
+ */
+ void _assertInvalidHintsVerifyErrors(Source unit) {
+ _assertUnitInvalid(unit, HINTS);
+ _assertUnitInvalid(unit, VERIFY_ERRORS);
+ _assertUnitInvalid(unit, LIBRARY_UNIT_ERRORS);
+ _assertInvalid(unit, DART_ERRORS);
+ _assertInvalid(unit, LIBRARY_ERRORS_READY);
+ }
+
+ /**
* Assert that [LIBRARY_ELEMENT_RESULTS] for [first] and after it are invalid.
*/
void _assertInvalidLibraryElements(
@@ -3545,6 +4325,18 @@
reason: '$descriptor in $target');
}
+ /**
+ * Assert that all error results for the given [unit] are valid.
+ */
+ void _assertValidAllErrors(Source unit) {
+ for (ListResultDescriptor<AnalysisError> result in ERROR_SOURCE_RESULTS) {
+ _assertValid(unit, result);
+ }
+ for (ListResultDescriptor<AnalysisError> result in ERROR_UNIT_RESULTS) {
+ _assertUnitValid(unit, result);
+ }
+ }
+
void _assertValidAllLibraryUnitResults(Source source, {Source library}) {
for (ResultDescriptor<LibraryElement> result in LIBRARY_ELEMENT_RESULTS) {
_assertValid(source, result);
@@ -3556,6 +4348,14 @@
}
}
+ void _assertValidAllResolution(Source unit) {
+ _assertValidUnits(unit, null);
+ _assertUnitValidTaskResults(unit, ResolveUnitTypeNamesTask.DESCRIPTOR);
+ _assertUnitValidTaskResults(unit, ResolveUnitTask.DESCRIPTOR);
+ _assertValidTaskResults(unit, ResolveLibraryReferencesTask.DESCRIPTOR);
+ _assertValidTaskResults(unit, ResolveLibraryTask.DESCRIPTOR);
+ }
+
void _assertValidForAnyLibrary(Source source) {
// Source results.
_assertValidTaskResults(source, ScanDartTask.DESCRIPTOR);
@@ -3589,6 +4389,25 @@
}
}
+ void _assertValidUnits(Source unit, ResultDescriptor<CompilationUnit> last,
+ {Source library}) {
+ var target = new LibrarySpecificUnit(library ?? unit, unit);
+ bool foundLast = false;
+ for (ResultDescriptor<CompilationUnit> result in RESOLVED_UNIT_RESULTS) {
+ if (!foundLast) {
+ _assertValid(target, result);
+ }
+ foundLast = foundLast || result == last;
+ }
+ }
+
+ ConstVariableElement _findConstVariable(
+ List<ConstantEvaluationTarget> constants, String name) {
+ return constants.singleWhere((c) {
+ return c is ConstVariableElement && c.name == name;
+ });
+ }
+
void _performPendingAnalysisTasks([int maxTasks = 512]) {
for (int i = 0; context.performAnalysisTask().hasMoreWork; i++) {
if (i > maxTasks) {
@@ -3596,6 +4415,32 @@
}
}
}
+
+ void _verifyTwoLibrariesAllValid(
+ String firstCodeA, String secondCodeA, String codeB) {
+ Source a = addSource('/a.dart', firstCodeA);
+ Source b = addSource('/b.dart', codeB);
+ _performPendingAnalysisTasks();
+ context.setContents(a, secondCodeA);
+ _assertValidForChangedLibrary(a);
+ _assertInvalid(a, LIBRARY_ERRORS_READY);
+ _assertValidForDependentLibrary(b);
+ _assertValidAllResolution(b);
+ _assertValidAllErrors(b);
+ }
+
+ void _verifyTwoLibrariesInvalidatesResolution(
+ String firstCodeA, String secondCodeA, String codeB) {
+ Source a = addSource('/a.dart', firstCodeA);
+ Source b = addSource('/b.dart', codeB);
+ _performPendingAnalysisTasks();
+ context.setContents(a, secondCodeA);
+ _assertValidForChangedLibrary(a);
+ _assertInvalid(a, LIBRARY_ERRORS_READY);
+ _assertValidForDependentLibrary(b);
+ _assertInvalid(b, LIBRARY_ERRORS_READY);
+ _assertInvalidUnits(b, RESOLVED_UNIT4);
+ }
}
class _AnalysisContextImplTest_Source_exists_true extends TestSource {
diff --git a/pkg/analyzer/test/src/context/test_all.dart b/pkg/analyzer/test/src/context/test_all.dart
index 33c2986..d0f1619 100644
--- a/pkg/analyzer/test/src/context/test_all.dart
+++ b/pkg/analyzer/test/src/context/test_all.dart
@@ -9,7 +9,6 @@
import '../../utils.dart';
import 'builder_test.dart' as builder_test;
import 'cache_test.dart' as cache_test;
-import 'context_factory_test.dart' as context_factory_test;
import 'context_test.dart' as context_test;
/// Utility for manually running all tests.
@@ -18,7 +17,6 @@
group('context tests', () {
builder_test.main();
cache_test.main();
- context_factory_test.main();
context_test.main();
});
}
diff --git a/pkg/analyzer/test/src/dart/constant/evaluation_test.dart b/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
index 960726e..cf6d9cd 100644
--- a/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
+++ b/pkg/analyzer/test/src/dart/constant/evaluation_test.dart
@@ -275,7 +275,7 @@
analysisContext.computeErrors(source);
expect(unit, isNotNull);
ConstantValueComputer computer = _makeConstantValueComputer();
- computer.add(unit, source, source);
+ computer.add(unit);
computer.computeValues();
NodeList<CompilationUnitMember> members = unit.declarations;
expect(members, hasLength(3));
@@ -296,7 +296,7 @@
analysisContext.resolveCompilationUnit(source, libraryElement);
expect(unit, isNotNull);
ConstantValueComputer computer = _makeConstantValueComputer();
- computer.add(unit, source, source);
+ computer.add(unit);
computer.computeValues();
NodeList<CompilationUnitMember> members = unit.declarations;
expect(members, hasLength(2));
@@ -331,8 +331,8 @@
analysisContext.resolveCompilationUnit(partSource, libraryElement);
expect(partUnit, isNotNull);
ConstantValueComputer computer = _makeConstantValueComputer();
- computer.add(libraryUnit, librarySource, librarySource);
- computer.add(partUnit, partSource, librarySource);
+ computer.add(libraryUnit);
+ computer.add(partUnit);
computer.computeValues();
NodeList<CompilationUnitMember> libraryMembers = libraryUnit.declarations;
expect(libraryMembers, hasLength(2));
@@ -353,7 +353,7 @@
analysisContext.resolveCompilationUnit(source, libraryElement);
expect(unit, isNotNull);
ConstantValueComputer computer = _makeConstantValueComputer();
- computer.add(unit, source, source);
+ computer.add(unit);
computer.computeValues();
NodeList<CompilationUnitMember> members = unit.declarations;
expect(members, hasLength(1));
@@ -370,7 +370,7 @@
analysisContext.resolveCompilationUnit(source, libraryElement);
expect(unit, isNotNull);
ConstantValueComputer computer = _makeConstantValueComputer();
- computer.add(unit, source, source);
+ computer.add(unit);
computer.computeValues();
TopLevelVariableDeclaration declaration = unit.declarations
.firstWhere((member) => member is TopLevelVariableDeclaration);
@@ -1200,7 +1200,7 @@
analysisContext.resolveCompilationUnit(source, element);
expect(unit, isNotNull);
ConstantValueComputer computer = _makeConstantValueComputer();
- computer.add(unit, source, source);
+ computer.add(unit);
computer.computeValues();
assertErrors(source, expectedErrorCodes);
}
@@ -1380,7 +1380,6 @@
ConstantEvaluationValidator_ForTest validator =
new ConstantEvaluationValidator_ForTest(analysisContext2);
validator.computer = new ConstantValueComputer(
- analysisContext2,
analysisContext2.typeProvider,
analysisContext2.declaredVariables,
validator,
diff --git a/pkg/analyzer/test/src/dart/constant/utilities_test.dart b/pkg/analyzer/test/src/dart/constant/utilities_test.dart
index f4fd958..48443b3 100644
--- a/pkg/analyzer/test/src/dart/constant/utilities_test.dart
+++ b/pkg/analyzer/test/src/dart/constant/utilities_test.dart
@@ -183,7 +183,7 @@
}
List<ConstantEvaluationTarget> _findConstants() {
- ConstantFinder finder = new ConstantFinder(_context, _source, _source);
+ ConstantFinder finder = new ConstantFinder();
_node.accept(finder);
List<ConstantEvaluationTarget> constants = finder.constantsToCompute;
expect(constants, isNotNull);
diff --git a/pkg/analyzer/test/src/dart/element/element_test.dart b/pkg/analyzer/test/src/dart/element/element_test.dart
index a6e718d..b8a61fe 100644
--- a/pkg/analyzer/test/src/dart/element/element_test.dart
+++ b/pkg/analyzer/test/src/dart/element/element_test.dart
@@ -2782,6 +2782,31 @@
expect(parameterTypes[0], same(typeI));
}
+ void test_getMethod_parameterized_flushCached_whenVersionChanges() {
+ //
+ // class A<E> { E m(E p) {} }
+ //
+ ClassElementImpl classA = ElementFactory.classElement2("A", ["E"]);
+ DartType typeE = classA.type.typeArguments[0];
+ String methodName = "m";
+ MethodElementImpl methodM =
+ ElementFactory.methodElement(methodName, typeE, [typeE]);
+ classA.methods = <MethodElement>[methodM];
+ methodM.type = new FunctionTypeImpl(methodM);
+ //
+ // A<I>
+ //
+ InterfaceType typeI = ElementFactory.classElement2("I").type;
+ InterfaceTypeImpl typeAI = new InterfaceTypeImpl(classA);
+ typeAI.typeArguments = <DartType>[typeI];
+ // Methods list is cached.
+ MethodElement method = typeAI.methods.single;
+ expect(typeAI.methods.single, same(method));
+ // Methods list is flushed on version change.
+ classA.version++;
+ expect(typeAI.methods.single, isNot(same(method)));
+ }
+
void test_getMethod_unimplemented() {
//
// class A {}
diff --git a/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart b/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
index 1adaae0..4321f0d 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_ast_test.dart
@@ -157,6 +157,51 @@
@override
@failingTest
+ void test_constructors_inferFromArguments() {
+ // TODO(jmesserly): does this need to be implemented in AST summaries?
+ // The test might need a change as well to not be based on local variable
+ // types, which don't seem to be available.
+ super.test_constructors_inferFromArguments();
+ }
+
+ @override
+ @failingTest
+ void test_constructors_inferFromArguments_const() {
+ super.test_constructors_inferFromArguments_const();
+ }
+
+ @override
+ @failingTest
+ void test_constructors_inferFromArguments_factory() {
+ super.test_constructors_inferFromArguments_factory();
+ }
+
+ @override
+ @failingTest
+ void test_constructors_inferFromArguments_named() {
+ super.test_constructors_inferFromArguments_named();
+ }
+
+ @override
+ @failingTest
+ void test_constructors_inferFromArguments_namedFactory() {
+ super.test_constructors_inferFromArguments_namedFactory();
+ }
+
+ @override
+ @failingTest
+ void test_constructors_inferFromArguments_redirecting() {
+ super.test_constructors_inferFromArguments_redirecting();
+ }
+
+ @override
+ @failingTest
+ void test_constructors_inferFromArguments_redirectingFactory() {
+ super.test_constructors_inferFromArguments_redirectingFactory();
+ }
+
+ @override
+ @failingTest
void test_genericMethods_inferJSBuiltin() {
super.test_genericMethods_inferJSBuiltin();
}
@@ -547,6 +592,72 @@
expect(unit.topLevelVariables[0].type.toString(), 'int');
}
+ @override
+ @failingTest
+ void test_unsafeBlockClosureInference_closureCall() {
+ super.test_unsafeBlockClosureInference_closureCall();
+ }
+
+ @override
+ @failingTest
+ void test_unsafeBlockClosureInference_constructorCall_implicitTypeParam() {
+ super.test_unsafeBlockClosureInference_constructorCall_implicitTypeParam();
+ }
+
+ @override
+ @failingTest
+ void
+ test_unsafeBlockClosureInference_functionCall_explicitDynamicParam_viaExpr2() {
+ super
+ .test_unsafeBlockClosureInference_functionCall_explicitDynamicParam_viaExpr2();
+ }
+
+ @override
+ @failingTest
+ void
+ test_unsafeBlockClosureInference_functionCall_explicitTypeParam_viaExpr2() {
+ super
+ .test_unsafeBlockClosureInference_functionCall_explicitTypeParam_viaExpr2();
+ }
+
+ @override
+ @failingTest
+ void test_unsafeBlockClosureInference_functionCall_implicitTypeParam() {
+ super.test_unsafeBlockClosureInference_functionCall_implicitTypeParam();
+ }
+
+ @override
+ @failingTest
+ void
+ test_unsafeBlockClosureInference_functionCall_implicitTypeParam_viaExpr() {
+ super
+ .test_unsafeBlockClosureInference_functionCall_implicitTypeParam_viaExpr();
+ }
+
+ @override
+ @failingTest
+ void test_unsafeBlockClosureInference_functionCall_noTypeParam_viaExpr() {
+ super.test_unsafeBlockClosureInference_functionCall_noTypeParam_viaExpr();
+ }
+
+ @override
+ @failingTest
+ void test_unsafeBlockClosureInference_inList_untyped() {
+ super.test_unsafeBlockClosureInference_inList_untyped();
+ }
+
+ @override
+ @failingTest
+ void test_unsafeBlockClosureInference_inMap_untyped() {
+ super.test_unsafeBlockClosureInference_inMap_untyped();
+ }
+
+ @override
+ @failingTest
+ void test_unsafeBlockClosureInference_methodCall_implicitTypeParam() {
+ super.test_unsafeBlockClosureInference_methodCall_implicitTypeParam();
+ }
+
LibraryElementImpl _checkSource(
SummaryResynthesizer resynthesizer, Source source) {
LibraryElementImpl resynthesized =
diff --git a/pkg/analyzer/test/src/summary/resynthesize_test.dart b/pkg/analyzer/test/src/summary/resynthesize_test.dart
index 881ad8f..b6e8b30 100644
--- a/pkg/analyzer/test/src/summary/resynthesize_test.dart
+++ b/pkg/analyzer/test/src/summary/resynthesize_test.dart
@@ -692,18 +692,12 @@
compareMetadata(resynthesized.metadata, original.metadata, desc);
// Validate modifiers.
- for (Modifier modifier in Modifier.persistedValues) {
+ for (Modifier modifier in Modifier.values) {
bool got = _hasModifier(resynthesized, modifier);
bool want = _hasModifier(original, modifier);
expect(got, want,
reason: 'Mismatch in $desc.$modifier: got $got, want $want');
}
- for (Modifier modifier in Modifier.transientValues) {
- bool got = rImpl.hasModifier(modifier);
- bool want = false;
- expect(got, false,
- reason: 'Mismatch in $desc.$modifier: got $got, want $want');
- }
// Validate members.
if (oImpl is Member) {
diff --git a/pkg/analyzer/test/src/summary/summary_common.dart b/pkg/analyzer/test/src/summary/summary_common.dart
index a3e2695..d3e94d3 100644
--- a/pkg/analyzer/test/src/summary/summary_common.dart
+++ b/pkg/analyzer/test/src/summary/summary_common.dart
@@ -11,7 +11,6 @@
import 'package:analyzer/src/dart/scanner/scanner.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/error.dart';
-import 'package:analyzer/src/generated/java_engine_io.dart';
import 'package:analyzer/src/generated/parser.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/source_io.dart';
@@ -21,16 +20,17 @@
as public_namespace;
import 'package:analyzer/src/summary/summarize_elements.dart'
as summarize_elements;
+import 'package:path/path.dart' show posix;
import 'package:unittest/unittest.dart';
import '../context/mock_sdk.dart';
/**
- * Convert [path] to a suitably formatted absolute path URI for the current
- * platform.
+ * Convert the given Posix style file [path] to the corresponding absolute URI.
*/
String absUri(String path) {
- return FileUtilities2.createFile(path).toURI().toString();
+ String absolutePath = posix.absolute(path);
+ return posix.toUri(absolutePath).toString();
}
/**
diff --git a/pkg/analyzer/test/src/task/dart_test.dart b/pkg/analyzer/test/src/task/dart_test.dart
index 25a6bef..8c081f7 100644
--- a/pkg/analyzer/test/src/task/dart_test.dart
+++ b/pkg/analyzer/test/src/task/dart_test.dart
@@ -772,11 +772,10 @@
part of lib;
'''
});
- expect(outputs, hasLength(4));
+ expect(outputs, hasLength(3));
// simple outputs
expect(outputs[BUILD_LIBRARY_ERRORS], isEmpty);
expect(outputs[IS_LAUNCHABLE], isFalse);
- expect(outputs[REFERENCED_NAMES], isNotNull);
// LibraryElement output
expect(libraryElement, isNotNull);
expect(libraryElement.entryPoint, isNull);
@@ -3185,7 +3184,7 @@
_performParseTask(r'''
part of lib;
class B {}''');
- expect(outputs, hasLength(10));
+ expect(outputs, hasLength(11));
expect(outputs[EXPLICITLY_IMPORTED_LIBRARIES], hasLength(0));
expect(outputs[EXPORTED_LIBRARIES], hasLength(0));
_assertHasCore(outputs[IMPORTED_LIBRARIES], 1);
@@ -3193,9 +3192,10 @@
expect(outputs[LIBRARY_SPECIFIC_UNITS], hasLength(1));
expect(outputs[PARSE_ERRORS], hasLength(0));
expect(outputs[PARSED_UNIT], isNotNull);
+ expect(outputs[REFERENCED_NAMES], isNotNull);
+ expect(outputs[REFERENCED_SOURCES], hasLength(2));
expect(outputs[SOURCE_KIND], SourceKind.PART);
expect(outputs[UNITS], hasLength(1));
- expect(outputs[REFERENCED_SOURCES], hasLength(2));
}
test_perform_computeSourceKind_noDirectives_hasContainingLibrary() {
@@ -3220,7 +3220,7 @@
test_perform_doesNotExist() {
_performParseTask(null);
- expect(outputs, hasLength(10));
+ expect(outputs, hasLength(11));
expect(outputs[EXPLICITLY_IMPORTED_LIBRARIES], hasLength(0));
expect(outputs[EXPORTED_LIBRARIES], hasLength(0));
_assertHasCore(outputs[IMPORTED_LIBRARIES], 1);
@@ -3228,9 +3228,10 @@
expect(outputs[LIBRARY_SPECIFIC_UNITS], hasLength(1));
expect(outputs[PARSE_ERRORS], hasLength(0));
expect(outputs[PARSED_UNIT], isNotNull);
+ expect(outputs[REFERENCED_NAMES], isNotNull);
+ expect(outputs[REFERENCED_SOURCES], hasLength(2));
expect(outputs[SOURCE_KIND], SourceKind.LIBRARY);
expect(outputs[UNITS], hasLength(1));
- expect(outputs[REFERENCED_SOURCES], hasLength(2));
}
test_perform_enableAsync_false() {
@@ -3240,7 +3241,7 @@
_performParseTask(r'''
import 'dart:async';
class B {void foo() async {}}''');
- expect(outputs, hasLength(10));
+ expect(outputs, hasLength(11));
expect(outputs[EXPLICITLY_IMPORTED_LIBRARIES], hasLength(1));
expect(outputs[EXPORTED_LIBRARIES], hasLength(0));
_assertHasCore(outputs[IMPORTED_LIBRARIES], 2);
@@ -3248,16 +3249,17 @@
expect(outputs[LIBRARY_SPECIFIC_UNITS], hasLength(1));
expect(outputs[PARSE_ERRORS], hasLength(1));
expect(outputs[PARSED_UNIT], isNotNull);
+ expect(outputs[REFERENCED_NAMES], isNotNull);
+ expect(outputs[REFERENCED_SOURCES], hasLength(3));
expect(outputs[SOURCE_KIND], SourceKind.LIBRARY);
expect(outputs[UNITS], hasLength(1));
- expect(outputs[REFERENCED_SOURCES], hasLength(3));
}
test_perform_enableAsync_true() {
_performParseTask(r'''
import 'dart:async';
class B {void foo() async {}}''');
- expect(outputs, hasLength(10));
+ expect(outputs, hasLength(11));
expect(outputs[EXPLICITLY_IMPORTED_LIBRARIES], hasLength(1));
expect(outputs[EXPORTED_LIBRARIES], hasLength(0));
_assertHasCore(outputs[IMPORTED_LIBRARIES], 2);
@@ -3265,9 +3267,10 @@
expect(outputs[LIBRARY_SPECIFIC_UNITS], hasLength(1));
expect(outputs[PARSE_ERRORS], hasLength(0));
expect(outputs[PARSED_UNIT], isNotNull);
+ expect(outputs[REFERENCED_NAMES], isNotNull);
+ expect(outputs[REFERENCED_SOURCES], hasLength(3));
expect(outputs[SOURCE_KIND], SourceKind.LIBRARY);
expect(outputs[UNITS], hasLength(1));
- expect(outputs[REFERENCED_SOURCES], hasLength(3));
}
test_perform_flushTokenStream() {
@@ -3285,7 +3288,7 @@
export '${a}lib3.dart';
part 'part.dart';
class A {}''');
- expect(outputs, hasLength(10));
+ expect(outputs, hasLength(11));
expect(outputs[EXPLICITLY_IMPORTED_LIBRARIES], hasLength(1));
expect(outputs[EXPORTED_LIBRARIES], hasLength(0));
_assertHasCore(outputs[IMPORTED_LIBRARIES], 2);
@@ -3293,9 +3296,10 @@
expect(outputs[LIBRARY_SPECIFIC_UNITS], hasLength(2));
expect(outputs[PARSE_ERRORS], hasLength(2));
expect(outputs[PARSED_UNIT], isNotNull);
+ expect(outputs[REFERENCED_NAMES], isNotNull);
+ expect(outputs[REFERENCED_SOURCES], hasLength(4));
expect(outputs[SOURCE_KIND], SourceKind.LIBRARY);
expect(outputs[UNITS], hasLength(2));
- expect(outputs[REFERENCED_SOURCES], hasLength(4));
}
test_perform_library() {
@@ -3305,7 +3309,7 @@
export 'lib3.dart';
part 'part.dart';
class A {''');
- expect(outputs, hasLength(10));
+ expect(outputs, hasLength(11));
expect(outputs[EXPLICITLY_IMPORTED_LIBRARIES], hasLength(1));
expect(outputs[EXPORTED_LIBRARIES], hasLength(1));
_assertHasCore(outputs[IMPORTED_LIBRARIES], 2);
@@ -3313,9 +3317,10 @@
expect(outputs[LIBRARY_SPECIFIC_UNITS], hasLength(2));
expect(outputs[PARSE_ERRORS], hasLength(1));
expect(outputs[PARSED_UNIT], isNotNull);
+ expect(outputs[REFERENCED_NAMES], isNotNull);
+ expect(outputs[REFERENCED_SOURCES], hasLength(5));
expect(outputs[SOURCE_KIND], SourceKind.LIBRARY);
expect(outputs[UNITS], hasLength(2));
- expect(outputs[REFERENCED_SOURCES], hasLength(5));
}
test_perform_library_selfReferenceAsPart() {
@@ -3330,7 +3335,7 @@
_performParseTask(r'''
part of lib;
class B {}''');
- expect(outputs, hasLength(10));
+ expect(outputs, hasLength(11));
expect(outputs[EXPLICITLY_IMPORTED_LIBRARIES], hasLength(0));
expect(outputs[EXPORTED_LIBRARIES], hasLength(0));
_assertHasCore(outputs[IMPORTED_LIBRARIES], 1);
@@ -3338,9 +3343,10 @@
expect(outputs[LIBRARY_SPECIFIC_UNITS], hasLength(1));
expect(outputs[PARSE_ERRORS], hasLength(0));
expect(outputs[PARSED_UNIT], isNotNull);
+ expect(outputs[REFERENCED_NAMES], isNotNull);
+ expect(outputs[REFERENCED_SOURCES], hasLength(2));
expect(outputs[SOURCE_KIND], SourceKind.PART);
expect(outputs[UNITS], hasLength(1));
- expect(outputs[REFERENCED_SOURCES], hasLength(2));
}
void _performParseTask(String content) {
@@ -4106,7 +4112,7 @@
ReferencedNames _computeReferencedNames(String code) {
Source source = newSource('/test.dart', code);
- computeResult(source, REFERENCED_NAMES, matcher: isBuildLibraryElementTask);
+ computeResult(source, REFERENCED_NAMES, matcher: isParseDartTask);
return outputs[REFERENCED_NAMES];
}
}
diff --git a/pkg/analyzer/test/src/task/dart_work_manager_test.dart b/pkg/analyzer/test/src/task/dart_work_manager_test.dart
index da36f87..31ee542 100644
--- a/pkg/analyzer/test/src/task/dart_work_manager_test.dart
+++ b/pkg/analyzer/test/src/task/dart_work_manager_test.dart
@@ -106,6 +106,21 @@
expect_unknownSourceQueue([source4, source1]);
}
+ /**
+ * When we perform limited invalidation, we keep [SOURCE_KIND] valid. So, we
+ * don't need to put such sources into [DartWorkManager.unknownSourceQueue],
+ * and remove from [DartWorkManager.librarySourceQueue].
+ */
+ void test_applyChange_change_hasSourceKind() {
+ entry1.setValue(SOURCE_KIND, SourceKind.LIBRARY, []);
+ manager.librarySourceQueue.addAll([source1, source2]);
+ manager.unknownSourceQueue.addAll([source3]);
+ // change source1
+ manager.applyChange([], [source1, source2], []);
+ expect_librarySourceQueue([source1]);
+ expect_unknownSourceQueue([source2, source3]);
+ }
+
void test_applyChange_remove() {
manager.librarySourceQueue.addAll([source1, source3]);
manager.unknownSourceQueue.addAll([source4]);
diff --git a/pkg/analyzer/test/src/task/incremental_element_builder_test.dart b/pkg/analyzer/test/src/task/incremental_element_builder_test.dart
index 8d495af..ecd98cb 100644
--- a/pkg/analyzer/test/src/task/incremental_element_builder_test.dart
+++ b/pkg/analyzer/test/src/task/incremental_element_builder_test.dart
@@ -6,6 +6,7 @@
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/dart/element/visitor.dart';
import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/generated/engine.dart';
@@ -66,6 +67,7 @@
ClassElement classElement = helper.element;
expect(classElement.constructors, unorderedEquals([newConstructorElement]));
// verify delta
+ expect(helper.delta.hasUnnamedConstructorChange, isTrue);
expect(helper.delta.addedConstructors,
unorderedEquals([newConstructorElement]));
expect(helper.delta.removedConstructors,
@@ -99,7 +101,9 @@
expect(constructors[0].isSynthetic, isTrue);
}
// verify delta
- expect(helper.delta.addedConstructors, unorderedEquals([]));
+ expect(helper.delta.hasUnnamedConstructorChange, isTrue);
+ expect(helper.delta.addedConstructors,
+ unorderedEquals([classElement.unnamedConstructor]));
expect(helper.delta.removedConstructors, unorderedEquals([oldElementA]));
expect(helper.delta.addedAccessors, isEmpty);
expect(helper.delta.removedAccessors, isEmpty);
@@ -107,6 +111,66 @@
expect(helper.delta.removedMethods, isEmpty);
}
+ test_classDelta_constructor_1to1_unnamed_addParameter() {
+ var helper = new _ClassDeltaHelper('A');
+ _buildOldUnit(r'''
+class A {
+ A();
+}
+''');
+ helper.initOld(oldUnit);
+ ConstructorElement oldConstructor = helper.element.unnamedConstructor;
+ _buildNewUnit(r'''
+class A {
+ A(int p);
+}
+''');
+ helper.initNew(newUnit, unitDelta);
+ ClassElement classElement = helper.element;
+ ConstructorElement newConstructor = classElement.unnamedConstructor;
+ expect(classElement.constructors, [newConstructor]);
+ // verify delta
+ expect(helper.delta.hasUnnamedConstructorChange, isTrue);
+ expect(helper.delta.addedConstructors, unorderedEquals([newConstructor]));
+ expect(helper.delta.removedConstructors, unorderedEquals([oldConstructor]));
+ expect(helper.delta.addedAccessors, isEmpty);
+ expect(helper.delta.removedAccessors, isEmpty);
+ expect(helper.delta.addedMethods, isEmpty);
+ expect(helper.delta.removedMethods, isEmpty);
+ }
+
+ test_classDelta_constructor_1to1_unnamed_removeParameter() {
+ var helper = new _ClassDeltaHelper('A');
+ _buildOldUnit(r'''
+class A {
+ final int a;
+ final int b;
+ A(this.a, this.b);
+}
+''');
+ helper.initOld(oldUnit);
+ ConstructorElement oldConstructor = helper.element.unnamedConstructor;
+ _buildNewUnit(r'''
+class A {
+ final int a;
+ final int b;
+ A(this.a);
+}
+''');
+ helper.initNew(newUnit, unitDelta);
+ ClassElement classElement = helper.element;
+ ConstructorElement newConstructor = classElement.unnamedConstructor;
+ expect(classElement.constructors, [newConstructor]);
+ // verify delta
+ expect(helper.delta.hasUnnamedConstructorChange, isTrue);
+ expect(helper.delta.addedConstructors, unorderedEquals([newConstructor]));
+ expect(helper.delta.removedConstructors, unorderedEquals([oldConstructor]));
+ expect(helper.delta.addedAccessors, isEmpty);
+ expect(helper.delta.removedAccessors, isEmpty);
+ expect(helper.delta.addedMethods, isEmpty);
+ expect(helper.delta.removedMethods, isEmpty);
+ }
+
test_classDelta_constructor_1to2() {
var helper = new _ClassDeltaHelper('A');
_buildOldUnit(r'''
@@ -161,6 +225,7 @@
}
''');
helper.initNew(newUnit, unitDelta);
+ expect(helper.delta.hasUnnamedConstructorChange, isFalse);
// nodes
ClassMember nodeB = helper.newMembers[0];
expect(nodeB, same(helper.oldMembers[1]));
@@ -685,6 +750,26 @@
expect(helper.delta.removedMethods, unorderedEquals([oldElementA]));
}
+ test_classDelta_null_abstractKeyword_add() {
+ _verifyNoClassDeltaForTheLast(
+ r'''
+class A {}
+''',
+ r'''
+abstract class A {}
+''');
+ }
+
+ test_classDelta_null_abstractKeyword_remove() {
+ _verifyNoClassDeltaForTheLast(
+ r'''
+abstract class A {}
+''',
+ r'''
+class A {}
+''');
+ }
+
test_classDelta_null_extendsClause_add() {
_verifyNoClassDeltaForTheLast(
r'''
@@ -1366,6 +1451,14 @@
expect(elementB, isNotNull);
expect(elementA.name, 'A');
expect(elementB.name, 'B');
+ expect(elementA.fields.map((f) => f.name),
+ unorderedEquals(['index', 'values', 'A1', 'A2']));
+ expect(elementA.accessors.map((a) => a.name),
+ unorderedEquals(['index', 'values', 'A1', 'A2']));
+ expect(elementB.fields.map((f) => f.name),
+ unorderedEquals(['index', 'values', 'B1', 'B2']));
+ expect(elementB.accessors.map((a) => a.name),
+ unorderedEquals(['index', 'values', 'B1', 'B2']));
// unit.types
expect(unitElement.enums, unorderedEquals([elementA, elementB]));
// verify delta
@@ -1565,6 +1658,18 @@
''');
}
+ test_update_annotation_add() {
+ _buildOldUnit(r'''
+const myAnnotation = const Object();
+foo() {}
+''');
+ _buildNewUnit(r'''
+const myAnnotation = const Object();
+@myAnnotation
+foo() {}
+''');
+ }
+
test_update_beforeClassWithDelta_nameOffset() {
_buildOldUnit(r'''
class A {}
@@ -1634,6 +1739,39 @@
''');
}
+ test_update_commentReference_multipleCommentTokens() {
+ _buildOldUnit(r'''
+class A {
+ /// C1 [C2]
+ /// C3 [C4]
+ /// C5 [C6]
+ void m() {}
+}
+''');
+ _buildNewUnit(r'''
+class A {
+ int field;
+
+ /// C1 [C2]
+ /// C3 [C4]
+ /// C5 [C6]
+ void m() {}
+}
+''');
+ }
+
+ test_update_commentReference_new() {
+ _buildOldUnit(r'''
+/// Comment reference with new [new A].
+class A {}
+''');
+ _buildNewUnit(r'''
+class B {}
+/// Comment reference with new [new A].
+class A {}
+''');
+ }
+
test_update_commentReference_notClosed() {
_buildOldUnit(r'''
/// [c)
@@ -1646,6 +1784,33 @@
''');
}
+ test_update_element_implicitAccessors_classField() {
+ _buildOldUnit(r'''
+// 0
+class A {
+ var F = 0;
+}
+''');
+ _materializeLazyElements(unitElement);
+ _buildNewUnit(r'''
+// 012
+class A {
+ var F = 0;
+}
+''');
+ }
+
+ test_update_element_implicitAccessors_topLevelVariable() {
+ _buildOldUnit(r'''
+var A = 0;
+var B = 1;
+''');
+ _materializeLazyElements(unitElement);
+ _buildNewUnit(r'''
+var B = 1;
+''');
+ }
+
test_update_rewrittenConstructorName() {
_buildOldUnit(r'''
class A {
@@ -1715,6 +1880,10 @@
expect(unitElement, isNotNull);
}
+ void _materializeLazyElements(CompilationUnitElement unitElement) {
+ unitElement.accept(new _MaterializeLazyElementsVisitor());
+ }
+
void _verifyNoClassDeltaForTheLast(String oldCode, String newCode) {
_buildOldUnit(oldCode);
List<CompilationUnitMember> oldMembers = oldUnit.declarations.toList();
@@ -1733,6 +1902,8 @@
* Compares tokens and ASTs, and built elements of declared identifiers.
*/
class _BuiltElementsValidator extends AstComparator {
+ final Set visited = new Set.identity();
+
@override
bool isEqualNodes(AstNode expected, AstNode actual) {
// Elements of nodes which are children of ClassDeclaration(s) must be
@@ -1761,6 +1932,16 @@
actual.getAncestor((n) => n is ClassDeclaration);
expect(element.enclosingElement, same(classNode.element));
}
+ // ElementAnnotationImpl must use the enclosing CompilationUnitElement.
+ if (actual is Annotation) {
+ AstNode parent = actual.parent;
+ if (parent is Declaration) {
+ ElementAnnotationImpl actualElement = actual.elementAnnotation;
+ CompilationUnitElement enclosingUnitElement =
+ parent.element.getAncestor((a) => a is CompilationUnitElement);
+ expect(actualElement.compilationUnit, same(enclosingUnitElement));
+ }
+ }
// Identifiers like 'a.b' in 'new a.b()' might be rewritten if resolver
// sees that 'a' is actually a class name, so 'b' is a constructor name.
//
@@ -1784,13 +1965,17 @@
expect(actual.inDeclarationContext(), isTrue);
Element expectedElement = expected.staticElement;
Element actualElement = actual.staticElement;
- _verifyElement(expectedElement, actualElement, 'staticElement');
+ _verifyElement(
+ expectedElement, actualElement, 'staticElement ($expectedElement)');
}
}
return true;
}
void _verifyElement(Element expected, Element actual, String desc) {
+ if (!visited.add(expected)) {
+ return;
+ }
if (expected == null && actual == null) {
return;
}
@@ -1820,6 +2005,23 @@
'${expectedEnclosing.name}.$desc');
}
}
+ // Compare implicit accessors.
+ if (expected is PropertyInducingElement &&
+ actual is PropertyInducingElement &&
+ !expected.isSynthetic) {
+ _verifyElement(expected.getter, actual.getter, '$desc getter');
+ _verifyElement(expected.setter, actual.setter, '$desc setter');
+ }
+ // Compare parameters.
+ if (expected is ExecutableElement && actual is ExecutableElement) {
+ List<ParameterElement> actualParameters = actual.parameters;
+ List<ParameterElement> expectedParameters = expected.parameters;
+ expect(actualParameters, hasLength(expectedParameters.length));
+ for (int i = 0; i < expectedParameters.length; i++) {
+ _verifyElement(
+ expectedParameters[i], actualParameters[i], '$desc parameters[$i]');
+ }
+ }
}
void _verifyEqual(String name, expected, actual) {
@@ -1833,13 +2035,15 @@
final String name;
ClassElementDelta delta;
- ClassElement element;
+ ClassElementImpl element;
+ int oldVersion;
List<ClassMember> oldMembers;
List<ClassMember> newMembers;
_ClassDeltaHelper(this.name);
void initNew(CompilationUnit newUnit, CompilationUnitElementDelta unitDelta) {
+ expect(element.version, isNot(oldVersion));
ClassDeclaration newClass = _findClassNode(newUnit, name);
expect(newClass, isNotNull);
newMembers = newClass.members.toList();
@@ -1851,6 +2055,7 @@
ClassDeclaration oldClass = _findClassNode(oldUnit, name);
expect(oldClass, isNotNull);
element = oldClass.element;
+ oldVersion = element.version;
oldMembers = oldClass.members.toList();
}
@@ -1858,3 +2063,11 @@
unit.declarations.singleWhere((unitMember) =>
unitMember is ClassDeclaration && unitMember.name.name == name);
}
+
+class _MaterializeLazyElementsVisitor extends GeneralizingElementVisitor {
+ @override
+ visitExecutableElement(ExecutableElement element) {
+ element.parameters;
+ super.visitExecutableElement(element);
+ }
+}
diff --git a/pkg/analyzer/test/src/task/options_test.dart b/pkg/analyzer/test/src/task/options_test.dart
index f65c3fb..a0cbca8 100644
--- a/pkg/analyzer/test/src/task/options_test.dart
+++ b/pkg/analyzer/test/src/task/options_test.dart
@@ -7,6 +7,7 @@
import 'package:analyzer/analyzer.dart';
import 'package:analyzer/source/analysis_options_provider.dart';
import 'package:analyzer/source/error_processor.dart';
+import 'package:analyzer/src/context/context.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/task/options.dart';
@@ -128,6 +129,18 @@
expect(unusedLocal.severity, ErrorSeverity.ERROR);
}
+ test_configure_excludes() {
+ configureContext('''
+analyzer:
+ exclude:
+ - foo/bar.dart
+ - 'test/**'
+''');
+
+ List<String> excludes = context.getConfigurationData(CONTEXT_EXCLUDES);
+ expect(excludes, unorderedEquals(['foo/bar.dart', 'test/**']));
+ }
+
test_configure_strong_mode() {
configureContext('''
analyzer:
diff --git a/pkg/analyzer/test/src/task/strong/checker_test.dart b/pkg/analyzer/test/src/task/strong/checker_test.dart
index 0b1a115..343a2ae 100644
--- a/pkg/analyzer/test/src/task/strong/checker_test.dart
+++ b/pkg/analyzer/test/src/task/strong/checker_test.dart
@@ -264,7 +264,7 @@
test() {
int x = 0;
x += 5;
- /*error:STATIC_TYPE_ERROR*/x += 3.14;
+ /*error:STATIC_TYPE_ERROR*/x += /*error:INVALID_ASSIGNMENT*/3.14;
double y = 0.0;
y += 5;
@@ -690,14 +690,14 @@
foo1() async => x;
Future foo2() async => x;
-Future<int> foo3() async => /*info:DYNAMIC_CAST*/x;
+Future<int> foo3() async => x;
Future<int> foo4() async => new Future<int>.value(/*info:DYNAMIC_CAST*/x);
Future<int> foo5() async =>
/*error:RETURN_OF_INVALID_TYPE*/new Future<String>.value(/*info:DYNAMIC_CAST*/x);
bar1() async { return x; }
Future bar2() async { return x; }
-Future<int> bar3() async { return /*info:DYNAMIC_CAST*/x; }
+Future<int> bar3() async { return x; }
Future<int> bar4() async { return new Future<int>.value(/*info:DYNAMIC_CAST*/x); }
Future<int> bar5() async {
return /*error:RETURN_OF_INVALID_TYPE*/new Future<String>.value(/*info:DYNAMIC_CAST*/x);
@@ -713,7 +713,7 @@
String d = /*error:INVALID_ASSIGNMENT*/await z;
}
-Future<bool> get issue_264 async {
+Future<bool> get issue_ddc_264 async {
await 42;
if (new Random().nextBool()) {
return true;
@@ -721,6 +721,11 @@
return new Future<bool>.value(false);
}
}
+
+
+Future<String> issue_sdk_26404() async {
+ return (1 > 0) ? new Future<String>.value('hello') : "world";
+}
''');
}
@@ -1917,6 +1922,23 @@
check(implicitCasts: false);
}
+ void test_implicitCasts_genericMethods() {
+ addFile('var x = <String>[].map((x) => "");');
+ check(implicitCasts: false);
+ }
+
+ void test_implicitCasts_numericOps() {
+ // Regression test for https://github.com/dart-lang/sdk/issues/26912
+ addFile(r'''
+void f() {
+ int x = 0;
+ int y = 0;
+ x += y;
+}
+ ''');
+ check(implicitCasts: false);
+ }
+
void test_implicitDynamic_field() {
addFile(r'''
class C {
diff --git a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
index 0446efa..feef92f 100644
--- a/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
+++ b/pkg/analyzer/test/src/task/strong/inferred_type_test.dart
@@ -62,7 +62,7 @@
var mainUnit = checkFile(r'''
import 'dart:async';
import 'dart:math' show Random;
-var f = /*info:INFERRED_TYPE_CLOSURE*/() async {
+var f = /*info:INFERRED_TYPE_CLOSURE,warning:UNSAFE_BLOCK_CLOSURE_INFERENCE*/() async {
if (new Random().nextBool()) {
return new Future<int>.value(1);
} else {
@@ -101,7 +101,7 @@
var mainUnit = checkFile(r'''
import 'dart:async';
import 'dart:math' show Random;
-var f = /*info:INFERRED_TYPE_CLOSURE*/() async {
+var f = /*info:INFERRED_TYPE_CLOSURE,warning:UNSAFE_BLOCK_CLOSURE_INFERENCE*/() async {
if (new Random().nextBool()) {
return 1;
} else {
@@ -140,7 +140,7 @@
var mainUnit = checkFile(r'''
import 'dart:async';
import 'dart:math' show Random;
-var f = /*info:INFERRED_TYPE_CLOSURE*/() async {
+var f = /*info:INFERRED_TYPE_CLOSURE,warning:UNSAFE_BLOCK_CLOSURE_INFERENCE*/() async {
if (new Random().nextBool()) {
return new Future<int>.value(1);
} else {
@@ -175,7 +175,7 @@
void test_blockBodiedLambdas_asyncStar_topLevel() {
var mainUnit = checkFile(r'''
import 'dart:async';
-var f = /*info:INFERRED_TYPE_CLOSURE*/() async* {
+var f = /*info:INFERRED_TYPE_CLOSURE,warning:UNSAFE_BLOCK_CLOSURE_INFERENCE*/() async* {
yield 1;
Stream<double> s;
yield* s;
@@ -198,7 +198,7 @@
void test_blockBodiedLambdas_basic_topLevel() {
checkFile(r'''
List<int> o;
-var y = o.map(/*info:INFERRED_TYPE_CLOSURE*/(x) { return x + 1; });
+var y = o.map(/*info:INFERRED_TYPE_CLOSURE,warning:UNSAFE_BLOCK_CLOSURE_INFERENCE*/(x) { return x + 1; });
Iterable<int> z = y;
''');
}
@@ -223,7 +223,7 @@
void test_blockBodiedLambdas_doesNotInferBottom_async_topLevel() {
var mainUnit = checkFile(r'''
import 'dart:async';
-var f = () async { return null; };
+var f = /*warning:UNSAFE_BLOCK_CLOSURE_INFERENCE*/() async { return null; };
''');
var f = mainUnit.topLevelVariables[0];
expect(f.type.toString(), '() → Future<dynamic>');
@@ -249,7 +249,7 @@
void test_blockBodiedLambdas_doesNotInferBottom_asyncStar_topLevel() {
var mainUnit = checkFile(r'''
import 'dart:async';
-var f = () async* { yield null; };
+var f = /*warning:UNSAFE_BLOCK_CLOSURE_INFERENCE*/() async* { yield null; };
''');
var f = mainUnit.topLevelVariables[0];
expect(f.type.toString(), '() → Stream<dynamic>');
@@ -304,7 +304,7 @@
void test_blockBodiedLambdas_doesNotInferBottom_syncStar_topLevel() {
var mainUnit = checkFile(r'''
-var f = () sync* { yield null; };
+var f = /*warning:UNSAFE_BLOCK_CLOSURE_INFERENCE*/() sync* { yield null; };
''');
var f = mainUnit.topLevelVariables[0];
expect(f.type.toString(), '() → Iterable<dynamic>');
@@ -357,7 +357,7 @@
checkFile(r'''
import 'dart:math' show Random;
List<num> o;
-var y = o.map(/*info:INFERRED_TYPE_CLOSURE*/(x) {
+var y = o.map(/*info:INFERRED_TYPE_CLOSURE,warning:UNSAFE_BLOCK_CLOSURE_INFERENCE*/(x) {
if (new Random().nextBool()) {
return x.toInt() + 1;
} else {
@@ -388,7 +388,7 @@
void test_blockBodiedLambdas_nestedLambdas_topLevel() {
// Original feature request: https://github.com/dart-lang/sdk/issues/25487
var mainUnit = checkFile(r'''
-var f = /*info:INFERRED_TYPE_CLOSURE*/() {
+var f = /*info:INFERRED_TYPE_CLOSURE,warning:UNSAFE_BLOCK_CLOSURE_INFERENCE*/() {
return /*info:INFERRED_TYPE_CLOSURE*/(int x) { return 2.0 * x; };
};
''');
@@ -440,7 +440,7 @@
void test_blockBodiedLambdas_syncStar_topLevel() {
var mainUnit = checkFile(r'''
-var f = /*info:INFERRED_TYPE_CLOSURE*/() sync* {
+var f = /*info:INFERRED_TYPE_CLOSURE,warning:UNSAFE_BLOCK_CLOSURE_INFERENCE*/() sync* {
yield 1;
yield* /*info:INFERRED_TYPE_LITERAL*/[3, 4.0];
};
@@ -588,6 +588,152 @@
''');
}
+ void test_constructors_inferFromArguments() {
+ var unit = checkFile('''
+class C<T> {
+ T t;
+ C(this.t);
+}
+
+var x = /*info:INFERRED_TYPE_ALLOCATION*/new C(42);
+
+// Don't infer if we had a context type.
+num y;
+C<int> c_int = /*info:INFERRED_TYPE_ALLOCATION*/new C(/*info:DOWN_CAST_IMPLICIT*/y);
+
+// These hints are not reported because we resolve with a null error listener.
+C<num> c_num = /*pass should be info:INFERRED_TYPE_ALLOCATION*/new C(123);
+C<num> c_num2 = (/*pass should be info:INFERRED_TYPE_ALLOCATION*/new C(456))
+ ..t = /*error:INVALID_ASSIGNMENT*/1.0;
+
+// Down't infer from explicit dynamic.
+var c_dynamic = new C<dynamic>(42);
+
+main() {
+ x.t = /*error:INVALID_ASSIGNMENT*/'hello';
+}
+''');
+ var vars = unit.topLevelVariables;
+ expect(vars[0].type.toString(), 'C<int>');
+ expect(vars.firstWhere((e) => e.name == 'c_int').type.toString(), 'C<int>');
+ expect(vars.firstWhere((e) => e.name == 'c_num').type.toString(), 'C<num>');
+ expect(vars.firstWhere((e) => e.name == 'c_dynamic').type.toString(),
+ 'C<dynamic>');
+ }
+
+ void test_constructors_inferFromArguments_const() {
+ var unit = checkFile('''
+class C<T> {
+ final T t;
+ const C(this.t);
+}
+
+var x = /*info:INFERRED_TYPE_ALLOCATION*/const C(42);
+''');
+ expect(unit.topLevelVariables[0].type.toString(), 'C<int>');
+ }
+
+ void test_constructors_inferFromArguments_factory() {
+ var unit = checkFile('''
+class C<T> {
+ T t;
+
+ C._();
+
+ factory C(T t) {
+ var x = new C<T>._();
+ x.t = t;
+ return x;
+ }
+}
+
+var x = /*info:INFERRED_TYPE_ALLOCATION*/new C(42);
+
+main() {
+ x.t = /*error:INVALID_ASSIGNMENT*/'hello';
+}
+''');
+ expect(unit.topLevelVariables[0].type.toString(), 'C<int>');
+ }
+
+ void test_constructors_inferFromArguments_named() {
+ var unit = checkFile('''
+class C<T> {
+ T t;
+ C.named(List<T> t);
+}
+
+var x = /*info:INFERRED_TYPE_ALLOCATION*/new C.named(<int>[]);
+
+main() {
+ x.t = /*error:INVALID_ASSIGNMENT*/'hello';
+}
+''');
+ expect(unit.topLevelVariables[0].type.toString(), 'C<int>');
+ }
+
+ void test_constructors_inferFromArguments_namedFactory() {
+ var unit = checkFile('''
+class C<T> {
+ T t;
+ C();
+
+ factory C.named(T t) {
+ var x = new C<T>();
+ x.t = t;
+ return x;
+ }
+}
+
+var x = /*info:INFERRED_TYPE_ALLOCATION*/new C.named(42);
+
+main() {
+ x.t = /*error:INVALID_ASSIGNMENT*/'hello';
+}
+''');
+ expect(unit.topLevelVariables[0].type.toString(), 'C<int>');
+ }
+
+ void test_constructors_inferFromArguments_redirecting() {
+ var unit = checkFile('''
+class C<T> {
+ T t;
+ C(this.t);
+ C.named(List<T> t) : this(t[0]);
+}
+
+var x = /*info:INFERRED_TYPE_ALLOCATION*/new C.named(<int>[42]);
+
+main() {
+ x.t = /*error:INVALID_ASSIGNMENT*/'hello';
+}
+''');
+ expect(unit.topLevelVariables[0].type.toString(), 'C<int>');
+ }
+
+ void test_constructors_inferFromArguments_redirectingFactory() {
+ var unit = checkFile('''
+abstract class C<T> {
+ T get t;
+ void set t(T x);
+
+ factory C(T t) = CImpl<T>;
+}
+
+class CImpl<T> implements C<T> {
+ T t;
+ CImpl(this.t);
+}
+
+var x = /*info:INFERRED_TYPE_ALLOCATION*/new C(42);
+
+main() {
+ x.t = /*error:INVALID_ASSIGNMENT*/'hello';
+}
+''');
+ expect(unit.topLevelVariables[0].type.toString(), 'C<int>');
+ }
+
void test_doNotInferOverriddenFieldsThatExplicitlySayDynamic_infer() {
checkFile('''
class A {
@@ -1073,8 +1219,8 @@
A<int, String> a1 = /*info:INFERRED_TYPE_ALLOCATION*/new D.named(
/*error:ARGUMENT_TYPE_NOT_ASSIGNABLE*/3);
}
- { // Currently we only allow variable constraints. Test that we reject.
- A<C<int>, String> a0 = /*error:STATIC_TYPE_ERROR*/new E("hello");
+ {
+ A<C<int>, String> a0 = /*info:INFERRED_TYPE_ALLOCATION*/new E("hello");
}
{ // Check named and optional arguments
A<int, String> a0 = /*info:INFERRED_TYPE_ALLOCATION*/new F(3, "hello",
@@ -3711,6 +3857,300 @@
// No type should be inferred for a because there is a circular reference
// between a and c.
}
+
+ void test_unsafeBlockClosureInference_closureCall() {
+ // Note: this is a DYNAMIC_INVOKE due to dartbug.com/26962.
+ var mainUnit = checkFile('''
+var v = /*info:DYNAMIC_INVOKE*/((x) => 1.0)(
+ /*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
+''');
+ var v = mainUnit.topLevelVariables[0];
+ expect(v.name, 'v');
+ expect(v.type.toString(), 'double');
+ }
+
+ void test_unsafeBlockClosureInference_constructorCall_explicitDynamicParam() {
+ var mainUnit = checkFile('''
+class C<T> {
+ C(T x());
+}
+var v = new C<dynamic>(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
+''');
+ var v = mainUnit.topLevelVariables[0];
+ expect(v.name, 'v');
+ expect(v.type.toString(), 'C<dynamic>');
+ }
+
+ void test_unsafeBlockClosureInference_constructorCall_explicitTypeParam() {
+ var mainUnit = checkFile('''
+class C<T> {
+ C(T x());
+}
+var v = new C<int>(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
+''');
+ var v = mainUnit.topLevelVariables[0];
+ expect(v.name, 'v');
+ expect(v.type.toString(), 'C<int>');
+ }
+
+ void test_unsafeBlockClosureInference_constructorCall_implicitTypeParam() {
+ var mainUnit = checkFile('''
+class C<T> {
+ C(T x());
+}
+var v = /*info:INFERRED_TYPE_ALLOCATION*/new C(
+ /*info:INFERRED_TYPE_CLOSURE,warning:UNSAFE_BLOCK_CLOSURE_INFERENCE*/() {
+ return 1;
+ });
+''');
+ var v = mainUnit.topLevelVariables[0];
+ expect(v.name, 'v');
+ expect(v.type.toString(), 'C<int>');
+ }
+
+ void test_unsafeBlockClosureInference_constructorCall_noTypeParam() {
+ var mainUnit = checkFile('''
+class C {
+ C(x());
+}
+var v = new C(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
+''');
+ var v = mainUnit.topLevelVariables[0];
+ expect(v.name, 'v');
+ expect(v.type.toString(), 'C');
+ }
+
+ void test_unsafeBlockClosureInference_functionCall_explicitDynamicParam() {
+ var mainUnit = checkFile('''
+dynamic /*=List<T>*/ f/*<T>*/(dynamic/*=T*/ g()) => <T>[g()];
+var v = f/*<dynamic>*/(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
+''');
+ var v = mainUnit.topLevelVariables[0];
+ expect(v.name, 'v');
+ expect(v.type.toString(), 'List<dynamic>');
+ }
+
+ @failingTest
+ void
+ test_unsafeBlockClosureInference_functionCall_explicitDynamicParam_viaExpr1() {
+ // Note: (f/*<dynamic>*/) is nort properly resulting in an instantiated
+ // function type due to dartbug.com/25824.
+ var mainUnit = checkFile('''
+dynamic /*=List<T>*/ f/*<T>*/(dynamic/*=T*/ g()) => <T>[g()];
+var v = (f/*<dynamic>*/)(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
+''');
+ var v = mainUnit.topLevelVariables[0];
+ expect(v.name, 'v');
+ expect(v.type.toString(), 'List<dynamic>');
+ }
+
+ void
+ test_unsafeBlockClosureInference_functionCall_explicitDynamicParam_viaExpr2() {
+ var mainUnit = checkFile('''
+dynamic /*=List<T>*/ f/*<T>*/(dynamic/*=T*/ g()) => <T>[g()];
+var v = (f)/*<dynamic>*/(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
+''');
+ var v = mainUnit.topLevelVariables[0];
+ expect(v.name, 'v');
+ expect(v.type.toString(), 'List<dynamic>');
+ }
+
+ void test_unsafeBlockClosureInference_functionCall_explicitTypeParam() {
+ var mainUnit = checkFile('''
+dynamic /*=List<T>*/ f/*<T>*/(dynamic/*=T*/ g()) => <T>[g()];
+var v = f/*<int>*/(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
+''');
+ var v = mainUnit.topLevelVariables[0];
+ expect(v.name, 'v');
+ expect(v.type.toString(), 'List<int>');
+ }
+
+ @failingTest
+ void
+ test_unsafeBlockClosureInference_functionCall_explicitTypeParam_viaExpr1() {
+ // TODO(paulberry): for some reason (f/*<int>) is nort properly resulting
+ // in an instantiated function type.
+ var mainUnit = checkFile('''
+dynamic /*=List<T>*/ f/*<T>*/(dynamic/*=T*/ g()) => <T>[g()];
+var v = (f/*<int>*/)(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
+''');
+ var v = mainUnit.topLevelVariables[0];
+ expect(v.name, 'v');
+ expect(v.type.toString(), 'List<int>');
+ }
+
+ void
+ test_unsafeBlockClosureInference_functionCall_explicitTypeParam_viaExpr2() {
+ var mainUnit = checkFile('''
+dynamic /*=List<T>*/ f/*<T>*/(dynamic/*=T*/ g()) => <T>[g()];
+var v = (f)/*<int>*/(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
+''');
+ var v = mainUnit.topLevelVariables[0];
+ expect(v.name, 'v');
+ expect(v.type.toString(), 'List<int>');
+ }
+
+ void test_unsafeBlockClosureInference_functionCall_implicitTypeParam() {
+ var mainUnit = checkFile('''
+dynamic /*=List<T>*/ f/*<T>*/(dynamic/*=T*/ g()) => <T>[g()];
+var v = f(
+ /*info:INFERRED_TYPE_CLOSURE,warning:UNSAFE_BLOCK_CLOSURE_INFERENCE*/() {
+ return 1;
+ });
+''');
+ var v = mainUnit.topLevelVariables[0];
+ expect(v.name, 'v');
+ expect(v.type.toString(), 'List<int>');
+ }
+
+ void
+ test_unsafeBlockClosureInference_functionCall_implicitTypeParam_viaExpr() {
+ var mainUnit = checkFile('''
+dynamic /*=List<T>*/ f/*<T>*/(dynamic/*=T*/ g()) => <T>[g()];
+var v = (f)(
+ /*info:INFERRED_TYPE_CLOSURE,warning:UNSAFE_BLOCK_CLOSURE_INFERENCE*/() {
+ return 1;
+ });
+''');
+ var v = mainUnit.topLevelVariables[0];
+ expect(v.name, 'v');
+ expect(v.type.toString(), 'List<int>');
+ }
+
+ void test_unsafeBlockClosureInference_functionCall_noTypeParam() {
+ var mainUnit = checkFile('''
+double f(x) => 1.0;
+var v = f(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
+''');
+ var v = mainUnit.topLevelVariables[0];
+ expect(v.name, 'v');
+ expect(v.type.toString(), 'double');
+ }
+
+ void test_unsafeBlockClosureInference_functionCall_noTypeParam_viaExpr() {
+ // TODO(paulberry): why is the call to f() considered a DYNAMIC_INVOKE?
+ var mainUnit = checkFile('''
+double f(x) => 1.0;
+var v = /*info:DYNAMIC_INVOKE*/(f)(
+ /*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
+''');
+ var v = mainUnit.topLevelVariables[0];
+ expect(v.name, 'v');
+ expect(v.type.toString(), 'double');
+ }
+
+ void test_unsafeBlockClosureInference_inList_dynamic() {
+ var mainUnit = checkFile('''
+var v = <dynamic>[/*info:INFERRED_TYPE_CLOSURE*/() { return 1; }];
+''');
+ var v = mainUnit.topLevelVariables[0];
+ expect(v.name, 'v');
+ expect(v.type.toString(), 'List<dynamic>');
+ }
+
+ void test_unsafeBlockClosureInference_inList_typed() {
+ var mainUnit = checkFile('''
+typedef int F();
+var v = <F>[/*info:INFERRED_TYPE_CLOSURE*/() { return 1; }];
+''');
+ var v = mainUnit.topLevelVariables[0];
+ expect(v.name, 'v');
+ expect(v.type.toString(), 'List<() → int>');
+ }
+
+ void test_unsafeBlockClosureInference_inList_untyped() {
+ var mainUnit = checkFile('''
+var v = /*info:INFERRED_TYPE_LITERAL*/[
+ /*info:INFERRED_TYPE_CLOSURE,warning:UNSAFE_BLOCK_CLOSURE_INFERENCE*/() {
+ return 1;
+ }];
+''');
+ var v = mainUnit.topLevelVariables[0];
+ expect(v.name, 'v');
+ expect(v.type.toString(), 'List<() → int>');
+ }
+
+ void test_unsafeBlockClosureInference_inMap_dynamic() {
+ var mainUnit = checkFile('''
+var v = <int, dynamic>{1: /*info:INFERRED_TYPE_CLOSURE*/() { return 1; }};
+''');
+ var v = mainUnit.topLevelVariables[0];
+ expect(v.name, 'v');
+ expect(v.type.toString(), 'Map<int, dynamic>');
+ }
+
+ void test_unsafeBlockClosureInference_inMap_typed() {
+ var mainUnit = checkFile('''
+typedef int F();
+var v = <int, F>{1: /*info:INFERRED_TYPE_CLOSURE*/() { return 1; }};
+''');
+ var v = mainUnit.topLevelVariables[0];
+ expect(v.name, 'v');
+ expect(v.type.toString(), 'Map<int, () → int>');
+ }
+
+ void test_unsafeBlockClosureInference_inMap_untyped() {
+ var mainUnit = checkFile('''
+var v = /*info:INFERRED_TYPE_LITERAL*/{
+ 1: /*info:INFERRED_TYPE_CLOSURE,warning:UNSAFE_BLOCK_CLOSURE_INFERENCE*/() {
+ return 1;
+ }};
+''');
+ var v = mainUnit.topLevelVariables[0];
+ expect(v.name, 'v');
+ expect(v.type.toString(), 'Map<int, () → int>');
+ }
+
+ void test_unsafeBlockClosureInference_methodCall_explicitDynamicParam() {
+ var mainUnit = checkFile('''
+class C {
+ dynamic /*=List<T>*/ f/*<T>*/(dynamic/*=T*/ g()) => <T>[g()];
+}
+var v = new C().f/*<dynamic>*/(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
+''');
+ var v = mainUnit.topLevelVariables[0];
+ expect(v.name, 'v');
+ expect(v.type.toString(), 'List<dynamic>');
+ }
+
+ void test_unsafeBlockClosureInference_methodCall_explicitTypeParam() {
+ var mainUnit = checkFile('''
+class C {
+ dynamic /*=List<T>*/ f/*<T>*/(dynamic/*=T*/ g()) => <T>[g()];
+}
+var v = new C().f/*<int>*/(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
+''');
+ var v = mainUnit.topLevelVariables[0];
+ expect(v.name, 'v');
+ expect(v.type.toString(), 'List<int>');
+ }
+
+ void test_unsafeBlockClosureInference_methodCall_implicitTypeParam() {
+ var mainUnit = checkFile('''
+class C {
+ dynamic /*=List<T>*/ f/*<T>*/(dynamic/*=T*/ g()) => <T>[g()];
+}
+var v = new C().f(
+ /*info:INFERRED_TYPE_CLOSURE,warning:UNSAFE_BLOCK_CLOSURE_INFERENCE*/() {
+ return 1;
+ });
+''');
+ var v = mainUnit.topLevelVariables[0];
+ expect(v.name, 'v');
+ expect(v.type.toString(), 'List<int>');
+ }
+
+ void test_unsafeBlockClosureInference_methodCall_noTypeParam() {
+ var mainUnit = checkFile('''
+class C {
+ double f(x) => 1.0;
+}
+var v = new C().f(/*info:INFERRED_TYPE_CLOSURE*/() { return 1; });
+''');
+ var v = mainUnit.topLevelVariables[0];
+ expect(v.name, 'v');
+ expect(v.type.toString(), 'double');
+ }
}
@reflectiveTest
diff --git a/pkg/analyzer/tool/task_dependency_graph/tasks.dot b/pkg/analyzer/tool/task_dependency_graph/tasks.dot
index 11040b1..feb61eb 100644
--- a/pkg/analyzer/tool/task_dependency_graph/tasks.dot
+++ b/pkg/analyzer/tool/task_dependency_graph/tasks.dot
@@ -25,7 +25,6 @@
BuildLibraryElementTask -> BUILD_LIBRARY_ERRORS
BuildLibraryElementTask -> IS_LAUNCHABLE
BuildLibraryElementTask -> LIBRARY_ELEMENT1
- BuildLibraryElementTask -> REFERENCED_NAMES
BuildPublicNamespaceTask -> LIBRARY_ELEMENT3
BuildSourceExportClosureTask -> EXPORT_SOURCE_CLOSURE
BuildTypeProviderTask -> TYPE_PROVIDER
@@ -91,6 +90,7 @@
EXPORTED_LIBRARIES -> ResolveTopLevelLibraryTypeBoundsTask
EXPORTED_LIBRARIES [shape=box]
EXPORT_SOURCE_CLOSURE -> BuildExportNamespaceTask
+ EXPORT_SOURCE_CLOSURE -> ResolveTopLevelUnitTypeBoundsTask
EXPORT_SOURCE_CLOSURE [shape=box]
EvaluateUnitConstantsTask -> CREATED_RESOLVED_UNIT13
EvaluateUnitConstantsTask -> RESOLVED_UNIT13
@@ -211,6 +211,7 @@
ParseDartTask -> LIBRARY_SPECIFIC_UNITS
ParseDartTask -> PARSED_UNIT
ParseDartTask -> PARSE_ERRORS
+ ParseDartTask -> REFERENCED_NAMES
ParseDartTask -> REFERENCED_SOURCES
ParseDartTask -> SOURCE_KIND
ParseDartTask -> UNITS
diff --git a/pkg/analyzer_cli/lib/src/driver.dart b/pkg/analyzer_cli/lib/src/driver.dart
index 44cc1d1..46316b7 100644
--- a/pkg/analyzer_cli/lib/src/driver.dart
+++ b/pkg/analyzer_cli/lib/src/driver.dart
@@ -523,7 +523,7 @@
_PackageInfo _findPackages(CommandLineOptions options) {
if (packageResolverProvider != null) {
// The resolver provider will do all the work later.
- return null;
+ return new _PackageInfo(null, null);
}
Packages packages;
@@ -648,6 +648,8 @@
contextOptions.generateSdkErrors = options.showSdkWarnings;
contextOptions.lint = options.lints;
contextOptions.strongMode = options.strongMode;
+ contextOptions.implicitCasts = options.implicitCasts;
+ contextOptions.implicitDynamic = options.implicitDynamic;
return contextOptions;
}
diff --git a/pkg/analyzer_cli/lib/src/options.dart b/pkg/analyzer_cli/lib/src/options.dart
index 3706464..030f1bf 100644
--- a/pkg/analyzer_cli/lib/src/options.dart
+++ b/pkg/analyzer_cli/lib/src/options.dart
@@ -150,6 +150,12 @@
/// Whether to use strong static checking.
final bool strongMode;
+ /// Whether implicit casts are enabled (in strong mode)
+ final bool implicitCasts;
+
+ /// Whether implicit dynamic is enabled (mainly for strong mode users)
+ final bool implicitDynamic;
+
/// Whether to treat lints as fatal
final bool lintsAreFatal;
@@ -197,6 +203,8 @@
sourceFiles = args.rest,
warningsAreFatal = args['fatal-warnings'],
strongMode = args['strong'],
+ implicitCasts = !args['no-implicit-casts'],
+ implicitDynamic = !args['no-implicit-dynamic'],
lintsAreFatal = args['fatal-lints'];
/// Parse [args] into [CommandLineOptions] describing the specified
@@ -478,7 +486,13 @@
negatable: false,
hide: true)
..addFlag('strong',
- help: 'Enable strong static checks (https://goo.gl/DqcBsw)');
+ help: 'Enable strong static checks (https://goo.gl/DqcBsw)')
+ ..addFlag('no-implicit-casts',
+ negatable: false,
+ help: 'Disable implicit casts in strong mode (https://goo.gl/cTLz40)')
+ ..addFlag('no-implicit-dynamic',
+ negatable: false,
+ help: 'Disable implicit dynamic (https://goo.gl/m0UgXD)');
try {
// TODO(scheglov) https://code.google.com/p/dart/issues/detail?id=11061
diff --git a/pkg/compiler/lib/src/closure.dart b/pkg/compiler/lib/src/closure.dart
index b0f01b8..0cffc40 100644
--- a/pkg/compiler/lib/src/closure.dart
+++ b/pkg/compiler/lib/src/closure.dart
@@ -255,6 +255,9 @@
final String name;
final ExecutableElement executableContext;
+ final int hashCode = _nextHashCode = (_nextHashCode + 10007).toUnsigned(30);
+ static int _nextHashCode = 0;
+
BoxLocal(this.name, this.executableContext);
String toString() => 'BoxLocal($name)';
@@ -326,7 +329,7 @@
/// A local variable used encode the direct (uncaptured) references to [this].
class ThisLocal extends Local {
final ExecutableElement executableContext;
- final hashCode = ++ElementX.elementHashCode;
+ final hashCode = ElementX.newHashCode();
ThisLocal(this.executableContext);
@@ -1125,7 +1128,7 @@
visitFunctionExpression(FunctionExpression node) {
Element element = elements[node];
- if (element.isParameter) {
+ if (element.isRegularParameter) {
// TODO(ahe): This is a hack. This method should *not* call
// visitChildren.
return node.name.accept(this);
diff --git a/pkg/compiler/lib/src/common/backend_api.dart b/pkg/compiler/lib/src/common/backend_api.dart
index c4c9020..5582734 100644
--- a/pkg/compiler/lib/src/common/backend_api.dart
+++ b/pkg/compiler/lib/src/common/backend_api.dart
@@ -17,15 +17,8 @@
import '../constants/values.dart' show ConstantValue;
import '../dart_types.dart' show DartType, InterfaceType;
import '../elements/elements.dart'
- show
- ClassElement,
- Element,
- FunctionElement,
- LibraryElement,
- MetadataAnnotation,
- MethodElement;
-import '../enqueue.dart'
- show Enqueuer, EnqueueTask, CodegenEnqueuer, ResolutionEnqueuer;
+ show ClassElement, Element, FunctionElement, LibraryElement;
+import '../enqueue.dart' show Enqueuer, EnqueueTask, ResolutionEnqueuer;
import '../io/code_output.dart' show CodeBuffer;
import '../io/source_information.dart' show SourceInformationStrategy;
import '../js_backend/backend_helpers.dart' as js_backend show BackendHelpers;
@@ -36,8 +29,7 @@
show checkNativeAnnotation, checkJsInteropAnnotation;
import '../serialization/serialization.dart'
show DeserializerPlugin, SerializerPlugin;
-import '../tree/tree.dart' show Node, Send;
-import '../universe/call_structure.dart' show CallStructure;
+import '../tree/tree.dart' show Node;
import '../universe/world_impact.dart' show ImpactStrategy, WorldImpact;
import 'codegen.dart' show CodegenWorkItem;
import 'registry.dart' show Registry;
@@ -52,9 +44,6 @@
/// Returns true if the backend supports reflection.
bool get supportsReflection;
- /// Returns true if the backend supports reflection.
- bool get supportsAsyncAwait;
-
/// The [ConstantSystem] used to interpret compile-time constants for this
/// backend.
ConstantSystem get constantSystem;
@@ -229,14 +218,6 @@
bool isInterceptorClass(ClassElement element) => false;
- /// Returns `true` if [element] is a foreign element, that is, that the
- /// backend has specialized handling for the element.
- bool isForeign(Element element) => false;
-
- /// Returns `true` if [element] is a native element, that is, that the
- /// corresponding entity already exists in the target language.
- bool isNative(Element element) => false;
-
/// Returns `true` if [element] is implemented via typed JavaScript interop.
// TODO(johnniwinther): Move this to [JavaScriptBackend].
bool isJsInterop(Element element) => false;
@@ -247,10 +228,6 @@
return native.maybeEnableNative(compiler, library);
}
- /// Processes [element] for resolution and returns the [MethodElement] that
- /// defines the implementation of [element].
- MethodElement resolveExternalFunction(MethodElement element) => element;
-
@override
bool isTargetSpecificLibrary(LibraryElement library) {
// TODO(johnniwinther): Remove this when patching is only done by the
@@ -375,12 +352,6 @@
void registerAsyncMarker(
FunctionElement element, Enqueuer enqueuer, Registry registry) {}
- /// Called when resolving a call to a foreign function. If a non-null value
- /// is returned, this is stored as native data for [node] in the resolved
- /// AST.
- dynamic resolveForeignCall(Send node, Element element,
- CallStructure callStructure, ForeignResolver resolver) {}
-
/// Returns the location of the patch-file associated with [libraryName]
/// resolved from [plaformConfigUri].
///
diff --git a/pkg/compiler/lib/src/common/resolution.dart b/pkg/compiler/lib/src/common/resolution.dart
index 515aa68..d48603d 100644
--- a/pkg/compiler/lib/src/common/resolution.dart
+++ b/pkg/compiler/lib/src/common/resolution.dart
@@ -6,27 +6,35 @@
import '../common.dart';
import '../compiler.dart' show Compiler;
+import '../compile_time_constants.dart';
import '../constants/expressions.dart' show ConstantExpression;
+import '../constants/values.dart' show ConstantValue;
import '../core_types.dart' show CoreClasses, CoreTypes;
import '../dart_types.dart' show DartType, InterfaceType, Types;
import '../elements/elements.dart'
show
AstElement,
ClassElement,
+ ConstructorElement,
Element,
ExecutableElement,
FunctionElement,
FunctionSignature,
LibraryElement,
MetadataAnnotation,
+ MethodElement,
ResolvedAst,
TypedefElement;
import '../enqueue.dart' show ResolutionEnqueuer;
-import '../options.dart' show ParserOptions;
+import '../id_generator.dart';
+import '../mirrors_used.dart';
+import '../options.dart' show CompilerOptions, ParserOptions;
import '../parser/element_listener.dart' show ScannerOptions;
import '../parser/parser_task.dart';
import '../patch_parser.dart';
-import '../tree/tree.dart' show TypeAnnotation;
+import '../resolution/resolution.dart';
+import '../tree/tree.dart' show Send, TypeAnnotation;
+import '../universe/call_structure.dart' show CallStructure;
import '../universe/world_impact.dart' show WorldImpact;
import 'backend_api.dart';
import 'work.dart' show ItemCompilationContext, WorkItem;
@@ -55,9 +63,8 @@
Iterable<MapLiteralUse> get mapLiterals => const <MapLiteralUse>[];
Iterable<ListLiteralUse> get listLiterals => const <ListLiteralUse>[];
Iterable<String> get constSymbolNames => const <String>[];
- Iterable<ConstantExpression> get constantLiterals {
- return const <ConstantExpression>[];
- }
+ Iterable<ConstantExpression> get constantLiterals =>
+ const <ConstantExpression>[];
Iterable<dynamic> get nativeData => const <dynamic>[];
}
@@ -206,6 +213,32 @@
/// Resolve target specific information for [element] and register it with
/// [registry].
void resolveNativeElement(Element element, NativeRegistry registry) {}
+
+ /// Processes [element] for resolution and returns the [MethodElement] that
+ /// defines the implementation of [element].
+ MethodElement resolveExternalFunction(MethodElement element) => element;
+
+ /// Called when resolving a call to a foreign function. If a non-null value
+ /// is returned, this is stored as native data for [node] in the resolved
+ /// AST.
+ dynamic resolveForeignCall(Send node, Element element,
+ CallStructure callStructure, ForeignResolver resolver) {
+ return null;
+ }
+
+ /// Returns the default superclass for the given [element] in this target.
+ ClassElement defaultSuperclass(ClassElement element);
+
+ /// Returns `true` if [element] is a native element, that is, that the
+ /// corresponding entity already exists in the target language.
+ bool isNative(Element element) => false;
+
+ /// Returns `true` if [element] is a foreign element, that is, that the
+ /// backend has specialized handling for the element.
+ bool isForeign(Element element) => false;
+
+ /// Returns `true` if this target supports async/await.
+ bool get supportsAsyncAwait => true;
}
// TODO(johnniwinther): Rename to `Resolver` or `ResolverContext`.
@@ -216,6 +249,24 @@
CoreTypes get coreTypes;
Types get types;
Target get target;
+ ResolverTask get resolver;
+ ResolutionEnqueuer get enqueuer;
+ CompilerOptions get options;
+ IdGenerator get idGenerator;
+ ConstantEnvironment get constants;
+ MirrorUsageAnalyzerTask get mirrorUsageAnalyzerTask;
+
+ // TODO(het): Move all elements into common/elements.dart
+ LibraryElement get coreLibrary;
+ FunctionElement get identicalFunction;
+ ClassElement get mirrorSystemClass;
+ FunctionElement get mirrorSystemGetNameFunction;
+ ConstructorElement get mirrorsUsedConstructor;
+ ConstructorElement get symbolConstructor;
+
+ // TODO(het): This is only referenced in a test...
+ /// The constant for the [proxy] variable defined in dart:core.
+ ConstantValue get proxyConstant;
/// If set to `true` resolution caches will not be cleared. Use this only for
/// testing.
@@ -237,6 +288,14 @@
/// Resolve [element] if it has not already been resolved.
void ensureResolved(Element element);
+ /// Called whenever a class has been resolved.
+ void onClassResolved(ClassElement element);
+
+ /// Registers that [element] has a compile time error.
+ ///
+ /// The error itself is given in [message].
+ void registerCompileTimeError(Element element, DiagnosticMessage message);
+
ResolutionWorkItem createWorkItem(
Element element, ItemCompilationContext compilationContext);
@@ -274,6 +333,10 @@
void emptyCache();
void forgetElement(Element element);
+
+ /// Returns `true` if [value] is the top-level [proxy] annotation from the
+ /// core library.
+ bool isProxyConstant(ConstantValue value);
}
/// A container of commonly used dependencies for tasks that involve parsing.
diff --git a/pkg/compiler/lib/src/common/tasks.dart b/pkg/compiler/lib/src/common/tasks.dart
index f1d3426..100181c 100644
--- a/pkg/compiler/lib/src/common/tasks.dart
+++ b/pkg/compiler/lib/src/common/tasks.dart
@@ -211,6 +211,9 @@
/// Whether measurement of tasks is enabled.
final bool enableTaskMeasurements;
+ static int _hashCodeGenerator = 197;
+ final int hashCode = _hashCodeGenerator++;
+
Measurer({this.enableTaskMeasurements: false});
/// The currently running task, that is, the task whose [Stopwatch] is
diff --git a/pkg/compiler/lib/src/compiler.dart b/pkg/compiler/lib/src/compiler.dart
index d567bba..7f73dcc 100644
--- a/pkg/compiler/lib/src/compiler.dart
+++ b/pkg/compiler/lib/src/compiler.dart
@@ -166,9 +166,6 @@
ClassElement typedDataClass;
- /// The constant for the [proxy] variable defined in dart:core.
- ConstantValue proxyConstant;
-
// TODO(johnniwinther): Move this to the JavaScriptBackend.
/// The class for patch annotation defined in dart:_js_helper.
ClassElement patchAnnotationClass;
@@ -373,7 +370,8 @@
///
/// Override this to mock the resolver for testing.
ResolverTask createResolverTask() {
- return new ResolverTask(this, backend.constantCompilerTask);
+ return new ResolverTask(
+ resolution, backend.constantCompilerTask, world, measurer);
}
Universe get resolverWorld => enqueuer.resolution.universe;
@@ -386,6 +384,8 @@
bool get disableTypeInference =>
options.disableTypeInference || compilationFailed;
+ // TODO(het): remove this from here. Either inline at all use sites or add it
+ // to Reporter.
void unimplemented(Spannable spannable, String methodName) {
reporter.internalError(spannable, "$methodName not implemented.");
}
@@ -581,17 +581,6 @@
}).then((_) => backend.onLibrariesLoaded(loadedLibraries));
}
- bool isProxyConstant(ConstantValue value) {
- FieldElement field = coreLibrary.find('proxy');
- if (field == null) return false;
- if (!resolution.hasBeenResolved(field)) return false;
- if (proxyConstant == null) {
- proxyConstant = constants
- .getConstantValue(resolver.constantCompiler.compileConstant(field));
- }
- return proxyConstant == value;
- }
-
Element findRequiredElement(LibraryElement library, String name) {
var element = library.find(name);
if (element == null) {
@@ -851,7 +840,7 @@
}
}
- if (options.resolveOnly) {
+ if (options.resolveOnly && !compilationFailed) {
reporter.log('Serializing to ${options.resolutionOutput}');
serialization
.serializeToSink(userOutputProvider.createEventSink('', 'data'),
@@ -1129,7 +1118,7 @@
if (markCompilationAsFailed(message, kind)) {
compilationFailed = true;
}
- registerCompiletimeError(currentElement, message);
+ registerCompileTimeError(currentElement, message);
}
/**
@@ -1272,7 +1261,7 @@
}
/// Associate [element] with a compile-time error [message].
- void registerCompiletimeError(Element element, DiagnosticMessage message) {
+ void registerCompileTimeError(Element element, DiagnosticMessage message) {
// The information is only needed if [generateCodeWithCompileTimeErrors].
if (options.generateCodeWithCompileTimeErrors) {
if (element == null) {
@@ -1553,7 +1542,7 @@
} else {
errorElement = currentElement;
}
- compiler.registerCompiletimeError(errorElement, message);
+ compiler.registerCompileTimeError(errorElement, message);
compiler.fatalDiagnosticReported(message, infos, kind);
}
}
@@ -1906,6 +1895,48 @@
Target get target => compiler.backend;
@override
+ ResolverTask get resolver => compiler.resolver;
+
+ @override
+ ResolutionEnqueuer get enqueuer => compiler.enqueuer.resolution;
+
+ @override
+ CompilerOptions get options => compiler.options;
+
+ @override
+ IdGenerator get idGenerator => compiler.idGenerator;
+
+ @override
+ ConstantEnvironment get constants => compiler.constants;
+
+ @override
+ MirrorUsageAnalyzerTask get mirrorUsageAnalyzerTask =>
+ compiler.mirrorUsageAnalyzerTask;
+
+ @override
+ LibraryElement get coreLibrary => compiler.coreLibrary;
+
+ @override
+ FunctionElement get identicalFunction => compiler.identicalFunction;
+
+ @override
+ ClassElement get mirrorSystemClass => compiler.mirrorSystemClass;
+
+ @override
+ FunctionElement get mirrorSystemGetNameFunction =>
+ compiler.mirrorSystemGetNameFunction;
+
+ @override
+ ConstructorElement get mirrorsUsedConstructor =>
+ compiler.mirrorsUsedConstructor;
+
+ @override
+ ConstructorElement get symbolConstructor => compiler.symbolConstructor;
+
+ @override
+ ConstantValue proxyConstant;
+
+ @override
void registerClass(ClassElement cls) {
compiler.world.registerClass(cls);
}
@@ -1944,6 +1975,14 @@
}
@override
+ void onClassResolved(ClassElement element) =>
+ compiler.onClassResolved(element);
+
+ @override
+ void registerCompileTimeError(Element element, DiagnosticMessage message) =>
+ compiler.registerCompileTimeError(element, message);
+
+ @override
bool hasResolvedAst(ExecutableElement element) {
assert(invariant(element, element.isDeclaration,
message: "Element $element must be the declaration."));
@@ -2084,6 +2123,18 @@
_worldImpactCache.remove(element);
_resolutionImpactCache.remove(element);
}
+
+ @override
+ bool isProxyConstant(ConstantValue value) {
+ FieldElement field = coreLibrary.find('proxy');
+ if (field == null) return false;
+ if (!hasBeenResolved(field)) return false;
+ if (proxyConstant == null) {
+ proxyConstant = constants
+ .getConstantValue(resolver.constantCompiler.compileConstant(field));
+ }
+ return proxyConstant == value;
+ }
}
class GlobalDependencyRegistry extends EagerRegistry {
diff --git a/pkg/compiler/lib/src/constants/expressions.dart b/pkg/compiler/lib/src/constants/expressions.dart
index 922ae06..9eb3fdc 100644
--- a/pkg/compiler/lib/src/constants/expressions.dart
+++ b/pkg/compiler/lib/src/constants/expressions.dart
@@ -101,12 +101,7 @@
int _computeHashCode();
- int get hashCode {
- if (_hashCode == null) {
- _hashCode = _computeHashCode();
- }
- return _hashCode;
- }
+ int get hashCode => _hashCode ??= _computeHashCode();
bool _equals(ConstantExpression other);
@@ -482,11 +477,15 @@
@override
ConstantValue evaluate(
Environment environment, ConstantSystem constantSystem) {
- return constantSystem.createMap(
- environment.compiler,
- type,
- keys.map((k) => k.evaluate(environment, constantSystem)).toList(),
- values.map((v) => v.evaluate(environment, constantSystem)).toList());
+ Map<ConstantValue, ConstantValue> valueMap =
+ <ConstantValue, ConstantValue>{};
+ for (int index = 0; index < keys.length; index++) {
+ ConstantValue key = keys[index].evaluate(environment, constantSystem);
+ ConstantValue value = values[index].evaluate(environment, constantSystem);
+ valueMap[key] = value;
+ }
+ return constantSystem.createMap(environment.compiler, type,
+ valueMap.keys.toList(), valueMap.values.toList());
}
ConstantExpression apply(NormalizedArguments arguments) {
@@ -654,7 +653,7 @@
for (ConstantExpression expression in expressions) {
ConstantValue value = expression.evaluate(environment, constantSystem);
DartString valueString;
- if (value.isNum || value.isBool) {
+ if (value.isNum || value.isBool || value.isNull) {
PrimitiveConstantValue primitive = value;
valueString =
new DartString.literal(primitive.primitiveValue.toString());
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 28cc94a..80f149d 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
@@ -3859,7 +3859,7 @@
if (Elements.isLocal(element)) {
LocalElement local = element;
if (insideInitializer &&
- (local.isParameter || local.isInitializingFormal) &&
+ (local.isRegularParameter || local.isInitializingFormal) &&
local.enclosingElement == currentFunction) {
assert(local.enclosingElement.isConstructor);
// Initializers in an initializer-list can communicate via parameters.
@@ -3871,7 +3871,7 @@
// outlive the activation of the function).
markAsCaptured(local);
} else if (inTryStatement) {
- assert(local.isParameter ||
+ assert(local.isRegularParameter ||
local.isVariable ||
local.isInitializingFormal);
// Search for the position of the try block containing the variable
diff --git a/pkg/compiler/lib/src/dart2js.dart b/pkg/compiler/lib/src/dart2js.dart
index 4301a55..1b41be1 100644
--- a/pkg/compiler/lib/src/dart2js.dart
+++ b/pkg/compiler/lib/src/dart2js.dart
@@ -878,7 +878,8 @@
}
}
}
- options = options.copy(resolutionInputs: resolutionInputs);
+ options =
+ CompilerOptions.copy(options, resolutionInputs: resolutionInputs);
}
return oldCompileFunc(options, input, compilerDiagnostics, compilerOutput);
}
@@ -892,15 +893,12 @@
api.CompilerDiagnostics compilerDiagnostics,
api.CompilerOutput compilerOutput,
[List<_SerializedData> serializedData]) {
- CompilerOptions options = new CompilerOptions.parse(
+ CompilerOptions options = CompilerOptions.copy(compilerOptions,
entryPoint: entryPoint,
- libraryRoot: compilerOptions.libraryRoot,
- packageRoot: compilerOptions.packageRoot,
- packageConfig: compilerOptions.packageConfig,
- packagesDiscoveryProvider: compilerOptions.packagesDiscoveryProvider,
- environment: compilerOptions.environment,
resolutionOutput: serializedUri,
- options: [Flags.resolveOnly]);
+ analyzeAll: true,
+ analyzeOnly: true,
+ resolveOnly: true);
return compileWithSerializedData(options, compilerInput,
compilerDiagnostics, compilerOutput, serializedData);
}
diff --git a/pkg/compiler/lib/src/dart_backend/backend.dart b/pkg/compiler/lib/src/dart_backend/backend.dart
index 371eed6..c9d69ae 100644
--- a/pkg/compiler/lib/src/dart_backend/backend.dart
+++ b/pkg/compiler/lib/src/dart_backend/backend.dart
@@ -20,8 +20,6 @@
bool get supportsReflection => true;
- bool get supportsAsyncAwait => true;
-
// TODO(zarah) Maybe change this to a command-line option.
// Right now, it is set by the tests.
bool useMirrorHelperLibrary = false;
diff --git a/pkg/compiler/lib/src/dart_backend/placeholder_collector.dart b/pkg/compiler/lib/src/dart_backend/placeholder_collector.dart
index e6656a7..65f2576 100644
--- a/pkg/compiler/lib/src/dart_backend/placeholder_collector.dart
+++ b/pkg/compiler/lib/src/dart_backend/placeholder_collector.dart
@@ -277,7 +277,7 @@
}
return false;
}
- if (element.isParameter &&
+ if (element.isRegularParameter &&
!isTypedefParameter(element) &&
isNamedOptionalParameter()) {
currentFunctionScope.registerParameter(node);
diff --git a/pkg/compiler/lib/src/dart_types.dart b/pkg/compiler/lib/src/dart_types.dart
index fb0eac4..271d09f 100644
--- a/pkg/compiler/lib/src/dart_types.dart
+++ b/pkg/compiler/lib/src/dart_types.dart
@@ -10,7 +10,7 @@
import 'common.dart';
import 'core_types.dart';
import 'elements/elements.dart';
-import 'elements/modelx.dart' show TypeDeclarationElementX, ErroneousElementX;
+import 'elements/modelx.dart' show TypeDeclarationElementX;
import 'ordered_typeset.dart' show OrderedTypeSet;
import 'util/util.dart' show equalElements;
@@ -298,6 +298,8 @@
}
String toString() => name;
+
+ int get hashCode => 6007;
}
class MalformedType extends DartType {
@@ -323,8 +325,8 @@
*/
final List<DartType> typeArguments;
- final int hashCode = (nextHash++) & 0x3fffffff;
- static int nextHash = 43765;
+ final int hashCode = _nextHash = (_nextHash + 1).toUnsigned(30);
+ static int _nextHash = 43765;
MalformedType(this.element, this.userProvidedBadType,
[this.typeArguments = null]);
@@ -845,6 +847,10 @@
void computeUnaliased(Resolution resolution) {
if (_unaliased == null) {
element.ensureResolved(resolution);
+ if (element.isMalformed) {
+ _unaliased = const DynamicType();
+ return;
+ }
element.checkCyclicReference(resolution);
element.alias.computeUnaliased(resolution);
_unaliased = element.alias.unaliased.substByContext(this);
diff --git a/pkg/compiler/lib/src/deferred_load.dart b/pkg/compiler/lib/src/deferred_load.dart
index 0f4f8d7..b45d3012 100644
--- a/pkg/compiler/lib/src/deferred_load.dart
+++ b/pkg/compiler/lib/src/deferred_load.dart
@@ -978,6 +978,10 @@
/// Computes a suggestive name for this import.
String computeImportDeferName(Compiler compiler) => 'main';
+
+ ImportElement get declaration => null;
+
+ String toString() => 'main';
}
/// A node in the deferred import graph defined by a deferred import directive.
@@ -1024,4 +1028,6 @@
}
int get hashCode => declaration.hashCode * 17;
+
+ String toString() => '$declaration';
}
diff --git a/pkg/compiler/lib/src/diagnostics/messages.dart b/pkg/compiler/lib/src/diagnostics/messages.dart
index dbcab63..11c0000 100644
--- a/pkg/compiler/lib/src/diagnostics/messages.dart
+++ b/pkg/compiler/lib/src/diagnostics/messages.dart
@@ -100,7 +100,6 @@
BEFORE_TOP_LEVEL,
BINARY_OPERATOR_BAD_ARITY,
BODY_EXPECTED,
- CALL_NOT_SUPPORTED_ON_NATIVE_CLASS,
CANNOT_EXTEND,
CANNOT_EXTEND_ENUM,
CANNOT_EXTEND_MALFORMED,
@@ -186,9 +185,11 @@
DUPLICATED_RESOURCE,
EMPTY_CATCH_DECLARATION,
EMPTY_ENUM_DECLARATION,
+ EMPTY_NAMED_PARAMETER_LIST,
+ EMPTY_OPTIONAL_PARAMETER_LIST,
EMPTY_HIDE,
- EQUAL_MAP_ENTRY_KEY,
EMPTY_SHOW,
+ EQUAL_MAP_ENTRY_KEY,
EXISTING_DEFINITION,
EXISTING_LABEL,
EXPECTED_IDENTIFIER_NOT_RESERVED_WORD,
@@ -878,6 +879,36 @@
},
]),
+ MessageKind.EMPTY_OPTIONAL_PARAMETER_LIST: const MessageTemplate(
+ MessageKind.EMPTY_OPTIONAL_PARAMETER_LIST,
+ "Optional parameter lists cannot be empty.",
+ howToFix: "Try adding an optional parameter to the list.",
+ examples: const [
+ const {
+ 'main.dart': """
+foo([]) {}
+
+main() {
+ foo();
+}"""
+ }
+ ]),
+
+ MessageKind.EMPTY_NAMED_PARAMETER_LIST: const MessageTemplate(
+ MessageKind.EMPTY_NAMED_PARAMETER_LIST,
+ "Named parameter lists cannot be empty.",
+ howToFix: "Try adding a named parameter to the list.",
+ examples: const [
+ const {
+ 'main.dart': """
+foo({}) {}
+
+main() {
+ foo();
+}"""
+ }
+ ]),
+
MessageKind.NOT_A_TYPE: const MessageTemplate(
MessageKind.NOT_A_TYPE, "'#{node}' is not a type."),
@@ -3671,11 +3702,6 @@
"""
$MIRRORS_NOT_SUPPORTED_BY_BACKEND_PADDING#{importChain}"""),
- 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."),
-
MessageKind.DIRECTLY_THROWING_NSM: const MessageTemplate(
MessageKind.DIRECTLY_THROWING_NSM,
"This 'noSuchMethod' implementation is guaranteed to throw an "
diff --git a/pkg/compiler/lib/src/elements/common.dart b/pkg/compiler/lib/src/elements/common.dart
index 5ff8341..0eb92a6 100644
--- a/pkg/compiler/lib/src/elements/common.dart
+++ b/pkg/compiler/lib/src/elements/common.dart
@@ -67,7 +67,7 @@
bool get isAbstractField => kind == ElementKind.ABSTRACT_FIELD;
@override
- bool get isParameter => kind == ElementKind.PARAMETER;
+ bool get isRegularParameter => kind == ElementKind.PARAMETER;
@override
bool get isInitializingFormal => kind == ElementKind.INITIALIZING_FORMAL;
diff --git a/pkg/compiler/lib/src/elements/elements.dart b/pkg/compiler/lib/src/elements/elements.dart
index 52f5f30..aac0b0d 100644
--- a/pkg/compiler/lib/src/elements/elements.dart
+++ b/pkg/compiler/lib/src/elements/elements.dart
@@ -254,18 +254,22 @@
/// explicit getter and/or setter.
bool get isAbstractField;
- /// `true` if this element is formal parameter either from a constructor,
- /// method, or typedef declaration or from an inlined function typed
+ /// `true` if this element is a formal parameter from a constructor,
+ /// a method, a typedef declaration, or from an inlined function typed
/// parameter.
///
/// This property is `false` if this element is an initializing formal.
/// See [isInitializingFormal].
- bool get isParameter;
+ bool get isRegularParameter;
/// `true` if this element is an initializing formal of constructor, that
/// is a formal of the form `this.foo`.
bool get isInitializingFormal;
+ /// `true` if this element is a formal parameter, either regular or
+ /// initializing.
+ bool get isParameter => isRegularParameter || isInitializingFormal;
+
/// `true` if this element represents a resolution error.
bool get isError;
@@ -590,45 +594,45 @@
static String operatorNameToIdentifier(String name) {
if (name == null) {
return name;
- } else if (identical(name, '==')) {
+ } else if (name == '==') {
return r'operator$eq';
- } else if (identical(name, '~')) {
+ } else if (name == '~') {
return r'operator$not';
- } else if (identical(name, '[]')) {
+ } else if (name == '[]') {
return r'operator$index';
- } else if (identical(name, '[]=')) {
+ } else if (name == '[]=') {
return r'operator$indexSet';
- } else if (identical(name, '*')) {
+ } else if (name == '*') {
return r'operator$mul';
- } else if (identical(name, '/')) {
+ } else if (name == '/') {
return r'operator$div';
- } else if (identical(name, '%')) {
+ } else if (name == '%') {
return r'operator$mod';
- } else if (identical(name, '~/')) {
+ } else if (name == '~/') {
return r'operator$tdiv';
- } else if (identical(name, '+')) {
+ } else if (name == '+') {
return r'operator$add';
- } else if (identical(name, '<<')) {
+ } else if (name == '<<') {
return r'operator$shl';
- } else if (identical(name, '>>')) {
+ } else if (name == '>>') {
return r'operator$shr';
- } else if (identical(name, '>=')) {
+ } else if (name == '>=') {
return r'operator$ge';
- } else if (identical(name, '>')) {
+ } else if (name == '>') {
return r'operator$gt';
- } else if (identical(name, '<=')) {
+ } else if (name == '<=') {
return r'operator$le';
- } else if (identical(name, '<')) {
+ } else if (name == '<') {
return r'operator$lt';
- } else if (identical(name, '&')) {
+ } else if (name == '&') {
return r'operator$and';
- } else if (identical(name, '^')) {
+ } else if (name == '^') {
return r'operator$xor';
- } else if (identical(name, '|')) {
+ } else if (name == '|') {
return r'operator$or';
- } else if (identical(name, '-')) {
+ } else if (name == '-') {
return r'operator$sub';
- } else if (identical(name, 'unary-')) {
+ } else if (name == 'unary-') {
return r'operator$negate';
} else {
return name;
@@ -936,6 +940,8 @@
abstract class PrefixElement extends Element {
Element lookupLocalMember(String memberName);
+ void forEachLocalMember(void f(Element member));
+
/// Is true if this prefix belongs to a deferred import.
bool get isDeferred;
diff --git a/pkg/compiler/lib/src/elements/modelx.dart b/pkg/compiler/lib/src/elements/modelx.dart
index bb331d9..265eb2e 100644
--- a/pkg/compiler/lib/src/elements/modelx.dart
+++ b/pkg/compiler/lib/src/elements/modelx.dart
@@ -39,12 +39,14 @@
abstract class DeclarationSite {}
abstract class ElementX extends Element with ElementCommon {
- static int elementHashCode = 0;
+ static int _elementHashCode = 0;
+ static int newHashCode() =>
+ _elementHashCode = (_elementHashCode + 1).toUnsigned(30);
final String name;
final ElementKind kind;
final Element enclosingElement;
- final int hashCode = ++elementHashCode;
+ final int hashCode = newHashCode();
List<MetadataAnnotation> metadataInternal;
ElementX(this.name, this.kind, this.enclosingElement) {
@@ -398,8 +400,18 @@
}
@override
- set immediateRedirectionTarget(_) {
- throw new UnsupportedError("immediateRedirectionTarget=");
+ get _immediateRedirectionTarget {
+ throw new UnsupportedError("_immediateRedirectionTarget");
+ }
+
+ @override
+ set _immediateRedirectionTarget(_) {
+ throw new UnsupportedError("_immediateRedirectionTarget=");
+ }
+
+ @override
+ setImmediateRedirectionTarget(a, b) {
+ throw new UnsupportedError("setImmediateRedirectionTarget");
}
@override
@@ -428,8 +440,13 @@
}
@override
- set redirectionDeferredPrefix(_) {
- throw new UnsupportedError("redirectionDeferredPrefix=");
+ get _redirectionDeferredPrefix {
+ throw new UnsupportedError("_redirectionDeferredPrefix");
+ }
+
+ @override
+ set _redirectionDeferredPrefix(_) {
+ throw new UnsupportedError("_redirectionDeferredPrefix=");
}
}
@@ -437,7 +454,7 @@
class WrappedMessage {
/// The message position. If [:null:] the position of the reference to the
/// [WarnOnUseElementX] is used.
- final Spannable spannable;
+ final SourceSpan sourceSpan;
/**
* The message to report on resolving a wrapped element.
@@ -449,7 +466,7 @@
*/
final Map messageArguments;
- WrappedMessage(this.spannable, this.messageKind, this.messageArguments);
+ WrappedMessage(this.sourceSpan, this.messageKind, this.messageArguments);
}
class WarnOnUseElementX extends ElementX implements WarnOnUseElement {
@@ -462,21 +479,21 @@
/// The element whose usage cause a warning.
final Element wrappedElement;
- WarnOnUseElementX(WrappedMessage this.warning, WrappedMessage this.info,
- Element enclosingElement, Element wrappedElement)
+ WarnOnUseElementX(
+ this.warning, this.info, Element enclosingElement, Element wrappedElement)
: this.wrappedElement = wrappedElement,
super(wrappedElement.name, ElementKind.WARN_ON_USE, enclosingElement);
Element unwrap(DiagnosticReporter reporter, Spannable usageSpannable) {
var unwrapped = wrappedElement;
if (warning != null) {
- Spannable spannable = warning.spannable;
+ Spannable spannable = warning.sourceSpan;
if (spannable == null) spannable = usageSpannable;
DiagnosticMessage warningMessage = reporter.createMessage(
spannable, warning.messageKind, warning.messageArguments);
List<DiagnosticMessage> infos = <DiagnosticMessage>[];
if (info != null) {
- Spannable spannable = info.spannable;
+ Spannable spannable = info.sourceSpan;
if (spannable == null) spannable = usageSpannable;
infos.add(reporter.createMessage(
spannable, info.messageKind, info.messageArguments));
@@ -930,8 +947,11 @@
}
class SyntheticImportElement extends ImportElementX {
- SyntheticImportElement(CompilationUnitElement enclosingElement, Uri uri)
- : super(enclosingElement, null, uri);
+ SyntheticImportElement(CompilationUnitElement enclosingElement, Uri uri,
+ LibraryElement libraryDependency)
+ : super(enclosingElement, null, uri) {
+ this.libraryDependency = libraryDependency;
+ }
@override
Token get position => library.position;
@@ -1247,6 +1267,8 @@
Element lookupLocalMember(String memberName) => importScope[memberName];
+ void forEachLocalMember(f(Element member)) => importScope.forEach(f);
+
DartType computeType(Resolution resolution) => const DynamicType();
Token get position => firstPosition;
@@ -2197,8 +2219,10 @@
String name, ElementKind kind, Modifiers modifiers, Element enclosing)
: super(name, kind, modifiers, enclosing);
- FunctionElement immediateRedirectionTarget;
- PrefixElement redirectionDeferredPrefix;
+ ConstructorElement _immediateRedirectionTarget;
+ PrefixElement _redirectionDeferredPrefix;
+
+ ConstructorElementX get patch => super.patch;
bool get isRedirectingFactory => immediateRedirectionTarget != null;
@@ -2211,45 +2235,93 @@
DartType _effectiveTargetType;
bool _isEffectiveTargetMalformed;
- bool get hasEffectiveTarget => effectiveTargetInternal != null;
+ bool get hasEffectiveTarget {
+ if (isPatched) {
+ return patch.hasEffectiveTarget;
+ }
+ return effectiveTargetInternal != null;
+ }
+
+ void setImmediateRedirectionTarget(
+ ConstructorElement target, PrefixElement prefix) {
+ if (isPatched) {
+ patch.setImmediateRedirectionTarget(target, prefix);
+ } else {
+ assert(invariant(this, _immediateRedirectionTarget == null,
+ message: "Immediate redirection target has already been "
+ "set on $this."));
+ _immediateRedirectionTarget = target;
+ _redirectionDeferredPrefix = prefix;
+ }
+ }
+
+ ConstructorElement get immediateRedirectionTarget {
+ if (isPatched) {
+ return patch.immediateRedirectionTarget;
+ }
+ return _immediateRedirectionTarget;
+ }
+
+ PrefixElement get redirectionDeferredPrefix {
+ if (isPatched) {
+ return patch.redirectionDeferredPrefix;
+ }
+ return _redirectionDeferredPrefix;
+ }
void setEffectiveTarget(ConstructorElement target, DartType type,
{bool isMalformed: false}) {
- assert(invariant(this, target != null,
- message: 'No effective target provided for $this.'));
- assert(invariant(this, effectiveTargetInternal == null,
- message: 'Effective target has already been computed for $this.'));
- effectiveTargetInternal = target;
- _effectiveTargetType = type;
- _isEffectiveTargetMalformed = isMalformed;
+ if (isPatched) {
+ patch.setEffectiveTarget(target, type, isMalformed: isMalformed);
+ } else {
+ assert(invariant(this, target != null,
+ message: 'No effective target provided for $this.'));
+ assert(invariant(this, effectiveTargetInternal == null,
+ message: 'Effective target has already been computed for $this.'));
+ assert(invariant(this, !target.isMalformed || isMalformed,
+ message: 'Effective target is not marked as malformed for $this: '
+ 'target=$target, type=$type, isMalformed: $isMalformed'));
+ assert(invariant(this, isMalformed || type.isInterfaceType,
+ message: 'Effective target type is not an interface type for $this: '
+ 'target=$target, type=$type, isMalformed: $isMalformed'));
+ effectiveTargetInternal = target;
+ _effectiveTargetType = type;
+ _isEffectiveTargetMalformed = isMalformed;
+ }
}
ConstructorElement get effectiveTarget {
- if (Elements.isMalformed(immediateRedirectionTarget)) {
- return immediateRedirectionTarget;
- }
- assert(!isRedirectingFactory || effectiveTargetInternal != null);
- if (isRedirectingFactory) {
- return effectiveTargetInternal;
- }
if (isPatched) {
- return effectiveTargetInternal ?? this;
+ return patch.effectiveTarget;
+ }
+ if (isRedirectingFactory) {
+ assert(effectiveTargetInternal != null);
+ return effectiveTargetInternal;
}
return this;
}
- InterfaceType get effectiveTargetType {
+ DartType get effectiveTargetType {
+ if (isPatched) {
+ return patch.effectiveTargetType;
+ }
assert(invariant(this, _effectiveTargetType != null,
message: 'Effective target type has not yet been computed for $this.'));
return _effectiveTargetType;
}
- InterfaceType computeEffectiveTargetType(InterfaceType newType) {
+ DartType computeEffectiveTargetType(InterfaceType newType) {
+ if (isPatched) {
+ return patch.computeEffectiveTargetType(newType);
+ }
if (!isRedirectingFactory) return newType;
return effectiveTargetType.substByContext(newType);
}
bool get isEffectiveTargetMalformed {
+ if (isPatched) {
+ return patch.isEffectiveTargetMalformed;
+ }
if (!isRedirectingFactory) return false;
assert(invariant(this, _isEffectiveTargetMalformed != null,
message: 'Malformedness has not yet been computed for $this.'));
@@ -3121,6 +3193,8 @@
bool isBreakTarget = false;
bool isContinueTarget = false;
+ final int hashCode = ElementX.newHashCode();
+
JumpTargetX(this.statement, this.nestingLevel, this.executableContext);
String get name => "target";
@@ -3220,6 +3294,8 @@
Token get endToken;
+ final int hashCode = ElementX.newHashCode();
+
MetadataAnnotationX([this.resolutionState = STATE_NOT_STARTED]);
MetadataAnnotation ensureResolved(Resolution resolution) {
diff --git a/pkg/compiler/lib/src/helpers/debug_collection.dart b/pkg/compiler/lib/src/helpers/debug_collection.dart
index c0276cf..751b8c8 100644
--- a/pkg/compiler/lib/src/helpers/debug_collection.dart
+++ b/pkg/compiler/lib/src/helpers/debug_collection.dart
@@ -131,12 +131,16 @@
E singleWhere(bool test(E element)) => iterable.singleWhere(test);
E elementAt(int index) => iterable.elementAt(index);
+
+ String toString() => iterable.toString();
}
class DebugList<E> extends DebugIterable<E> implements List<E> {
DebugCallback addCallback;
+ DebugCallback addAllCallback;
- DebugList(List<E> list, {this.addCallback}) : super(list);
+ DebugList(List<E> list, {this.addCallback, this.addAllCallback})
+ : super(list);
List<E> get list => iterable;
@@ -159,7 +163,12 @@
list.add(value);
}
- void addAll(Iterable<E> iterable) => list.addAll(iterable);
+ void addAll(Iterable<E> iterable) {
+ if (addAllCallback != null) {
+ addAllCallback('addAll', iterable, null);
+ }
+ list.addAll(iterable);
+ }
Iterable<E> get reversed => list.reversed;
diff --git a/pkg/compiler/lib/src/inferrer/node_tracer.dart b/pkg/compiler/lib/src/inferrer/node_tracer.dart
index c50929d..dca18a5 100644
--- a/pkg/compiler/lib/src/inferrer/node_tracer.dart
+++ b/pkg/compiler/lib/src/inferrer/node_tracer.dart
@@ -333,7 +333,7 @@
* [isAddedToContainer].
*/
bool isParameterOfListAddingMethod(Element element) {
- if (!element.isParameter) return false;
+ if (!element.isRegularParameter) return false;
if (element.enclosingClass != compiler.backend.listImplementation) {
return false;
}
@@ -349,7 +349,7 @@
* [isValueAddedToMap] and [isKeyAddedToMap].
*/
bool isParameterOfMapAddingMethod(Element element) {
- if (!element.isParameter) return false;
+ if (!element.isRegularParameter) return false;
if (element.enclosingClass != compiler.backend.mapImplementation) {
return false;
}
diff --git a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
index 3b0127a..d5492f1 100644
--- a/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
+++ b/pkg/compiler/lib/src/inferrer/type_graph_nodes.dart
@@ -88,9 +88,9 @@
/// change.
bool isStable = false;
- // TypeInformations are unique.
- static int staticHashCode = 0;
- final int hashCode = staticHashCode++;
+ // TypeInformations are unique. Store an arbitrary identity hash code.
+ static int _staticHashCode = 0;
+ final int hashCode = _staticHashCode = (_staticHashCode + 1).toUnsigned(30);
bool get isConcrete => false;
@@ -344,7 +344,7 @@
bool disableInferenceForClosures = true;
factory ElementTypeInformation(Element element, TypeInformationSystem types) {
- if (element.isParameter || element.isInitializingFormal) {
+ if (element.isRegularParameter || element.isInitializingFormal) {
ParameterElement parameter = element;
if (parameter.functionDeclaration.isInstanceMember) {
return new ParameterTypeInformation._instanceMember(element, types);
@@ -601,7 +601,7 @@
bool isTearOffClosureParameter = false;
void tagAsTearOffClosureParameter(TypeGraphInferrerEngine inferrer) {
- assert(element.isParameter);
+ assert(element.isRegularParameter);
isTearOffClosureParameter = true;
// We have to add a flow-edge for the default value (if it exists), as we
// might not see all call-sites and thus miss the use of it.
diff --git a/pkg/compiler/lib/src/js/rewrite_async.dart b/pkg/compiler/lib/src/js/rewrite_async.dart
index 2a9d8bf..9578f3f 100644
--- a/pkg/compiler/lib/src/js/rewrite_async.dart
+++ b/pkg/compiler/lib/src/js/rewrite_async.dart
@@ -283,7 +283,7 @@
/// Each buffer ends up as its own case part in the big state-switch.
void beginLabel(int label) {
assert(!labelledParts.containsKey(label));
- currentStatementBuffer = new List<js.Statement>();
+ currentStatementBuffer = <js.Statement>[];
labelledParts[label] = currentStatementBuffer;
addStatement(new js.Comment(labelComments[label]));
}
@@ -967,7 +967,7 @@
bool oldInsideUntranslatedBreakable = insideUntranslatedBreakable;
insideUntranslatedBreakable = true;
addStatement(js.js.statement('do {#} while (#)',
- [translateInBlock(node.body), visitExpression(node.condition)]));
+ [translateToStatement(node.body), visitExpression(node.condition)]));
insideUntranslatedBreakable = oldInsideUntranslatedBreakable;
return;
}
@@ -1013,7 +1013,7 @@
withExpressions([node.init, node.condition, node.update],
(List<js.Expression> transformed) {
addStatement(new js.For(transformed[0], transformed[1], transformed[2],
- translateInBlock(node.body)));
+ translateToStatement(node.body)));
});
insideUntranslatedBreakable = oldInsideUntranslated;
return;
@@ -1063,23 +1063,34 @@
unsupported(node);
}
- // Only used for code where `!shouldTransform(node)`.
- js.Block translateInBlock(js.Statement node) {
+ List<js.Statement> translateToStatementSequence(js.Statement node) {
assert(!shouldTransform(node));
List<js.Statement> oldBuffer = currentStatementBuffer;
- currentStatementBuffer = new List();
+ currentStatementBuffer = <js.Statement>[];
List<js.Statement> resultBuffer = currentStatementBuffer;
visitStatement(node);
currentStatementBuffer = oldBuffer;
- return new js.Block(resultBuffer);
+ return resultBuffer;
+ }
+
+ js.Statement translateToStatement(js.Statement node) {
+ List<js.Statement> statements = translateToStatementSequence(node);
+ if (statements.length == 1)
+ return statements.single;
+ return new js.Block(statements);
+ }
+
+ js.Block translateToBlock(js.Statement node) {
+ return new js.Block(translateToStatementSequence(node));
}
@override
void visitIf(js.If node) {
if (!shouldTransform(node.then) && !shouldTransform(node.otherwise)) {
withExpression(node.condition, (js.Expression condition) {
- addStatement(new js.If(condition, translateInBlock(node.then),
- translateInBlock(node.otherwise)));
+ js.Statement translatedThen = translateToStatement(node.then);
+ js.Statement translatedElse = translateToStatement(node.otherwise);
+ addStatement(new js.If(condition, translatedThen, translatedElse));
}, store: false);
return;
}
@@ -1137,7 +1148,7 @@
void visitLabeledStatement(js.LabeledStatement node) {
if (!shouldTransform(node)) {
addStatement(
- new js.LabeledStatement(node.label, translateInBlock(node.body)));
+ new js.LabeledStatement(node.label, translateToStatement(node.body)));
return;
}
// `continue label` is really continuing the nested loop.
@@ -1302,9 +1313,9 @@
List<js.SwitchClause> cases = node.cases.map((js.SwitchClause clause) {
if (clause is js.Case) {
return new js.Case(
- clause.expression, translateInBlock(clause.body));
+ clause.expression, translateToBlock(clause.body));
} else if (clause is js.Default) {
- return new js.Default(translateInBlock(clause.body));
+ return new js.Default(translateToBlock(clause.body));
}
}).toList();
addStatement(new js.Switch(key, cases));
@@ -1426,14 +1437,14 @@
/// See the comments of [rewriteFunction] for more explanation.
void visitTry(js.Try node) {
if (!shouldTransform(node)) {
- js.Block body = translateInBlock(node.body);
+ js.Block body = translateToBlock(node.body);
js.Catch catchPart = (node.catchPart == null)
? null
: new js.Catch(node.catchPart.declaration,
- translateInBlock(node.catchPart.body));
+ translateToBlock(node.catchPart.body));
js.Block finallyPart = (node.finallyPart == null)
? null
- : translateInBlock(node.finallyPart);
+ : translateToBlock(node.finallyPart);
addStatement(new js.Try(body, catchPart, finallyPart));
return;
}
@@ -1576,7 +1587,7 @@
bool oldInsideUntranslated = insideUntranslatedBreakable;
insideUntranslatedBreakable = true;
withExpression(node.condition, (js.Expression condition) {
- addStatement(new js.While(condition, translateInBlock(node.body)));
+ addStatement(new js.While(condition, translateToStatement(node.body)));
}, store: false);
insideUntranslatedBreakable = oldInsideUntranslated;
return;
diff --git a/pkg/compiler/lib/src/js_backend/backend.dart b/pkg/compiler/lib/src/js_backend/backend.dart
index cbae712..4bf0d1e 100644
--- a/pkg/compiler/lib/src/js_backend/backend.dart
+++ b/pkg/compiler/lib/src/js_backend/backend.dart
@@ -232,8 +232,6 @@
bool get supportsReflection => emitter.emitter.supportsReflection;
- bool get supportsAsyncAwait => true;
-
final Annotations annotations;
/// Set of classes that need to be considered for reflection although not
@@ -660,7 +658,7 @@
}
bool usedByBackend(Element element) {
- if (element.isParameter ||
+ if (element.isRegularParameter ||
element.isInitializingFormal ||
element.isField) {
if (usedByBackend(element.enclosingElement)) return true;
@@ -669,7 +667,7 @@
}
bool invokedReflectively(Element element) {
- if (element.isParameter || element.isInitializingFormal) {
+ if (element.isRegularParameter || element.isInitializingFormal) {
ParameterElement parameter = element;
if (invokedReflectively(parameter.functionDeclaration)) return true;
}
@@ -947,8 +945,6 @@
cls.ensureResolved(resolution);
cls.forEachMember((ClassElement classElement, Element member) {
if (member.name == Identifiers.call) {
- reporter.reportErrorMessage(
- member, MessageKind.CALL_NOT_SUPPORTED_ON_NATIVE_CLASS);
return;
}
if (member.isSynthesized) return;
diff --git a/pkg/compiler/lib/src/js_backend/backend_serialization.dart b/pkg/compiler/lib/src/js_backend/backend_serialization.dart
index 97da2f5..471456cb 100644
--- a/pkg/compiler/lib/src/js_backend/backend_serialization.dart
+++ b/pkg/compiler/lib/src/js_backend/backend_serialization.dart
@@ -18,8 +18,10 @@
const String _BACKEND_DATA_TAG = 'jsBackendData';
const Key DART_TYPES_RETURNED = const Key('dartTypesReturned');
+const Key THIS_TYPES_RETURNED = const Key('thisTypesReturned');
const Key SPECIAL_TYPES_RETURNED = const Key('specialTypesReturned');
const Key DART_TYPES_INSTANTIATED = const Key('dartTypesInstantiated');
+const Key THIS_TYPES_INSTANTIATED = const Key('thisTypesInstantiated');
const Key SPECIAL_TYPES_INSTANTIATED = const Key('specialTypesInstantiated');
const Key CODE_TEMPLATE = const Key('codeTemplate');
const Key SIDE_EFFECTS = const Key('sideEffects');
@@ -150,15 +152,43 @@
}
class NativeBehaviorSerialization {
- /// Returns a list of the [DartType]s in [types].
+ static const int NORMAL_TYPE = 0;
+ static const int THIS_TYPE = 1;
+ static const int SPECIAL_TYPE = 2;
+
+ static int getTypeKind(var type) {
+ if (type is DartType) {
+ // TODO(johnniwinther): Remove this when annotation are no longer resolved
+ // to this-types.
+ if (type is GenericType &&
+ type.isGeneric &&
+ type == type.element.thisType) {
+ return THIS_TYPE;
+ }
+ return NORMAL_TYPE;
+ }
+ return SPECIAL_TYPE;
+ }
+
+ /// Returns a list of the non-this-type [DartType]s in [types].
static List<DartType> filterDartTypes(List types) {
- return types.where((type) => type is DartType).toList();
+ return types.where((type) => getTypeKind(type) == NORMAL_TYPE).toList();
+ }
+
+ // TODO(johnniwinther): Remove this when annotation are no longer resolved
+ // to this-types.
+ /// Returns a list of the classes of this-types in [types].
+ static List<Element> filterThisTypes(List types) {
+ return types
+ .where((type) => getTypeKind(type) == THIS_TYPE)
+ .map((type) => type.element)
+ .toList();
}
/// Returns a list of the names of the [SpecialType]s in [types].
static List<String> filterSpecialTypes(List types) {
return types
- .where((type) => type is SpecialType)
+ .where((type) => getTypeKind(type) == SPECIAL_TYPE)
.map((SpecialType type) => type.name)
.toList();
}
@@ -167,11 +197,15 @@
NativeBehavior behavior, ObjectEncoder encoder) {
encoder.setTypes(
DART_TYPES_RETURNED, filterDartTypes(behavior.typesReturned));
+ encoder.setElements(
+ THIS_TYPES_RETURNED, filterThisTypes(behavior.typesReturned));
encoder.setStrings(
SPECIAL_TYPES_RETURNED, filterSpecialTypes(behavior.typesReturned));
encoder.setTypes(
DART_TYPES_INSTANTIATED, filterDartTypes(behavior.typesInstantiated));
+ encoder.setElements(
+ THIS_TYPES_INSTANTIATED, filterThisTypes(behavior.typesInstantiated));
encoder.setStrings(SPECIAL_TYPES_INSTANTIATED,
filterSpecialTypes(behavior.typesInstantiated));
@@ -193,12 +227,20 @@
behavior.typesReturned
.addAll(decoder.getTypes(DART_TYPES_RETURNED, isOptional: true));
behavior.typesReturned.addAll(decoder
+ .getElements(THIS_TYPES_RETURNED, isOptional: true)
+ .map((element) => element.thisType)
+ .toList());
+ behavior.typesReturned.addAll(decoder
.getStrings(SPECIAL_TYPES_RETURNED, isOptional: true)
.map(SpecialType.fromName));
behavior.typesInstantiated
.addAll(decoder.getTypes(DART_TYPES_INSTANTIATED, isOptional: true));
behavior.typesInstantiated.addAll(decoder
+ .getElements(THIS_TYPES_INSTANTIATED, isOptional: true)
+ .map((element) => element.thisType)
+ .toList());
+ behavior.typesInstantiated.addAll(decoder
.getStrings(SPECIAL_TYPES_INSTANTIATED, isOptional: true)
.map(SpecialType.fromName));
diff --git a/pkg/compiler/lib/src/js_backend/js_interop_analysis.dart b/pkg/compiler/lib/src/js_backend/js_interop_analysis.dart
index 83f6284..74b10ab 100644
--- a/pkg/compiler/lib/src/js_backend/js_interop_analysis.dart
+++ b/pkg/compiler/lib/src/js_backend/js_interop_analysis.dart
@@ -8,11 +8,7 @@
import '../common.dart';
import '../constants/values.dart'
show ConstantValue, ConstructedConstantValue, StringConstantValue;
-import '../dart_types.dart'
- show
- DartType,
- DynamicType,
- FunctionType;
+import '../dart_types.dart' show DartType, DynamicType, FunctionType;
import '../diagnostics/messages.dart' show MessageKind;
import '../elements/elements.dart'
show
@@ -195,9 +191,7 @@
// TODO(jacobr): consider using codegenWorld.isChecks to determine the
// range of positional arguments that need to be supported by JavaScript
// function types.
- return new FunctionType.synthesized(
- const DynamicType(),
- [],
- new List<DartType>.filled(16, const DynamicType()));
+ return new FunctionType.synthesized(const DynamicType(), [],
+ new List<DartType>.filled(16, const DynamicType()));
}
}
diff --git a/pkg/compiler/lib/src/js_backend/native_data.dart b/pkg/compiler/lib/src/js_backend/native_data.dart
index 67b473b..31fe7d6 100644
--- a/pkg/compiler/lib/src/js_backend/native_data.dart
+++ b/pkg/compiler/lib/src/js_backend/native_data.dart
@@ -35,6 +35,10 @@
Map<MemberElement, NativeBehavior> nativeFieldStoreBehavior =
<FieldElement, NativeBehavior>{};
+ /// Prefix used to escape JS names that are not valid Dart names
+ /// when using JSInterop.
+ static const String _jsInteropEscapePrefix = r'JS$';
+
/// Returns `true` if [element] is explicitly marked as part of JsInterop.
bool _isJsInterop(Element element) {
return jsInteropNames.containsKey(element.declaration);
@@ -93,7 +97,7 @@
if (jsInteropName != null && jsInteropName.isNotEmpty) {
return jsInteropName;
}
- return element.isLibrary ? 'self' : element.name;
+ return element.isLibrary ? 'self' : getUnescapedJSInteropName(element.name);
}
/// Computes the name for [element] to use in the generated JavaScript. This
@@ -216,4 +220,12 @@
FieldElement field, NativeBehavior behavior) {
nativeFieldStoreBehavior[field] = behavior;
}
+
+ /// Apply JS$ escaping scheme to convert possible escaped Dart names into
+ /// JS names.
+ String getUnescapedJSInteropName(String name) {
+ return name.startsWith(_jsInteropEscapePrefix)
+ ? name.substring(_jsInteropEscapePrefix.length)
+ : name;
+ }
}
diff --git a/pkg/compiler/lib/src/js_backend/runtime_types.dart b/pkg/compiler/lib/src/js_backend/runtime_types.dart
index 369cec0..e3f74b7 100644
--- a/pkg/compiler/lib/src/js_backend/runtime_types.dart
+++ b/pkg/compiler/lib/src/js_backend/runtime_types.dart
@@ -150,7 +150,7 @@
@override
void registerRtiDependency(Element element, Element dependency) {
// We're not dealing with typedef for now.
- if (!element.isClass || !dependency.isClass) return;
+ if (element == null || !element.isClass || !dependency.isClass) return;
Set<ClassElement> classes =
rtiDependencies.putIfAbsent(element, () => new Set<ClassElement>());
classes.add(dependency);
@@ -1049,8 +1049,8 @@
class TypeCheck {
final ClassElement cls;
final Substitution substitution;
- final int hashCode = (nextHash++) & 0x3fffffff;
- static int nextHash = 49;
+ final int hashCode = _nextHash = (_nextHash + 100003).toUnsigned(30);
+ static int _nextHash = 0;
TypeCheck(this.cls, this.substitution);
}
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 5bd1cb1..6301e77 100644
--- a/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
+++ b/pkg/compiler/lib/src/js_emitter/full_emitter/emitter.dart
@@ -1067,9 +1067,28 @@
var cls = function () {};
cls.prototype = {'p': {}};
var object = new cls();
- return object.__proto__ &&
- object.__proto__.p === cls.prototype.p;
- })();
+ if (!(object.__proto__ && object.__proto__.p === cls.prototype.p))
+ return false;
+
+ try {
+ // Are we running on a platform where the performance is good?
+ // (i.e. Chrome or d8).
+
+ // Chrome userAgent?
+ if (typeof navigator != "undefined" &&
+ typeof navigator.userAgent == "string" &&
+ navigator.userAgent.indexOf("Chrome/") >= 0) return true;
+
+ // d8 version() looks like "N.N.N.N", jsshell version() like "N".
+ if (typeof version == "function" &&
+ version.length == 0) {
+ var v = version();
+ if (/^\d+\.\d+\.\d+\.\d+$/.test(v)) return true;
+ }
+ } catch(_) {}
+
+ return false;
+ })();
''');
}
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 1f81f6d..efec052 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
@@ -345,6 +345,8 @@
for (Element e in elements) {
if (e is ClassElement && backend.isJsInterop(e)) {
e.declaration.forEachMember((_, Element member) {
+ var jsName =
+ backend.nativeData.getUnescapedJSInteropName(member.name);
if (!member.isInstanceMember) return;
if (member.isGetter || member.isField || member.isFunction) {
var selectors =
@@ -354,7 +356,7 @@
var stubName = namer.invocationName(selector);
if (stubNames.add(stubName.key)) {
interceptorClass.callStubs.add(_buildStubMethod(stubName,
- js.js('function(obj) { return obj.# }', [member.name]),
+ js.js('function(obj) { return obj.# }', [jsName]),
element: member));
}
}
@@ -367,10 +369,8 @@
if (selectors != null && !selectors.isEmpty) {
var stubName = namer.setterForElement(member);
if (stubNames.add(stubName.key)) {
- interceptorClass.callStubs.add(_buildStubMethod(
- stubName,
- js.js('function(obj, v) { return obj.# = v }',
- [member.name]),
+ interceptorClass.callStubs.add(_buildStubMethod(stubName,
+ js.js('function(obj, v) { return obj.# = v }', [jsName]),
element: member));
}
}
@@ -447,7 +447,7 @@
interceptorClass.callStubs.add(_buildStubMethod(
stubName,
js.js('function(receiver, #) { return receiver.#(#) }',
- [parameters, member.name, parameters]),
+ [parameters, jsName, parameters]),
element: member));
}
}
diff --git a/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart b/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
index ddef40b..c41bfa9 100644
--- a/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
+++ b/pkg/compiler/lib/src/js_emitter/runtime_type_generator.dart
@@ -133,15 +133,15 @@
generateFunctionTypeSignature, generateSubstitution, generateTypeCheck);
if (classElement == backend.helpers.jsJavaScriptFunctionClass) {
- var type = backend.jsInteropAnalysis.buildJsFunctionType();
- if (type != null) {
- jsAst.Expression thisAccess = new jsAst.This();
- RuntimeTypesEncoder rtiEncoder = backend.rtiEncoder;
- jsAst.Expression encoding =
- rtiEncoder.getSignatureEncoding(type, thisAccess);
- jsAst.Name operatorSignature = namer.asName(namer.operatorSignature);
- result.properties[operatorSignature] = encoding;
- }
+ var type = backend.jsInteropAnalysis.buildJsFunctionType();
+ if (type != null) {
+ jsAst.Expression thisAccess = new jsAst.This();
+ RuntimeTypesEncoder rtiEncoder = backend.rtiEncoder;
+ jsAst.Expression encoding =
+ rtiEncoder.getSignatureEncoding(type, thisAccess);
+ jsAst.Name operatorSignature = namer.asName(namer.operatorSignature);
+ result.properties[operatorSignature] = encoding;
+ }
}
return result;
}
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 1b7beca..69e3dea 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
@@ -64,13 +64,9 @@
}
}
-var supportsDirectProtoAccess = (function () {
- var cls = function () {};
- cls.prototype = {'p': {}};
- var object = new cls();
- return object.__proto__ &&
- object.__proto__.p === cls.prototype.p;
-})();
+// Only use direct proto access to construct the prototype chain (instead of
+// copying properties) on platforms where we know it works well (Chrome / d8).
+var supportsDirectProtoAccess = #directAccessTestExpression;
var functionsHaveName = (function() {
function t() {};
@@ -354,6 +350,36 @@
})()
''';
+/// An expression that returns `true` if `__proto__` can be assigned to stitch
+/// together a prototype chain, and the performance is good.
+const String directAccessTestExpression = r'''
+ (function () {
+ var cls = function () {};
+ cls.prototype = {'p': {}};
+ var object = new cls();
+ if (!(object.__proto__ && object.__proto__.p === cls.prototype.p))
+ return false;
+
+ try {
+ // Are we running on a platform where the performance is good?
+ // (i.e. Chrome or d8).
+
+ // Chrome userAgent?
+ if (typeof navigator != "undefined" &&
+ typeof navigator.userAgent == "string" &&
+ navigator.userAgent.indexOf("Chrome/") >= 0) return true;
+ // d8 version() looks like "N.N.N.N", jsshell version() like "N".
+ if (typeof version == "function" &&
+ version.length == 0) {
+ var v = version();
+ if (/^\d+\.\d+\.\d+\.\d+$/.test(v)) return true;
+ }
+ } catch(_) {}
+
+ return false;
+ })()
+''';
+
/// Deferred fragments (aka 'hunks') are built similarly to the main fragment.
///
/// However, at specific moments they need to contribute their data.
@@ -436,6 +462,7 @@
program.holders.where((Holder holder) => !holder.isStaticStateHolder);
return js.js.statement(mainBoilerplate, {
+ 'directAccessTestExpression': js.js(directAccessTestExpression),
'typeNameProperty': js.string(ModelEmitter.typeNameProperty),
'cyclicThrow': backend.emitter
.staticFunctionAccess(backend.helpers.cyclicThrowHelper),
diff --git a/pkg/compiler/lib/src/library_loader.dart b/pkg/compiler/lib/src/library_loader.dart
index be0cb41..c7c6e86 100644
--- a/pkg/compiler/lib/src/library_loader.dart
+++ b/pkg/compiler/lib/src/library_loader.dart
@@ -548,7 +548,7 @@
handler.registerDependency(
library,
new SyntheticImportElement(
- library.entryCompilationUnit, Uris.dart_core),
+ library.entryCompilationUnit, Uris.dart_core, coreLibrary),
coreLibrary);
});
}
@@ -916,10 +916,9 @@
class LibraryDependencyNode {
final LibraryElementX library;
- // TODO(ahe): Remove [hashCodeCounter] and [hashCode] when
- // VM implementation of Object.hashCode is not slow.
- final int hashCode = ++hashCodeCounter;
- static int hashCodeCounter = 0;
+ // Stored identity based hashCode for performance.
+ final int hashCode = _nextHash = (_nextHash + 100019).toUnsigned(30);
+ static int _nextHash = 0;
/**
* A linked list of the import tags that import [library] mapped to the
diff --git a/pkg/compiler/lib/src/native/native.dart b/pkg/compiler/lib/src/native/native.dart
index c9c60f69..c0d6a86 100644
--- a/pkg/compiler/lib/src/native/native.dart
+++ b/pkg/compiler/lib/src/native/native.dart
@@ -19,6 +19,7 @@
'html_common',
'indexed_db',
'js',
+ 'js_util',
'svg',
'_native_typed_data',
'web_audio',
diff --git a/pkg/compiler/lib/src/options.dart b/pkg/compiler/lib/src/options.dart
index ee3370e..c5eefce 100644
--- a/pkg/compiler/lib/src/options.dart
+++ b/pkg/compiler/lib/src/options.dart
@@ -527,7 +527,7 @@
/// Creates a copy of the [CompilerOptions] where the provided non-null
/// option values replace existing.
- CompilerOptions copy(
+ static CompilerOptions copy(CompilerOptions options,
{entryPoint,
libraryRoot,
packageRoot,
@@ -583,71 +583,76 @@
useStartupEmitter,
verbose}) {
return new CompilerOptions._(
- entryPoint ?? this.entryPoint,
- libraryRoot ?? this.libraryRoot,
- packageRoot ?? this.packageRoot,
- packageConfig ?? this.packageConfig,
- packagesDiscoveryProvider ?? this.packagesDiscoveryProvider,
- environment ?? this.environment,
- allowMockCompilation: allowMockCompilation ?? this.allowMockCompilation,
+ entryPoint ?? options.entryPoint,
+ libraryRoot ?? options.libraryRoot,
+ packageRoot ?? options.packageRoot,
+ packageConfig ?? options.packageConfig,
+ packagesDiscoveryProvider ?? options.packagesDiscoveryProvider,
+ environment ?? options.environment,
+ allowMockCompilation:
+ allowMockCompilation ?? options.allowMockCompilation,
allowNativeExtensions:
- allowNativeExtensions ?? this.allowNativeExtensions,
- analyzeAll: analyzeAll ?? this.analyzeAll,
- analyzeMain: analyzeMain ?? this.analyzeMain,
- analyzeOnly: analyzeOnly ?? this.analyzeOnly,
+ allowNativeExtensions ?? options.allowNativeExtensions,
+ analyzeAll: analyzeAll ?? options.analyzeAll,
+ analyzeMain: analyzeMain ?? options.analyzeMain,
+ analyzeOnly: analyzeOnly ?? options.analyzeOnly,
analyzeSignaturesOnly:
- analyzeSignaturesOnly ?? this.analyzeSignaturesOnly,
- buildId: buildId ?? this.buildId,
- dart2dartMultiFile: dart2dartMultiFile ?? this.dart2dartMultiFile,
- deferredMapUri: deferredMapUri ?? this.deferredMapUri,
- fatalWarnings: fatalWarnings ?? this.fatalWarnings,
- terseDiagnostics: terseDiagnostics ?? this.terseDiagnostics,
- suppressWarnings: suppressWarnings ?? this.suppressWarnings,
- suppressHints: suppressHints ?? this.suppressHints,
+ analyzeSignaturesOnly ?? options.analyzeSignaturesOnly,
+ buildId: buildId ?? options.buildId,
+ dart2dartMultiFile: dart2dartMultiFile ?? options.dart2dartMultiFile,
+ deferredMapUri: deferredMapUri ?? options.deferredMapUri,
+ fatalWarnings: fatalWarnings ?? options.fatalWarnings,
+ terseDiagnostics: terseDiagnostics ?? options.terseDiagnostics,
+ suppressWarnings: suppressWarnings ?? options.suppressWarnings,
+ suppressHints: suppressHints ?? options.suppressHints,
shownPackageWarnings:
- shownPackageWarnings ?? this._shownPackageWarnings,
- disableInlining: disableInlining ?? this.disableInlining,
- disableTypeInference: disableTypeInference ?? this.disableTypeInference,
- dumpInfo: dumpInfo ?? this.dumpInfo,
- emitJavaScript: emitJavaScript ?? this.emitJavaScript,
- enableAssertMessage: enableAssertMessage ?? this.enableAssertMessage,
+ shownPackageWarnings ?? options._shownPackageWarnings,
+ disableInlining: disableInlining ?? options.disableInlining,
+ disableTypeInference:
+ disableTypeInference ?? options.disableTypeInference,
+ dumpInfo: dumpInfo ?? options.dumpInfo,
+ emitJavaScript: emitJavaScript ?? options.emitJavaScript,
+ enableAssertMessage: enableAssertMessage ?? options.enableAssertMessage,
enableGenericMethodSyntax:
- enableGenericMethodSyntax ?? this.enableGenericMethodSyntax,
+ enableGenericMethodSyntax ?? options.enableGenericMethodSyntax,
enableInitializingFormalAccess: enableInitializingFormalAccess ??
- this.enableInitializingFormalAccess,
+ options.enableInitializingFormalAccess,
enableExperimentalMirrors:
- enableExperimentalMirrors ?? this.enableExperimentalMirrors,
- enableMinification: enableMinification ?? this.enableMinification,
- enableNativeLiveTypeAnalysis:
- enableNativeLiveTypeAnalysis ?? this.enableNativeLiveTypeAnalysis,
- enableTypeAssertions: enableTypeAssertions ?? this.enableTypeAssertions,
- enableUserAssertions: enableUserAssertions ?? this.enableUserAssertions,
+ enableExperimentalMirrors ?? options.enableExperimentalMirrors,
+ enableMinification: enableMinification ?? options.enableMinification,
+ enableNativeLiveTypeAnalysis: enableNativeLiveTypeAnalysis ??
+ options.enableNativeLiveTypeAnalysis,
+ enableTypeAssertions:
+ enableTypeAssertions ?? options.enableTypeAssertions,
+ enableUserAssertions:
+ enableUserAssertions ?? options.enableUserAssertions,
generateCodeWithCompileTimeErrors: generateCodeWithCompileTimeErrors ??
- this.generateCodeWithCompileTimeErrors,
- generateSourceMap: generateSourceMap ?? this.generateSourceMap,
+ options.generateCodeWithCompileTimeErrors,
+ generateSourceMap: generateSourceMap ?? options.generateSourceMap,
hasIncrementalSupport:
- hasIncrementalSupport ?? this.hasIncrementalSupport,
- outputUri: outputUri ?? this.outputUri,
- platformConfigUri: platformConfigUri ?? this.platformConfigUri,
- preserveComments: preserveComments ?? this.preserveComments,
- preserveUris: preserveUris ?? this.preserveUris,
- resolutionInputs: resolutionInputs ?? this.resolutionInputs,
- resolutionOutput: resolutionOutput ?? this.resolutionOutput,
- resolveOnly: resolveOnly ?? this.resolveOnly,
- sourceMapUri: sourceMapUri ?? this.sourceMapUri,
- strips: strips ?? this.strips,
- testMode: testMode ?? this.testMode,
- trustJSInteropTypeAnnotations:
- trustJSInteropTypeAnnotations ?? this.trustJSInteropTypeAnnotations,
- trustPrimitives: trustPrimitives ?? this.trustPrimitives,
- trustTypeAnnotations: trustTypeAnnotations ?? this.trustTypeAnnotations,
+ hasIncrementalSupport ?? options.hasIncrementalSupport,
+ outputUri: outputUri ?? options.outputUri,
+ platformConfigUri: platformConfigUri ?? options.platformConfigUri,
+ preserveComments: preserveComments ?? options.preserveComments,
+ preserveUris: preserveUris ?? options.preserveUris,
+ resolutionInputs: resolutionInputs ?? options.resolutionInputs,
+ resolutionOutput: resolutionOutput ?? options.resolutionOutput,
+ resolveOnly: resolveOnly ?? options.resolveOnly,
+ sourceMapUri: sourceMapUri ?? options.sourceMapUri,
+ strips: strips ?? options.strips,
+ testMode: testMode ?? options.testMode,
+ trustJSInteropTypeAnnotations: trustJSInteropTypeAnnotations ??
+ options.trustJSInteropTypeAnnotations,
+ trustPrimitives: trustPrimitives ?? options.trustPrimitives,
+ trustTypeAnnotations:
+ trustTypeAnnotations ?? options.trustTypeAnnotations,
useContentSecurityPolicy:
- useContentSecurityPolicy ?? this.useContentSecurityPolicy,
- useCpsIr: useCpsIr ?? this.useCpsIr,
- useFrequencyNamer: useFrequencyNamer ?? this.useFrequencyNamer,
- useNewSourceInfo: useNewSourceInfo ?? this.useNewSourceInfo,
- useStartupEmitter: useStartupEmitter ?? this.useStartupEmitter,
- verbose: verbose ?? this.verbose);
+ useContentSecurityPolicy ?? options.useContentSecurityPolicy,
+ useCpsIr: useCpsIr ?? options.useCpsIr,
+ useFrequencyNamer: useFrequencyNamer ?? options.useFrequencyNamer,
+ useNewSourceInfo: useNewSourceInfo ?? options.useNewSourceInfo,
+ useStartupEmitter: useStartupEmitter ?? options.useStartupEmitter,
+ verbose: verbose ?? options.verbose);
}
/// Returns `true` if warnings and hints are shown for all packages.
diff --git a/pkg/compiler/lib/src/parser/parser.dart b/pkg/compiler/lib/src/parser/parser.dart
index 821fcad..3ac4900 100644
--- a/pkg/compiler/lib/src/parser/parser.dart
+++ b/pkg/compiler/lib/src/parser/parser.dart
@@ -424,13 +424,12 @@
listener.beginFormalParameters(begin);
expect('(', token);
int parameterCount = 0;
- if (optional(')', token.next)) {
- listener.endFormalParameters(parameterCount, begin, token.next);
- return token.next.next;
- }
do {
- ++parameterCount;
token = token.next;
+ if (optional(')', token)) {
+ break;
+ }
+ ++parameterCount;
String value = token.stringValue;
if (identical(value, '[')) {
token = parseOptionalFormalParameters(token, false);
@@ -495,11 +494,23 @@
int parameterCount = 0;
do {
token = token.next;
+ if (isNamed && optional('}', token)) {
+ break;
+ } else if (!isNamed && optional(']', token)) {
+ break;
+ }
var type =
isNamed ? FormalParameterType.NAMED : FormalParameterType.POSITIONAL;
token = parseFormalParameter(token, type);
++parameterCount;
} while (optional(',', token));
+ if (parameterCount == 0) {
+ listener.reportError(
+ token,
+ isNamed
+ ? MessageKind.EMPTY_NAMED_PARAMETER_LIST
+ : MessageKind.EMPTY_OPTIONAL_PARAMETER_LIST);
+ }
listener.endOptionalFormalParameters(parameterCount, begin, token);
if (isNamed) {
return expect('}', token);
@@ -2565,6 +2576,10 @@
bool old = mayParseFunctionExpressions;
mayParseFunctionExpressions = true;
do {
+ if (optional(')', token.next)) {
+ token = token.next;
+ break;
+ }
Token colon = null;
if (optional(':', token.next.next)) {
token = parseIdentifier(token.next);
diff --git a/pkg/compiler/lib/src/resolution/class_hierarchy.dart b/pkg/compiler/lib/src/resolution/class_hierarchy.dart
index 87c00a8..39fe5e1 100644
--- a/pkg/compiler/lib/src/resolution/class_hierarchy.dart
+++ b/pkg/compiler/lib/src/resolution/class_hierarchy.dart
@@ -5,8 +5,7 @@
library dart2js.resolution.class_hierarchy;
import '../common.dart';
-import '../common/resolution.dart' show Feature;
-import '../compiler.dart' show Compiler;
+import '../common/resolution.dart' show Feature, Resolution;
import '../core_types.dart' show CoreClasses, CoreTypes;
import '../dart_types.dart';
import '../elements/elements.dart';
@@ -34,13 +33,13 @@
final TypeDeclarationElement enclosingElement;
TypeDeclarationElement get element => enclosingElement;
- TypeDefinitionVisitor(Compiler compiler, TypeDeclarationElement element,
+ TypeDefinitionVisitor(Resolution resolution, TypeDeclarationElement element,
ResolutionRegistry registry)
: this.enclosingElement = element,
scope = Scope.buildEnclosingScope(element),
- super(compiler, registry);
+ super(resolution, registry);
- CoreTypes get coreTypes => compiler.coreTypes;
+ CoreTypes get coreTypes => resolution.coreTypes;
DartType get objectType => coreTypes.objectType;
@@ -118,9 +117,9 @@
class ClassResolverVisitor extends TypeDefinitionVisitor {
BaseClassElementX get element => enclosingElement;
- ClassResolverVisitor(
- Compiler compiler, ClassElement classElement, ResolutionRegistry registry)
- : super(compiler, classElement, registry);
+ ClassResolverVisitor(Resolution resolution, ClassElement classElement,
+ ResolutionRegistry registry)
+ : super(resolution, classElement, registry);
DartType visitClassNode(ClassNode node) {
if (element == null) {
@@ -212,7 +211,7 @@
new SynthesizedConstructorElementX.forDefault(superMember, element);
if (superMember.isMalformed) {
ErroneousElement erroneousElement = superMember;
- compiler.registerCompiletimeError(
+ resolution.registerCompileTimeError(
constructor,
reporter.createMessage(node, erroneousElement.messageKind,
erroneousElement.messageArguments));
@@ -243,7 +242,7 @@
}
EnumCreator creator =
- new EnumCreator(reporter, compiler.coreTypes, element);
+ new EnumCreator(reporter, resolution.coreTypes, element);
creator.createMembers();
return enumType;
}
@@ -304,7 +303,7 @@
String mixinName = mixinType.name;
MixinApplicationElementX mixinApplication =
new UnnamedMixinApplicationElementX("${superName}+${mixinName}",
- element, compiler.idGenerator.getNextFreeId(), node);
+ element, resolution.idGenerator.getNextFreeId(), node);
// Create synthetic type variables for the mixin application.
List<DartType> typeVariables = <DartType>[];
int index = 0;
@@ -360,7 +359,7 @@
if (mixinApplication.supertype != null) {
// [supertype] is not null if there was a cycle.
- assert(invariant(node, compiler.compilationFailed));
+ assert(invariant(node, reporter.hasReportedError));
supertype = mixinApplication.supertype;
assert(invariant(node, supertype.isObject));
} else {
@@ -545,7 +544,7 @@
reporter: reporter, objectType: coreTypes.objectType)
.createOrderedTypeSet(supertype, cls.interfaces);
} else {
- assert(cls == compiler.coreClasses.objectClass);
+ assert(cls == resolution.coreClasses.objectClass);
cls.allSupertypesAndSelf =
new OrderedTypeSet.singleton(cls.computeType(resolution));
}
@@ -553,7 +552,7 @@
isBlackListed(DartType type) {
LibraryElement lib = element.library;
- return !identical(lib, compiler.coreLibrary) &&
+ return !identical(lib, resolution.coreLibrary) &&
!resolution.target.isTargetSpecificLibrary(lib) &&
(type.isDynamic ||
type == coreTypes.boolType ||
@@ -569,16 +568,16 @@
Scope context;
ClassElement classElement;
- ClassSupertypeResolver(Compiler compiler, ClassElement cls)
+ ClassSupertypeResolver(Resolution resolution, ClassElement cls)
: context = Scope.buildEnclosingScope(cls),
this.classElement = cls,
- super(compiler);
+ super(resolution);
- CoreClasses get coreClasses => compiler.coreClasses;
+ CoreClasses get coreClasses => resolution.coreClasses;
void loadSupertype(ClassElement element, Node from) {
if (!element.isResolved) {
- compiler.resolver.loadSupertypes(element, from);
+ resolution.resolver.loadSupertypes(element, from);
element.ensureResolved(resolution);
}
}
diff --git a/pkg/compiler/lib/src/resolution/constructors.dart b/pkg/compiler/lib/src/resolution/constructors.dart
index 90f4716..50f51d1 100644
--- a/pkg/compiler/lib/src/resolution/constructors.dart
+++ b/pkg/compiler/lib/src/resolution/constructors.dart
@@ -5,8 +5,7 @@
library dart2js.resolution.constructors;
import '../common.dart';
-import '../common/resolution.dart' show Feature;
-import '../compiler.dart' show Compiler;
+import '../common/resolution.dart' show Feature, Resolution;
import '../constants/constructors.dart'
show
GenerativeConstantConstructor,
@@ -476,9 +475,9 @@
final ResolverVisitor resolver;
final bool inConstContext;
- ConstructorResolver(Compiler compiler, this.resolver,
+ ConstructorResolver(Resolution resolution, this.resolver,
{bool this.inConstContext: false})
- : super(compiler);
+ : super(resolution);
ResolutionRegistry get registry => resolver.registry;
diff --git a/pkg/compiler/lib/src/resolution/members.dart b/pkg/compiler/lib/src/resolution/members.dart
index b12218b..97f59bc 100644
--- a/pkg/compiler/lib/src/resolution/members.dart
+++ b/pkg/compiler/lib/src/resolution/members.dart
@@ -6,8 +6,8 @@
import '../common.dart';
import '../common/names.dart' show Selectors;
-import '../common/resolution.dart' show Feature;
-import '../compiler.dart' show Compiler;
+import '../common/resolution.dart' show Feature, Resolution;
+import '../compile_time_constants.dart';
import '../constants/constructors.dart'
show RedirectingFactoryConstantConstructor;
import '../constants/expressions.dart';
@@ -27,6 +27,7 @@
ParameterElementX,
VariableElementX,
VariableList;
+import '../options.dart';
import '../tokens/token.dart' show isUserDefinableOperator;
import '../tree/tree.dart';
import '../universe/call_structure.dart' show CallStructure;
@@ -112,7 +113,7 @@
bool isPotentiallyMutableTarget(Element target) {
if (target == null) return false;
- return (target.isVariable || target.isParameter) &&
+ return (target.isVariable || target.isRegularParameter) &&
!(target.isFinal || target.isConst);
}
@@ -142,7 +143,7 @@
r')$');
ResolverVisitor(
- Compiler compiler, Element element, ResolutionRegistry registry,
+ Resolution resolution, Element element, ResolutionRegistry registry,
{Scope scope, bool useEnclosingScope: false})
: this.enclosingElement = element,
// When the element is a field, we are actually resolving its
@@ -159,7 +160,7 @@
: element.buildScope()),
// The type annotations on a typedef do not imply type checks.
// TODO(karlklose): clean this up (dartbug.com/8870).
- inCheckContext = compiler.options.enableTypeAssertions &&
+ inCheckContext = resolution.options.enableTypeAssertions &&
!element.isLibrary &&
!element.isTypedef &&
!element.enclosingElement.isTypedef,
@@ -167,11 +168,13 @@
constantState = element.isConst
? ConstantState.CONSTANT
: ConstantState.NON_CONSTANT,
- super(compiler, registry);
+ super(resolution, registry);
- CoreClasses get coreClasses => compiler.coreClasses;
-
- CoreTypes get coreTypes => compiler.coreTypes;
+ CoreClasses get coreClasses => resolution.coreClasses;
+ CoreTypes get coreTypes => resolution.coreTypes;
+ ConstantEnvironment get constants => resolution.constants;
+ ResolverTask get resolver => resolution.resolver;
+ CompilerOptions get options => resolution.options;
AsyncMarker get currentAsyncMarker {
if (enclosingElement is FunctionElement) {
@@ -370,11 +373,7 @@
}
TypeResult visitTypeAnnotation(TypeAnnotation node) {
- DartType type = resolveTypeAnnotation(node);
- if (inCheckContext) {
- registry.registerTypeUse(new TypeUse.checkedModeCheck(type));
- }
- return new TypeResult(type);
+ return new TypeResult(resolveTypeAnnotation(node));
}
bool isNamedConstructor(Send node) => node.receiver != null;
@@ -454,18 +453,16 @@
addDeferredAction(enclosingElement, () {
functionSignature.forEachOptionalParameter((ParameterElementX parameter) {
parameter.constant =
- compiler.resolver.constantCompiler.compileConstant(parameter);
+ resolver.constantCompiler.compileConstant(parameter);
});
});
- if (inCheckContext) {
- functionSignature.forEachParameter((ParameterElement element) {
- registry.registerTypeUse(new TypeUse.checkedModeCheck(element.type));
- });
- }
+ functionSignature.forEachParameter((ParameterElement element) {
+ registry.registerTypeUse(new TypeUse.checkedModeCheck(element.type));
+ });
}
ResolutionResult visitAssert(Assert node) {
- if (!compiler.options.enableAssertMessage) {
+ if (!options.enableAssertMessage) {
if (node.hasMessage) {
reporter.reportErrorMessage(
node, MessageKind.EXPERIMENTAL_ASSERT_MESSAGE);
@@ -564,7 +561,6 @@
reporter.reportErrorMessage(node.name,
MessageKind.NAMED_FUNCTION_EXPRESSION, {'name': node.name});
}
- visit(node.returnType);
String name;
if (node.name == null) {
name = "";
@@ -573,9 +569,9 @@
}
LocalFunctionElementX function = new LocalFunctionElementX(
name, node, ElementKind.FUNCTION, Modifiers.EMPTY, enclosingElement);
- ResolverTask.processAsyncMarker(compiler, function, registry);
+ ResolverTask.processAsyncMarker(resolution, function, registry);
function.functionSignature = SignatureResolver.analyze(
- compiler,
+ resolution,
scope,
node.typeVariables,
node.parameters,
@@ -880,7 +876,7 @@
/// Compute the [AccessSemantics] corresponding to a local access of [target].
AccessSemantics computeLocalAccessSemantics(
Spannable node, LocalElement target) {
- if (target.isParameter) {
+ if (target.isRegularParameter) {
if (target.isFinal || target.isConst) {
return new StaticAccess.finalParameter(target);
} else {
@@ -2017,7 +2013,7 @@
ResolutionResult handleConstantTypeLiteralUpdate(SendSet node, Name name,
TypeDeclarationElement element, DartType type, ConstantAccess semantics) {
// TODO(johnniwinther): Remove this when all constants are evaluated.
- compiler.resolver.constantCompiler.evaluate(semantics.constant);
+ resolver.constantCompiler.evaluate(semantics.constant);
ErroneousElement error;
if (node.isIfNullAssignment) {
@@ -2560,7 +2556,7 @@
ResolutionResult handleLocalUpdate(Send node, Name name, Element element) {
AccessSemantics semantics;
ErroneousElement error;
- if (element.isParameter) {
+ if (element.isRegularParameter) {
if (element.isFinal) {
error = reportAndCreateErroneousElement(node.selector, name.text,
MessageKind.UNDEFINED_STATIC_SETTER_BUT_GETTER, {'name': name});
@@ -2569,7 +2565,7 @@
semantics = new StaticAccess.parameter(element);
}
} else if (element.isInitializingFormal &&
- compiler.options.enableInitializingFormalAccess) {
+ options.enableInitializingFormalAccess) {
error = reportAndCreateErroneousElement(node.selector, name.text,
MessageKind.UNDEFINED_STATIC_SETTER_BUT_GETTER, {'name': name});
semantics = new StaticAccess.finalParameter(element);
@@ -2627,12 +2623,12 @@
// of parse errors to make [element] erroneous. Fix this!
member.computeType(resolution);
- if (member == compiler.mirrorSystemGetNameFunction &&
- !compiler.mirrorUsageAnalyzerTask.hasMirrorUsage(enclosingElement)) {
+ if (member == resolution.mirrorSystemGetNameFunction &&
+ !resolution.mirrorUsageAnalyzerTask.hasMirrorUsage(enclosingElement)) {
reporter
.reportHintMessage(node.selector, MessageKind.STATIC_FUNCTION_BLOAT, {
- 'class': compiler.mirrorSystemClass.name,
- 'name': compiler.mirrorSystemGetNameFunction.name
+ 'class': resolution.mirrorSystemClass.name,
+ 'name': resolution.mirrorSystemGetNameFunction.name
});
}
@@ -2658,7 +2654,7 @@
registry.registerStaticUse(
new StaticUse.staticInvoke(semantics.element, callStructure));
handleForeignCall(node, semantics.element, callStructure);
- if (method == compiler.identicalFunction &&
+ if (method == resolution.identicalFunction &&
argumentsResult.isValidAsConstant) {
result = new ConstantResult(
node,
@@ -3028,7 +3024,7 @@
// TODO(johnniwinther): Move this to the backend resolution callbacks.
void handleForeignCall(
Send node, Element target, CallStructure callStructure) {
- if (target != null && compiler.backend.isForeign(target)) {
+ if (target != null && resolution.target.isForeign(target)) {
registry.registerForeignCall(node, target, callStructure, this);
}
}
@@ -3577,7 +3573,7 @@
}
ResolutionResult visitYield(Yield node) {
- if (!compiler.backend.supportsAsyncAwait) {
+ if (!resolution.target.supportsAsyncAwait) {
reporter.reportErrorMessage(
node.yieldToken, MessageKind.ASYNC_AWAIT_NOT_SUPPORTED);
} else {
@@ -3608,11 +3604,8 @@
ConstructorResult result =
resolveRedirectingFactory(node, inConstContext: isConstConstructor);
ConstructorElement redirectionTarget = result.element;
- constructor.immediateRedirectionTarget = redirectionTarget;
-
- if (result.isDeferred) {
- constructor.redirectionDeferredPrefix = result.prefix;
- }
+ constructor.setImmediateRedirectionTarget(
+ redirectionTarget, result.isDeferred ? result.prefix : null);
registry.setRedirectingTargetConstructor(node, redirectionTarget);
switch (result.kind) {
@@ -3621,7 +3614,7 @@
// Register a post process to check for cycles in the redirection chain
// and set the actual generative constructor at the end of the chain.
addDeferredAction(constructor, () {
- compiler.resolver.resolveRedirectionChain(constructor, node);
+ resolver.resolveRedirectionChain(constructor, node);
});
break;
case ConstructorResultKind.ABSTRACT:
@@ -3659,7 +3652,7 @@
.subst(type.typeArguments, targetClass.typeVariables);
FunctionType constructorType = constructor.computeType(resolution);
bool isSubtype =
- compiler.types.isSubtype(targetConstructorType, constructorType);
+ resolution.types.isSubtype(targetConstructorType, constructorType);
if (!isSubtype) {
reporter.reportWarningMessage(node, MessageKind.NOT_ASSIGNABLE,
{'fromType': targetConstructorType, 'toType': constructorType});
@@ -3684,7 +3677,7 @@
registry.registerTypeUse(new TypeUse.instantiation(redirectionTarget
.enclosingClass.thisType
.subst(type.typeArguments, targetClass.typeVariables)));
- if (enclosingElement == compiler.symbolConstructor) {
+ if (enclosingElement == resolution.symbolConstructor) {
registry.registerFeature(Feature.SYMBOL_CONSTRUCTOR);
}
if (isValidAsConstant) {
@@ -3718,7 +3711,7 @@
}
ResolutionResult visitAwait(Await node) {
- if (!compiler.backend.supportsAsyncAwait) {
+ if (!resolution.target.supportsAsyncAwait) {
reporter.reportErrorMessage(
node.awaitToken, MessageKind.ASYNC_AWAIT_NOT_SUPPORTED);
} else {
@@ -3740,7 +3733,7 @@
}
VariableList variables = new VariableList.node(node, type);
VariableDefinitionsVisitor visitor =
- new VariableDefinitionsVisitor(compiler, node, this, variables);
+ new VariableDefinitionsVisitor(resolution, node, this, variables);
Modifiers modifiers = node.modifiers;
void reportExtraModifier(String modifier) {
@@ -3773,7 +3766,7 @@
}
if (node.metadata != null) {
variables.metadataInternal =
- compiler.resolver.resolveMetadata(enclosingElement, node);
+ resolver.resolveMetadata(enclosingElement, node);
}
visitor.visit(node.definitions);
return const NoneResult();
@@ -3893,11 +3886,11 @@
if (node.isConst) {
bool isValidAsConstant = !isInvalid && constructor.isConst;
- if (constructor == compiler.symbolConstructor) {
+ if (constructor == resolution.symbolConstructor) {
Node argumentNode = node.send.arguments.head;
- ConstantExpression constant = compiler.resolver.constantCompiler
+ ConstantExpression constant = resolver.constantCompiler
.compileNode(argumentNode, registry.mapping);
- ConstantValue name = compiler.constants.getConstantValue(constant);
+ ConstantValue name = resolution.constants.getConstantValue(constant);
if (!name.isString) {
DartType type = name.getType(coreTypes);
reporter.reportErrorMessage(
@@ -3909,8 +3902,8 @@
registry.registerConstSymbol(nameString);
}
}
- } else if (constructor == compiler.mirrorsUsedConstructor) {
- compiler.mirrorUsageAnalyzerTask.validate(node, registry.mapping);
+ } else if (constructor == resolution.mirrorsUsedConstructor) {
+ resolution.mirrorUsageAnalyzerTask.validate(node, registry.mapping);
}
analyzeConstantDeferred(node);
@@ -3969,8 +3962,9 @@
analyzeConstantDeferred(node, onAnalyzed: onAnalyzed);
} else {
// Not constant.
- if (constructor == compiler.symbolConstructor &&
- !compiler.mirrorUsageAnalyzerTask.hasMirrorUsage(enclosingElement)) {
+ if (constructor == resolution.symbolConstructor &&
+ !resolution.mirrorUsageAnalyzerTask
+ .hasMirrorUsage(enclosingElement)) {
reporter.reportHintMessage(node.newToken, MessageKind.NON_CONST_BLOAT,
{'name': coreClasses.symbolClass.name});
}
@@ -4001,15 +3995,15 @@
}
void analyzeConstant(Node node, {enforceConst: true}) {
- ConstantExpression constant = compiler.resolver.constantCompiler
+ ConstantExpression constant = resolver.constantCompiler
.compileNode(node, registry.mapping, enforceConst: enforceConst);
if (constant == null) {
- assert(invariant(node, compiler.compilationFailed));
+ assert(invariant(node, reporter.hasReportedError));
return;
}
- ConstantValue value = compiler.constants.getConstantValue(constant);
+ ConstantValue value = resolution.constants.getConstantValue(constant);
if (value.isMap) {
checkConstMapKeysDontOverrideEquals(node, value);
}
@@ -4050,13 +4044,13 @@
* [:null:], if there is no corresponding constructor, class or library.
*/
ConstructorResult resolveConstructor(NewExpression node) {
- return node.accept(
- new ConstructorResolver(compiler, this, inConstContext: node.isConst));
+ return node.accept(new ConstructorResolver(resolution, this,
+ inConstContext: node.isConst));
}
ConstructorResult resolveRedirectingFactory(RedirectingFactoryBody node,
{bool inConstContext: false}) {
- return node.accept(new ConstructorResolver(compiler, this,
+ return node.accept(new ConstructorResolver(resolution, this,
inConstContext: inConstContext));
}
@@ -4065,9 +4059,7 @@
DartType type = typeResolver.resolveTypeAnnotation(this, node,
malformedIsError: malformedIsError,
deferredIsMalformed: deferredIsMalformed);
- if (inCheckContext) {
- registry.registerTypeUse(new TypeUse.checkedModeCheck(type));
- }
+ registry.registerTypeUse(new TypeUse.checkedModeCheck(type));
return type;
}
@@ -4245,7 +4237,7 @@
}
ResolutionResult visitAsyncForIn(AsyncForIn node) {
- if (!compiler.backend.supportsAsyncAwait) {
+ if (!resolution.target.supportsAsyncAwait) {
reporter.reportErrorMessage(
node.awaitToken, MessageKind.ASYNC_AWAIT_NOT_SUPPORTED);
} else {
@@ -4333,7 +4325,7 @@
}
} else {
// The selector may only be null if we reported an error.
- assert(invariant(declaration, compiler.compilationFailed));
+ assert(invariant(declaration, reporter.hasReportedError));
}
if (loopVariable != null) {
// loopVariable may be null if it could not be resolved.
@@ -4496,7 +4488,7 @@
assert(invariant(node, constant != null,
message: 'No constant computed for $node'));
- ConstantValue value = compiler.constants.getConstantValue(constant);
+ ConstantValue value = resolution.constants.getConstantValue(constant);
DartType caseType = value.getType(coreTypes); //typeOfConstant(value);
if (firstCaseType == null) {
diff --git a/pkg/compiler/lib/src/resolution/registry.dart b/pkg/compiler/lib/src/resolution/registry.dart
index e52b185..753d9a7 100644
--- a/pkg/compiler/lib/src/resolution/registry.dart
+++ b/pkg/compiler/lib/src/resolution/registry.dart
@@ -8,7 +8,7 @@
import '../common/backend_api.dart'
show Backend, ForeignResolver, NativeRegistry;
import '../common/resolution.dart'
- show Feature, ListLiteralUse, MapLiteralUse, ResolutionImpact;
+ show Feature, ListLiteralUse, MapLiteralUse, ResolutionImpact, Target;
import '../common/registry.dart' show Registry;
import '../compiler.dart' show Compiler;
import '../constants/expressions.dart';
@@ -160,20 +160,17 @@
/// [Backend], [World] and [Enqueuer].
// TODO(johnniwinther): Split this into an interface and implementation class.
class ResolutionRegistry extends Registry {
- final Compiler compiler;
+ final Target target;
final TreeElementMapping mapping;
final _ResolutionWorldImpact worldImpact;
- ResolutionRegistry(Compiler compiler, TreeElementMapping mapping)
- : this.compiler = compiler,
- this.mapping = mapping,
+ ResolutionRegistry(this.target, TreeElementMapping mapping)
+ : this.mapping = mapping,
this.worldImpact =
new _ResolutionWorldImpact(mapping.analyzedElement.toString());
bool get isForResolution => true;
- Backend get backend => compiler.backend;
-
String toString() => 'ResolutionRegistry for ${mapping.analyzedElement}';
//////////////////////////////////////////////////////////////////////////////
@@ -364,7 +361,7 @@
void registerForeignCall(Node node, Element element,
CallStructure callStructure, ResolverVisitor visitor) {
- var nativeData = backend.resolveForeignCall(node, element, callStructure,
+ var nativeData = target.resolveForeignCall(node, element, callStructure,
new ForeignResolutionResolver(visitor, this));
if (nativeData != null) {
// Split impact from resolution result.
@@ -390,7 +387,7 @@
}
ClassElement defaultSuperclass(ClassElement element) {
- return backend.defaultSuperclass(element);
+ return target.defaultSuperclass(element);
}
void registerInstantiation(InterfaceType type) {
diff --git a/pkg/compiler/lib/src/resolution/resolution.dart b/pkg/compiler/lib/src/resolution/resolution.dart
index f775190..619f748 100644
--- a/pkg/compiler/lib/src/resolution/resolution.dart
+++ b/pkg/compiler/lib/src/resolution/resolution.dart
@@ -9,10 +9,9 @@
import '../common.dart';
import '../common/names.dart' show Identifiers;
import '../common/resolution.dart'
- show Feature, ParsingContext, Resolution, ResolutionImpact;
-import '../common/tasks.dart' show CompilerTask;
+ show Feature, ParsingContext, Resolution, ResolutionImpact, Target;
+import '../common/tasks.dart' show CompilerTask, Measurer;
import '../compile_time_constants.dart' show ConstantCompiler;
-import '../compiler.dart' show Compiler;
import '../constants/expressions.dart'
show
ConstantExpression,
@@ -36,6 +35,8 @@
ParameterMetadataAnnotation,
SetterElementX,
TypedefElementX;
+import '../enqueue.dart';
+import '../options.dart';
import '../tokens/token.dart'
show
isBinaryOperator,
@@ -48,36 +49,35 @@
import '../universe/use.dart' show StaticUse, TypeUse;
import '../universe/world_impact.dart' show WorldImpact;
import '../util/util.dart' show Link, Setlet;
+import '../world.dart';
import 'class_hierarchy.dart';
import 'class_members.dart' show MembersCreator;
import 'constructors.dart';
import 'members.dart';
import 'registry.dart';
import 'resolution_result.dart';
-import 'scope.dart' show MutableScope;
import 'signatures.dart';
import 'tree_elements.dart';
import 'typedefs.dart';
class ResolverTask extends CompilerTask {
final ConstantCompiler constantCompiler;
- final Compiler compiler;
+ final Resolution resolution;
+ final World world;
- ResolverTask(Compiler compiler, this.constantCompiler)
- : compiler = compiler,
- super(compiler.measurer);
+ ResolverTask(
+ this.resolution, this.constantCompiler, this.world, Measurer measurer)
+ : super(measurer);
String get name => 'Resolver';
- DiagnosticReporter get reporter => compiler.reporter;
-
- Resolution get resolution => compiler.resolution;
-
- ParsingContext get parsingContext => compiler.parsingContext;
-
- CoreClasses get coreClasses => compiler.coreClasses;
-
- CoreTypes get coreTypes => compiler.coreTypes;
+ DiagnosticReporter get reporter => resolution.reporter;
+ Target get target => resolution.target;
+ CoreTypes get coreTypes => resolution.coreTypes;
+ CoreClasses get coreClasses => resolution.coreClasses;
+ ParsingContext get parsingContext => resolution.parsingContext;
+ CompilerOptions get options => resolution.options;
+ ResolutionEnqueuer get enqueuer => resolution.enqueuer;
ResolutionImpact resolve(Element element) {
return measure(() {
@@ -115,7 +115,7 @@
return processMetadata(resolveTypedef(typdef));
}
- compiler.unimplemented(element, "resolve($element)");
+ reporter.internalError(element, "resolve($element) not implemented.");
});
}
@@ -142,15 +142,14 @@
}
}
- static void processAsyncMarker(Compiler compiler,
+ static void processAsyncMarker(Resolution resolution,
BaseFunctionElementX element, ResolutionRegistry registry) {
- DiagnosticReporter reporter = compiler.reporter;
- Resolution resolution = compiler.resolution;
- CoreClasses coreClasses = compiler.coreClasses;
+ DiagnosticReporter reporter = resolution.reporter;
+ CoreClasses coreClasses = resolution.coreClasses;
FunctionExpression functionExpression = element.node;
AsyncModifier asyncModifier = functionExpression.asyncModifier;
if (asyncModifier != null) {
- if (!compiler.backend.supportsAsyncAwait) {
+ if (!resolution.target.supportsAsyncAwait) {
reporter.reportErrorMessage(functionExpression.asyncModifier,
MessageKind.ASYNC_AWAIT_NOT_SUPPORTED);
} else {
@@ -207,7 +206,7 @@
bool _isNativeClassOrExtendsNativeClass(ClassElement classElement) {
assert(classElement != null);
while (classElement != null) {
- if (compiler.backend.isNative(classElement)) return true;
+ if (target.isNative(classElement)) return true;
classElement = classElement.superclass;
}
return false;
@@ -239,7 +238,7 @@
ResolutionRegistry registry = visitor.registry;
registry.defineFunction(tree, element);
visitor.setupFunction(tree, element); // Modifies the scope.
- processAsyncMarker(compiler, element, registry);
+ processAsyncMarker(resolution, element, registry);
if (element.isGenerativeConstructor) {
// Even if there is no initializer list we still have to do the
@@ -248,7 +247,7 @@
new InitializerResolver(visitor, element, tree);
FunctionElement redirection = resolver.resolveInitializers(
enableInitializingFormalAccess:
- compiler.options.enableInitializingFormalAccess);
+ options.enableInitializingFormalAccess);
if (redirection != null) {
resolveRedirectingConstructor(resolver, tree, element, redirection);
}
@@ -257,8 +256,7 @@
tree, MessageKind.FUNCTION_WITH_INITIALIZER);
}
- if (!compiler.options.analyzeSignaturesOnly ||
- tree.isRedirectingFactory) {
+ if (!options.analyzeSignaturesOnly || tree.isRedirectingFactory) {
// We need to analyze the redirecting factory bodies to ensure that
// we can analyze compile-time constants.
visitor.visit(tree.body);
@@ -274,7 +272,7 @@
if (enclosingClass != null) {
// TODO(johnniwinther): Find another way to obtain mixin uses.
Iterable<MixinApplicationElement> mixinUses =
- compiler.world.allMixinUsesOf(enclosingClass);
+ world.allMixinUsesOf(enclosingClass);
ClassElement mixin = enclosingClass;
for (MixinApplicationElement mixinApplication in mixinUses) {
checkMixinSuperUses(resolutionTree, mixinApplication, mixin);
@@ -298,7 +296,7 @@
WorldImpact resolveMethodElement(FunctionElementX element) {
assert(invariant(element, element.isDeclaration));
return reporter.withCurrentElement(element, () {
- if (compiler.enqueuer.resolution.hasBeenProcessed(element)) {
+ if (enqueuer.hasBeenProcessed(element)) {
// TODO(karlklose): Remove the check for [isConstructor]. [elememts]
// should never be non-null, not even for constructors.
assert(invariant(element, element.isConstructor,
@@ -309,7 +307,7 @@
if (element.isSynthesized) {
if (element.isGenerativeConstructor) {
ResolutionRegistry registry =
- new ResolutionRegistry(compiler, _ensureTreeElements(element));
+ new ResolutionRegistry(this.target, _ensureTreeElements(element));
ConstructorElement constructor = element.asFunctionElement();
ConstructorElement target = constructor.definingConstructor;
// Ensure the signature of the synthesized element is
@@ -331,7 +329,7 @@
element.computeType(resolution);
FunctionElementX implementation = element;
if (element.isExternal) {
- implementation = compiler.backend.resolveExternalFunction(element);
+ implementation = target.resolveExternalFunction(element);
}
return resolveMethodElementImplementation(
implementation, implementation.node);
@@ -346,8 +344,8 @@
/// This method should only be used by this library (or tests of
/// this library).
ResolverVisitor visitorFor(Element element, {bool useEnclosingScope: false}) {
- return new ResolverVisitor(compiler, element,
- new ResolutionRegistry(compiler, _ensureTreeElements(element)),
+ return new ResolverVisitor(resolution, element,
+ new ResolutionRegistry(target, _ensureTreeElements(element)),
useEnclosingScope: useEnclosingScope);
}
@@ -448,11 +446,11 @@
void resolveRedirectionChain(ConstructorElement constructor, Spannable node) {
ConstructorElement target = constructor;
- InterfaceType targetType;
- List<Element> seen = new List<Element>();
+ DartType targetType;
+ List<ConstructorElement> seen = new List<ConstructorElement>();
bool isMalformed = false;
// Follow the chain of redirections and check for cycles.
- while (target.isRedirectingFactory || target.isPatched) {
+ while (target.isRedirectingFactory) {
if (target.hasEffectiveTarget) {
// We found a constructor that already has been processed.
// TODO(johnniwinther): Should `effectiveTargetType` be part of the
@@ -466,12 +464,7 @@
break;
}
- Element nextTarget;
- if (target.isPatched) {
- nextTarget = target.patch;
- } else {
- nextTarget = target.immediateRedirectionTarget;
- }
+ Element nextTarget = target.immediateRedirectionTarget;
if (seen.contains(nextTarget)) {
reporter.reportErrorMessage(
@@ -503,16 +496,14 @@
// substitution of the target type with respect to the factory type.
while (!seen.isEmpty) {
ConstructorElementX factory = seen.removeLast();
- TreeElements treeElements = factory.treeElements;
- assert(invariant(node, treeElements != null,
- message: 'No TreeElements cached for $factory.'));
- if (!factory.isPatched) {
- FunctionExpression functionNode = factory.node;
- RedirectingFactoryBody redirectionNode = functionNode.body;
- DartType factoryType = treeElements.getType(redirectionNode);
- if (!factoryType.isDynamic) {
- targetType = targetType.substByContext(factoryType);
- }
+ ResolvedAst resolvedAst = factory.resolvedAst;
+ assert(invariant(node, resolvedAst != null,
+ message: 'No ResolvedAst for $factory.'));
+ FunctionExpression functionNode = resolvedAst.node;
+ RedirectingFactoryBody redirectionNode = resolvedAst.body;
+ DartType factoryType = resolvedAst.elements.getType(redirectionNode);
+ if (!factoryType.isDynamic) {
+ targetType = targetType.substByContext(factoryType);
}
factory.setEffectiveTarget(target, targetType, isMalformed: isMalformed);
}
@@ -545,7 +536,7 @@
// TODO(ahe): Cache the node in cls.
cls
.parseNode(parsingContext)
- .accept(new ClassSupertypeResolver(compiler, cls));
+ .accept(new ClassSupertypeResolver(resolution, cls));
if (cls.supertypeLoadState != STATE_DONE) {
cls.supertypeLoadState = STATE_DONE;
}
@@ -610,8 +601,8 @@
TreeElements resolveClass(BaseClassElementX element) {
return _resolveTypeDeclaration(element, () {
// TODO(johnniwinther): Store the mapping in the resolution enqueuer.
- ResolutionRegistry registry =
- new ResolutionRegistry(compiler, _ensureTreeElements(element));
+ ResolutionRegistry registry = new ResolutionRegistry(
+ resolution.target, _ensureTreeElements(element));
resolveClassInternal(element, registry);
return element.treeElements;
});
@@ -637,10 +628,10 @@
loadSupertypes(element, tree);
ClassResolverVisitor visitor =
- new ClassResolverVisitor(compiler, element, registry);
+ new ClassResolverVisitor(resolution, element, registry);
visitor.visit(tree);
element.resolutionState = STATE_DONE;
- compiler.onClassResolved(element);
+ resolution.onClassResolved(element);
pendingClassesToBePostProcessed.add(element);
}));
if (element.isPatched) {
@@ -671,8 +662,8 @@
for (MetadataAnnotation metadata in element.implementation.metadata) {
metadata.ensureResolved(resolution);
ConstantValue value =
- compiler.constants.getConstantValue(metadata.constant);
- if (!element.isProxy && compiler.isProxyConstant(value)) {
+ resolution.constants.getConstantValue(metadata.constant);
+ if (!element.isProxy && resolution.isProxyConstant(value)) {
element.isProxy = true;
}
}
@@ -760,7 +751,7 @@
// mixin application has been performed.
// TODO(johnniwinther): Obtain the [TreeElements] for [member]
// differently.
- if (compiler.enqueuer.resolution.hasBeenProcessed(member)) {
+ if (resolution.enqueuer.hasBeenProcessed(member)) {
if (member.resolvedAst.kind == ResolvedAstKind.PARSED) {
checkMixinSuperUses(
member.resolvedAst.elements, mixinApplication, mixin);
@@ -1009,13 +1000,14 @@
return reporter.withCurrentElement(element, () {
FunctionExpression node = element.parseNode(parsingContext);
return measure(() => SignatureResolver.analyze(
- compiler,
+ resolution,
element.enclosingElement.buildScope(),
node.typeVariables,
node.parameters,
node.returnType,
element,
- new ResolutionRegistry(compiler, _ensureTreeElements(element)),
+ new ResolutionRegistry(
+ resolution.target, _ensureTreeElements(element)),
defaultValuesError: defaultValuesError,
createRealParameters: true));
});
@@ -1023,17 +1015,17 @@
WorldImpact resolveTypedef(TypedefElementX element) {
if (element.isResolved) return const ResolutionImpact();
- compiler.world.allTypedefs.add(element);
+ world.allTypedefs.add(element);
return _resolveTypeDeclaration(element, () {
- ResolutionRegistry registry =
- new ResolutionRegistry(compiler, _ensureTreeElements(element));
+ ResolutionRegistry registry = new ResolutionRegistry(
+ resolution.target, _ensureTreeElements(element));
return reporter.withCurrentElement(element, () {
return measure(() {
assert(element.resolutionState == STATE_NOT_STARTED);
element.resolutionState = STATE_STARTED;
Typedef node = element.parseNode(parsingContext);
TypedefResolverVisitor visitor =
- new TypedefResolverVisitor(compiler, element, registry);
+ new TypedefResolverVisitor(resolution, element, registry);
visitor.visit(node);
element.resolutionState = STATE_DONE;
return registry.worldImpact;
diff --git a/pkg/compiler/lib/src/resolution/resolution_common.dart b/pkg/compiler/lib/src/resolution/resolution_common.dart
index 819c292..53d3c69 100644
--- a/pkg/compiler/lib/src/resolution/resolution_common.dart
+++ b/pkg/compiler/lib/src/resolution/resolution_common.dart
@@ -6,22 +6,18 @@
import '../common.dart';
import '../common/resolution.dart' show Resolution;
-import '../compiler.dart' show Compiler;
import '../elements/elements.dart';
import '../tree/tree.dart';
-
import 'registry.dart' show ResolutionRegistry;
import 'scope.dart' show Scope;
import 'type_resolver.dart' show TypeResolver;
class CommonResolverVisitor<R> extends Visitor<R> {
- final Compiler compiler;
+ final Resolution resolution;
- CommonResolverVisitor(Compiler this.compiler);
+ CommonResolverVisitor(this.resolution);
- DiagnosticReporter get reporter => compiler.reporter;
-
- Resolution get resolution => compiler.resolution;
+ DiagnosticReporter get reporter => resolution.reporter;
R visitNode(Node node) {
return reporter.internalError(
@@ -34,7 +30,7 @@
R visit(Node node) => (node == null) ? null : node.accept(this);
void addDeferredAction(Element element, void action()) {
- compiler.enqueuer.resolution.addDeferredAction(element, action);
+ resolution.enqueuer.addDeferredAction(element, action);
}
}
@@ -52,9 +48,9 @@
/// The current scope of the visitor.
Scope get scope;
- MappingVisitor(Compiler compiler, ResolutionRegistry this.registry)
- : typeResolver = new TypeResolver(compiler),
- super(compiler);
+ MappingVisitor(Resolution resolution, this.registry)
+ : typeResolver = new TypeResolver(resolution),
+ super(resolution);
AsyncMarker get currentAsyncMarker => AsyncMarker.SYNC;
diff --git a/pkg/compiler/lib/src/resolution/send_structure.dart b/pkg/compiler/lib/src/resolution/send_structure.dart
index 4b6d187..b26087e 100644
--- a/pkg/compiler/lib/src/resolution/send_structure.dart
+++ b/pkg/compiler/lib/src/resolution/send_structure.dart
@@ -1504,7 +1504,7 @@
IndexSetIfNullStructure(this.semantics);
@override
- SendStructureKind get kind => SendStructureKind.INDEX_SET;
+ SendStructureKind get kind => SendStructureKind.INDEX_SET_IF_NULL;
R dispatch(SemanticSendVisitor<R, A> visitor, Send node, A arg) {
switch (semantics.kind) {
diff --git a/pkg/compiler/lib/src/resolution/signatures.dart b/pkg/compiler/lib/src/resolution/signatures.dart
index d3f3264..eff4988 100644
--- a/pkg/compiler/lib/src/resolution/signatures.dart
+++ b/pkg/compiler/lib/src/resolution/signatures.dart
@@ -5,7 +5,7 @@
library dart2js.resolution.signatures;
import '../common.dart';
-import '../compiler.dart' show Compiler;
+import '../common/resolution.dart';
import '../dart_types.dart';
import '../elements/elements.dart';
import '../elements/modelx.dart'
@@ -40,15 +40,19 @@
bool optionalParametersAreNamed = false;
VariableDefinitions currentDefinitions;
- SignatureResolver(Compiler compiler, FunctionTypedElement enclosingElement,
- Scope scope, ResolutionRegistry registry,
- {this.defaultValuesError, this.createRealParameters})
+ SignatureResolver(
+ Resolution resolution,
+ FunctionTypedElement enclosingElement,
+ Scope scope,
+ ResolutionRegistry registry,
+ {this.defaultValuesError,
+ this.createRealParameters})
: this.scope = scope,
this.enclosingElement = enclosingElement,
this.resolver = new ResolverVisitor(
- compiler, enclosingElement, registry,
+ resolution, enclosingElement, registry,
scope: scope),
- super(compiler, registry);
+ super(resolution, registry);
bool get defaultValuesAllowed => defaultValuesError == null;
@@ -93,7 +97,7 @@
FormalElementX element = definition.accept(this);
if (currentDefinitions.metadata != null) {
element.metadataInternal =
- compiler.resolver.resolveMetadata(element, node);
+ resolution.resolver.resolveMetadata(element, node);
}
currentDefinitions = null;
return element;
@@ -111,7 +115,7 @@
[VariableElement fieldElement]) {
void computeFunctionType(FunctionExpression functionExpression) {
FunctionSignature functionSignature = SignatureResolver.analyze(
- compiler,
+ resolution,
scope,
functionExpression.typeVariables,
functionExpression.parameters,
@@ -290,7 +294,7 @@
* the parameters will only implement [FormalElement].
*/
static FunctionSignature analyze(
- Compiler compiler,
+ Resolution resolution,
Scope scope,
NodeList typeVariables,
NodeList formalParameters,
@@ -300,7 +304,7 @@
{MessageKind defaultValuesError,
bool createRealParameters: false,
bool isFunctionExpression: false}) {
- DiagnosticReporter reporter = compiler.reporter;
+ DiagnosticReporter reporter = resolution.reporter;
List<DartType> createTypeVariables(NodeList typeVariableNodes) {
if (typeVariableNodes == null) return const <DartType>[];
@@ -329,7 +333,7 @@
List<DartType> typeVariableTypes = createTypeVariables(typeVariables);
scope = new FunctionSignatureBuildingScope(scope, typeVariableTypes);
SignatureResolver visitor = new SignatureResolver(
- compiler, element, scope, registry,
+ resolution, element, scope, registry,
defaultValuesError: defaultValuesError,
createRealParameters: createRealParameters);
List<Element> parameters = const <Element>[];
@@ -341,7 +345,7 @@
// reported. In the case of parse errors, it is possible that there
// are formal parameters, but something else in the method failed to
// parse. So we suppress the message about missing formals.
- assert(invariant(element, compiler.compilationFailed));
+ assert(invariant(element, reporter.hasReportedError));
} else {
reporter.reportErrorMessage(element, MessageKind.MISSING_FORMALS);
}
@@ -366,9 +370,7 @@
returnType = element.enclosingClass.thisType;
// Because there is no type annotation for the return type of
// this element, we explicitly add one.
- if (compiler.options.enableTypeAssertions) {
- registry.registerTypeUse(new TypeUse.checkedModeCheck(returnType));
- }
+ registry.registerTypeUse(new TypeUse.checkedModeCheck(returnType));
} else {
AsyncMarker asyncMarker = AsyncMarker.SYNC;
if (isFunctionExpression) {
@@ -382,13 +384,13 @@
returnType = visitor.resolveReturnType(returnNode);
break;
case AsyncMarker.SYNC_STAR:
- returnType = compiler.coreTypes.iterableType();
+ returnType = resolution.coreTypes.iterableType();
break;
case AsyncMarker.ASYNC:
- returnType = compiler.coreTypes.futureType();
+ returnType = resolution.coreTypes.futureType();
break;
case AsyncMarker.ASYNC_STAR:
- returnType = compiler.coreTypes.streamType();
+ returnType = resolution.coreTypes.streamType();
break;
}
}
diff --git a/pkg/compiler/lib/src/resolution/tree_elements.dart b/pkg/compiler/lib/src/resolution/tree_elements.dart
index 1e52fca..974981c 100644
--- a/pkg/compiler/lib/src/resolution/tree_elements.dart
+++ b/pkg/compiler/lib/src/resolution/tree_elements.dart
@@ -139,7 +139,7 @@
/// Map from nodes to native data.
Map<Node, dynamic> _nativeData;
- final int hashCode = ++_hashCodeCounter;
+ final int hashCode = _hashCodeCounter = (_hashCodeCounter + 1).toUnsigned(30);
static int _hashCodeCounter = 0;
TreeElementMapping(this.analyzedElement);
diff --git a/pkg/compiler/lib/src/resolution/type_resolver.dart b/pkg/compiler/lib/src/resolution/type_resolver.dart
index 9837a09..c1dbcfb 100644
--- a/pkg/compiler/lib/src/resolution/type_resolver.dart
+++ b/pkg/compiler/lib/src/resolution/type_resolver.dart
@@ -6,8 +6,6 @@
import '../common.dart';
import '../common/resolution.dart' show Feature, Resolution;
-import '../compiler.dart' show Compiler;
-import '../dart_backend/dart_backend.dart' show DartBackend;
import '../dart_types.dart';
import '../elements/elements.dart'
show
@@ -18,25 +16,24 @@
ErroneousElement,
PrefixElement,
TypedefElement,
- TypeDeclarationElement,
TypeVariableElement;
import '../elements/modelx.dart' show ErroneousElementX;
+import '../resolution/resolution.dart';
import '../tree/tree.dart';
import '../util/util.dart' show Link;
-
import 'members.dart' show lookupInScope;
import 'registry.dart' show ResolutionRegistry;
import 'resolution_common.dart' show MappingVisitor;
import 'scope.dart' show Scope;
class TypeResolver {
- final Compiler compiler;
+ final Resolution resolution;
- TypeResolver(this.compiler);
+ TypeResolver(this.resolution);
- DiagnosticReporter get reporter => compiler.reporter;
-
- Resolution get resolution => compiler.resolution;
+ ResolverTask get resolver => resolution.resolver;
+ DiagnosticReporter get reporter => resolution.reporter;
+ Types get types => resolution.types;
/// Tries to resolve the type name as an element.
Element resolveTypeName(
@@ -50,12 +47,7 @@
// The receiver is a prefix. Lookup in the imported members.
PrefixElement prefix = prefixElement;
element = prefix.lookupLocalMember(typeName.source);
- // TODO(17260, sigurdm): The test for DartBackend is there because
- // dart2dart outputs malformed types with prefix.
- if (element != null &&
- prefix.isDeferred &&
- deferredIsMalformed &&
- compiler.backend is! DartBackend) {
+ if (element != null && prefix.isDeferred && deferredIsMalformed) {
element = new ErroneousElementX(MessageKind.DEFERRED_TYPE_ANNOTATION,
{'node': typeName}, element.name, element);
}
@@ -167,7 +159,7 @@
ClassElement cls = element;
// TODO(johnniwinther): [ensureClassWillBeResolvedInternal] should imply
// [computeType].
- compiler.resolver.ensureClassWillBeResolvedInternal(cls);
+ resolver.ensureClassWillBeResolvedInternal(cls);
cls.computeType(resolution);
List<DartType> arguments = <DartType>[];
bool hasTypeArgumentMismatch =
@@ -240,7 +232,7 @@
void checkTypeVariableBounds(TypeAnnotation node, GenericType type) {
void checkTypeVariableBound(_, DartType typeArgument,
TypeVariableType typeVariable, DartType bound) {
- if (!compiler.types.isSubtype(typeArgument, bound)) {
+ if (!types.isSubtype(typeArgument, bound)) {
reporter.reportWarningMessage(
node, MessageKind.INVALID_TYPE_VARIABLE_BOUND, {
'typeVariable': typeVariable,
@@ -250,9 +242,8 @@
});
}
}
- ;
- compiler.types.checkTypeVariableBounds(type, checkTypeVariableBound);
+ types.checkTypeVariableBounds(type, checkTypeVariableBound);
}
/**
diff --git a/pkg/compiler/lib/src/resolution/typedefs.dart b/pkg/compiler/lib/src/resolution/typedefs.dart
index cee72df..7f18141 100644
--- a/pkg/compiler/lib/src/resolution/typedefs.dart
+++ b/pkg/compiler/lib/src/resolution/typedefs.dart
@@ -4,8 +4,10 @@
library dart2js.resolution.typedefs;
+import 'dart:developer';
+
import '../common.dart';
-import '../compiler.dart' show Compiler;
+import '../common/resolution.dart';
import '../dart_types.dart';
import '../elements/elements.dart'
show FunctionSignature, TypedefElement, TypeVariableElement;
@@ -21,9 +23,9 @@
class TypedefResolverVisitor extends TypeDefinitionVisitor {
TypedefElementX get element => enclosingElement;
- TypedefResolverVisitor(Compiler compiler, TypedefElement typedefElement,
+ TypedefResolverVisitor(Resolution resolution, TypedefElement typedefElement,
ResolutionRegistry registry)
- : super(compiler, typedefElement, registry);
+ : super(resolution, typedefElement, registry);
visitTypedef(Typedef node) {
element.computeType(resolution);
@@ -31,7 +33,7 @@
resolveTypeVariableBounds(node.typeParameters);
FunctionSignature signature = SignatureResolver.analyze(
- compiler,
+ resolution,
scope,
null /* typeVariables */,
node.formals,
@@ -67,7 +69,7 @@
Link<TypeVariableElement> seenTypeVariables =
const Link<TypeVariableElement>();
- TypedefCyclicVisitor(this.reporter, TypedefElement this.element);
+ TypedefCyclicVisitor(this.reporter, this.element);
visitType(DartType type, _) {
// Do nothing.
@@ -115,7 +117,9 @@
seenTypedefs = seenTypedefs.prepend(typedefElement);
seenTypedefsCount++;
type.visitChildren(this, null);
- typedefElement.aliasCache.accept(this, null);
+ if (!typedefElement.isMalformed) {
+ typedefElement.aliasCache.accept(this, null);
+ }
seenTypedefs = seenTypedefs.tail;
seenTypedefsCount--;
}
diff --git a/pkg/compiler/lib/src/resolution/variables.dart b/pkg/compiler/lib/src/resolution/variables.dart
index c5609a8..28d5372 100644
--- a/pkg/compiler/lib/src/resolution/variables.dart
+++ b/pkg/compiler/lib/src/resolution/variables.dart
@@ -5,7 +5,7 @@
library dart2js.resolution.variables;
import '../common.dart';
-import '../compiler.dart' show Compiler;
+import '../common/resolution.dart';
import '../elements/modelx.dart' show LocalVariableElementX, VariableList;
import '../tree/tree.dart';
import '../universe/use.dart' show TypeUse;
@@ -22,8 +22,8 @@
VariableList variables;
VariableDefinitionsVisitor(
- Compiler compiler, this.definitions, this.resolver, this.variables)
- : super(compiler) {}
+ Resolution resolution, this.definitions, this.resolver, this.variables)
+ : super(resolution);
ResolutionRegistry get registry => resolver.registry;
@@ -45,7 +45,7 @@
// The variable is initialized to null.
// TODO(johnniwinther): Register a feature instead.
registry.registerTypeUse(
- new TypeUse.instantiation(compiler.coreTypes.nullType));
+ new TypeUse.instantiation(resolution.coreTypes.nullType));
if (definitions.modifiers.isConst) {
if (resolver.inLoopVariable) {
reporter.reportErrorMessage(node, MessageKind.CONST_LOOP_VARIABLE);
@@ -68,9 +68,9 @@
resolver.defineLocalVariable(link.head, element);
resolver.addToScope(element);
if (definitions.modifiers.isConst) {
- compiler.enqueuer.resolution.addDeferredAction(element, () {
+ addDeferredAction(element, () {
element.constant =
- compiler.resolver.constantCompiler.compileConstant(element);
+ resolution.resolver.constantCompiler.compileConstant(element);
});
}
}
diff --git a/pkg/compiler/lib/src/serialization/element_serialization.dart b/pkg/compiler/lib/src/serialization/element_serialization.dart
index d51c67a..3a63bbc 100644
--- a/pkg/compiler/lib/src/serialization/element_serialization.dart
+++ b/pkg/compiler/lib/src/serialization/element_serialization.dart
@@ -12,7 +12,11 @@
import '../diagnostics/messages.dart';
import '../elements/elements.dart';
import '../elements/modelx.dart'
- show DeferredLoaderGetterElementX, ErroneousElementX;
+ show
+ DeferredLoaderGetterElementX,
+ ErroneousElementX,
+ WarnOnUseElementX,
+ WrappedMessage;
import 'constant_serialization.dart';
import 'keys.dart';
import 'modelz.dart';
@@ -55,6 +59,7 @@
PREFIX,
DEFERRED_LOAD_LIBRARY,
LOCAL_VARIABLE,
+ WARN_ON_USE,
EXTERNAL_LIBRARY,
EXTERNAL_LIBRARY_MEMBER,
EXTERNAL_CLASS_MEMBER,
@@ -84,6 +89,7 @@
const ImportSerializer(),
const ExportSerializer(),
const LocalVariableSerializer(),
+ const WarnOnUseSerializer(),
];
/// Interface for a function that can serialize a set of element kinds.
@@ -216,12 +222,7 @@
encoder.setElement(Key.ENCLOSING, element.enclosingElement);
encoder.setString(Key.NAME, element.name);
encoder.setEnum(Key.MESSAGE_KIND, element.messageKind);
- if (element.messageArguments.isNotEmpty) {
- MapEncoder mapEncoder = encoder.createMap(Key.ARGUMENTS);
- element.messageArguments.forEach((String key, var value) {
- mapEncoder.setString(key, Message.convertToString(value));
- });
- }
+ serializeMessageArguments(encoder, Key.ARGUMENTS, element.messageArguments);
}
}
@@ -292,8 +293,52 @@
encoder.setElements(Key.IMPORTS, getImports(element));
encoder.setElements(Key.EXPORTS, element.exports);
- encoder.setElements(Key.IMPORT_SCOPE, getImportedElements(element));
+ List<Element> importedElements = getImportedElements(element);
+ encoder.setElements(Key.IMPORT_SCOPE, importedElements);
encoder.setElements(Key.EXPORT_SCOPE, getExportedElements(element));
+
+ Map<Element, Iterable<ImportElement>> importsForMap =
+ <Element, Iterable<ImportElement>>{};
+
+ /// Map imports for [importedElement] in importsForMap.
+ ///
+ /// Imports are mapped to [AbstractFieldElement] which are not serialized
+ /// so we use getter (or setter if there is no getter) as the key.
+ void addImportsForElement(Element importedElement) {
+ Element key = importedElement;
+ if (importedElement.isDeferredLoaderGetter) {
+ // Use [importedElement].
+ } else if (importedElement.isGetter) {
+ GetterElement getter = importedElement;
+ importedElement = getter.abstractField;
+ } else if (importedElement.isSetter) {
+ SetterElement setter = importedElement;
+ if (setter.getter != null) {
+ return;
+ }
+ importedElement = setter.abstractField;
+ }
+ importsForMap.putIfAbsent(
+ key, () => element.getImportsFor(importedElement));
+ }
+
+ for (ImportElement import in getImports(element)) {
+ if (import.prefix != null) {
+ Set<Element> importedElements = new Set<Element>();
+ import.prefix.forEachLocalMember(
+ SerializerUtil.flattenElements(importedElements));
+ importedElements.forEach(addImportsForElement);
+ }
+ }
+ importedElements.forEach(addImportsForElement);
+
+ ListEncoder importsForEncoder = encoder.createList(Key.IMPORTS_FOR);
+ importsForMap
+ .forEach((Element importedElement, Iterable<ImportElement> imports) {
+ ObjectEncoder objectEncoder = importsForEncoder.createObject();
+ objectEncoder.setElement(Key.ELEMENT, importedElement);
+ objectEncoder.setElements(Key.IMPORTS, imports);
+ });
}
}
@@ -454,6 +499,8 @@
.computeEffectiveTargetType(element.enclosingClass.thisType));
encoder.setElement(Key.IMMEDIATE_REDIRECTION_TARGET,
element.immediateRedirectionTarget);
+ encoder.setBool(Key.EFFECTIVE_TARGET_IS_MALFORMED,
+ element.isEffectiveTargetMalformed);
if (element.redirectionDeferredPrefix != null) {
encoder.setElement(Key.PREFIX, element.redirectionDeferredPrefix);
}
@@ -544,6 +591,8 @@
if (element.isFunction) {
encoder.setBool(Key.IS_OPERATOR, element.isOperator);
encoder.setEnum(Key.ASYNC_MARKER, element.asyncMarker);
+ } else if (element.isGetter) {
+ encoder.setEnum(Key.ASYNC_MARKER, element.asyncMarker);
}
SerializerUtil.serializeParentRelation(element, encoder);
encoder.setBool(Key.IS_EXTERNAL, element.isExternal);
@@ -554,6 +603,7 @@
encoder.setElement(
Key.EXECUTABLE_CONTEXT, localFunction.executableContext);
}
+ encoder.setTypes(Key.TYPE_VARIABLES, element.typeVariables);
}
}
@@ -605,7 +655,7 @@
const ParameterSerializer();
SerializedElementKind getSerializedKind(Element element) {
- if (element.isParameter) {
+ if (element.isRegularParameter) {
return SerializedElementKind.PARAMETER;
} else if (element.isInitializingFormal) {
return SerializedElementKind.INITIALIZING_FORMAL;
@@ -721,6 +771,9 @@
encoder.setElement(Key.LIBRARY, element.library);
encoder.setElement(Key.COMPILATION_UNIT, element.compilationUnit);
encoder.setBool(Key.IS_DEFERRED, element.isDeferred);
+ Set<Element> members = new Set<Element>();
+ element.forEachLocalMember(SerializerUtil.flattenElements(members));
+ encoder.setElements(Key.MEMBERS, members);
if (element.isDeferred) {
encoder.setElement(Key.IMPORT, element.deferredImport);
encoder.setElement(Key.GETTER, element.loadLibrary);
@@ -744,6 +797,25 @@
}
}
+class WarnOnUseSerializer implements ElementSerializer {
+ const WarnOnUseSerializer();
+
+ SerializedElementKind getSerializedKind(Element element) {
+ if (element.isWarnOnUse) {
+ return SerializedElementKind.WARN_ON_USE;
+ }
+ return null;
+ }
+
+ void serialize(WarnOnUseElementX element, ObjectEncoder encoder,
+ SerializedElementKind kind) {
+ encoder.setElement(Key.ENCLOSING, element.enclosingElement);
+ encoder.setElement(Key.ELEMENT, element.wrappedElement);
+ serializeWrappedMessage(encoder, Key.WARNING, element.warning);
+ serializeWrappedMessage(encoder, Key.INFO, element.info);
+ }
+}
+
/// Utility class for deserializing [Element]s.
///
/// This is used by the [Deserializer].
@@ -762,13 +834,8 @@
String name = decoder.getString(Key.NAME);
MessageKind messageKind =
decoder.getEnum(Key.MESSAGE_KIND, MessageKind.values);
- Map<String, String> arguments = <String, String>{};
- MapDecoder mapDecoder = decoder.getMap(Key.ARGUMENTS, isOptional: true);
- if (mapDecoder != null) {
- mapDecoder.forEachKey((String key) {
- arguments[key] = mapDecoder.getString(key);
- });
- }
+ Map<String, String> arguments =
+ deserializeMessageArguments(decoder, Key.ARGUMENTS);
return new ErroneousElementX(messageKind, arguments, name, enclosing);
case SerializedElementKind.LIBRARY:
return new LibraryElementZ(decoder);
@@ -839,6 +906,13 @@
return new DeferredLoaderGetterElementX(decoder.getElement(Key.PREFIX));
case SerializedElementKind.LOCAL_VARIABLE:
return new LocalVariableElementZ(decoder);
+ case SerializedElementKind.WARN_ON_USE:
+ Element enclosing = decoder.getElement(Key.ENCLOSING);
+ Element element = decoder.getElement(Key.ELEMENT);
+ WrappedMessage warning =
+ deserializeWrappedMessage(decoder, Key.WARNING);
+ WrappedMessage info = deserializeWrappedMessage(decoder, Key.INFO);
+ return new WarnOnUseElementX(warning, info, enclosing, element);
case SerializedElementKind.EXTERNAL_LIBRARY:
case SerializedElementKind.EXTERNAL_LIBRARY_MEMBER:
case SerializedElementKind.EXTERNAL_CLASS_MEMBER:
diff --git a/pkg/compiler/lib/src/serialization/equivalence.dart b/pkg/compiler/lib/src/serialization/equivalence.dart
index a7c08b5..6cb175c 100644
--- a/pkg/compiler/lib/src/serialization/equivalence.dart
+++ b/pkg/compiler/lib/src/serialization/equivalence.dart
@@ -516,6 +516,20 @@
element1, element2, 'name', element1.name, element2.name) &&
visit(element1.library, element2.library);
}
+
+ @override
+ bool visitErroneousElement(
+ ErroneousElement element1, ErroneousElement element2) {
+ return strategy.test(element1, element2, 'messageKind',
+ element1.messageKind, element2.messageKind);
+ }
+
+ @override
+ bool visitWarnOnUseElement(
+ WarnOnUseElement element1, WarnOnUseElement element2) {
+ return strategy.testElements(element1, element2, 'wrappedElement',
+ element1.wrappedElement, element2.wrappedElement);
+ }
}
/// Visitor that checks for equivalence of [DartType]s.
@@ -562,7 +576,9 @@
@override
bool visitTypeVariableType(TypeVariableType type, TypeVariableType other) {
return strategy.testElements(
- type, other, 'element', type.element, other.element);
+ type, other, 'element', type.element, other.element) &&
+ strategy.test(type, other, 'is MethodTypeVariableType',
+ type is MethodTypeVariableType, other is MethodTypeVariableType);
}
@override
diff --git a/pkg/compiler/lib/src/serialization/keys.dart b/pkg/compiler/lib/src/serialization/keys.dart
index 2c70168..0fa501a 100644
--- a/pkg/compiler/lib/src/serialization/keys.dart
+++ b/pkg/compiler/lib/src/serialization/keys.dart
@@ -29,6 +29,8 @@
static const Key DYNAMIC_USES = const Key('dynamic-uses');
static const Key EFFECTIVE_TARGET = const Key('effectiveTarget');
static const Key EFFECTIVE_TARGET_TYPE = const Key('effectiveTargetType');
+ static const Key EFFECTIVE_TARGET_IS_MALFORMED =
+ const Key('effectiveTargetIsMalformed');
static const Key ELEMENT = const Key('element');
static const Key ELEMENTS = const Key('elements');
static const Key ENCLOSING = const Key('enclosing');
@@ -49,9 +51,11 @@
static const Key IMPACTS = const Key('impacts');
static const Key IMPORT = const Key('import');
static const Key IMPORTS = const Key('imports');
+ static const Key IMPORTS_FOR = const Key('importsFor');
static const Key IMPORT_SCOPE = const Key('import-scope');
- static const Key INTERFACES = const Key('interfaces');
static const Key INDEX = const Key('index');
+ static const Key INFO = const Key('info');
+ static const Key INTERFACES = const Key('interfaces');
static const Key IS_ABSTRACT = const Key('isAbstract');
static const Key IS_BREAK_TARGET = const Key('isBreakTarget');
static const Key IS_CONST = const Key('isConst');
@@ -61,6 +65,8 @@
static const Key IS_EXTERNAL = const Key('isExternal');
static const Key IS_FINAL = const Key('isFinal');
static const Key IS_INJECTED = const Key('isInjected');
+ static const Key IS_METHOD_TYPE_VARIABLE_TYPE =
+ const Key('isMethodTypeVariableType');
static const Key IS_NAMED = const Key('isNamed');
static const Key IS_OPERATOR = const Key('isOperator');
static const Key IS_OPTIONAL = const Key('isOptional');
@@ -111,6 +117,7 @@
static const Key SEMANTICS = const Key('semantics');
static const Key SEND_STRUCTURE = const Key('sendStructure');
static const Key SETTER = const Key('setter');
+ static const Key SOURCE_SPAN = const Key('sourceSpan');
static const Key STATIC_USES = const Key('static-uses');
static const Key SUB_KIND = const Key('subKind');
static const Key SUPERTYPE = const Key('supertype');
@@ -128,6 +135,7 @@
static const Key URI = const Key('uri');
static const Key VALUE = const Key('value');
static const Key VALUES = const Key('values');
+ static const Key WARNING = const Key('warning');
final String name;
diff --git a/pkg/compiler/lib/src/serialization/modelz.dart b/pkg/compiler/lib/src/serialization/modelz.dart
index 4c932f3..55ab23e 100644
--- a/pkg/compiler/lib/src/serialization/modelz.dart
+++ b/pkg/compiler/lib/src/serialization/modelz.dart
@@ -196,7 +196,7 @@
String setterName = '$name,=';
bool hasSetterId = members.containsKey(setterName);
Element element;
- Element setterElement;
+ SetterElement setterElement;
if (!hasId && !hasSetterId) {
_lookupCache[name] = null;
return null;
@@ -236,7 +236,12 @@
Map<String, Element> setters = <String, Element>{};
for (Element element in elements) {
String name = element.name;
- if (element.isGetter) {
+ if (element.isDeferredLoaderGetter) {
+ // Store directly.
+ // TODO(johnniwinther): Should modelx be normalized to put `loadLibrary`
+ // in an [AbstractFieldElement] instead?
+ _lookupMap[name] = element;
+ } else if (element.isGetter) {
accessorNames.add(name);
getters[name] = element;
// Inserting [element] here to ensure insert order of [name].
@@ -329,7 +334,18 @@
final GetterElementZ getter;
final SetterElementZ setter;
- AbstractFieldElementZ(this.name, this.getter, this.setter) {
+ factory AbstractFieldElementZ(
+ String name, GetterElement getter, SetterElement setter) {
+ if (getter?.abstractField != null) {
+ return getter.abstractField;
+ } else if (setter?.abstractField != null) {
+ return setter.abstractField;
+ } else {
+ return new AbstractFieldElementZ._(name, getter, setter);
+ }
+ }
+
+ AbstractFieldElementZ._(this.name, this.getter, this.setter) {
if (getter != null) {
getter.abstractField = this;
getter.setter = setter;
@@ -393,6 +409,7 @@
List<ExportElement> _exports;
ListedContainer _exportsMap;
ListedContainer _importsMap;
+ Map<Element, List<ImportElement>> _importsFor;
LibraryElementZ(ObjectDecoder decoder) : super(decoder);
@@ -492,7 +509,28 @@
void _ensureImports() {
if (_importsMap == null) {
- _importsMap = new ListedContainer(_decoder.getElements(Key.IMPORT_SCOPE));
+ _importsMap = new ListedContainer(
+ _decoder.getElements(Key.IMPORT_SCOPE, isOptional: true));
+ _importsFor = <Element, List<ImportElement>>{};
+
+ ListDecoder importsDecoder = _decoder.getList(Key.IMPORTS_FOR);
+ for (int index = 0; index < importsDecoder.length; index++) {
+ ObjectDecoder objectDecoder = importsDecoder.getObject(index);
+ Element key = objectDecoder.getElement(Key.ELEMENT);
+ List<ImportElement> imports =
+ objectDecoder.getElements(Key.IMPORTS, isOptional: true);
+
+ // Imports are mapped to [AbstractFieldElement] which are not serialized
+ // so we use getter (or setter if there is no getter) as the key.
+ Element importedElement = key;
+ if (key.isDeferredLoaderGetter) {
+ // Use as [importedElement].
+ } else if (key.isAccessor) {
+ AccessorElement accessor = key;
+ importedElement = accessor.abstractField;
+ }
+ _importsFor[importedElement] = imports;
+ }
}
}
@@ -504,9 +542,8 @@
@override
Iterable<ImportElement> getImportsFor(Element element) {
- // TODO(johnniwinther): Serialize this to support deferred access to
- // serialized entities.
- return <ImportElement>[];
+ _ensureImports();
+ return _importsFor[element] ?? const <ImportElement>[];
}
String toString() {
@@ -788,6 +825,8 @@
namedParameterTypes.add(parameter.type);
}
}
+ List<DartType> typeVariables =
+ _decoder.getTypes(Key.TYPE_VARIABLES, isOptional: true);
FunctionType type = new FunctionType(
this,
@@ -797,6 +836,7 @@
namedParameters,
namedParameterTypes);
_functionSignature = new FunctionSignatureX(
+ typeVariables: typeVariables,
requiredParameters: requiredParameters,
requiredParameterCount: requiredParameterCount,
optionalParameters: optionalParameters,
@@ -1295,9 +1335,10 @@
}
class RedirectingFactoryConstructorElementZ extends ConstructorElementZ {
- InterfaceType _effectiveTargetType;
+ DartType _effectiveTargetType;
ConstructorElement _immediateRedirectionTarget;
PrefixElement _redirectionDeferredPrefix;
+ bool _effectiveTargetIsMalformed;
RedirectingFactoryConstructorElementZ(ObjectDecoder decoder) : super(decoder);
@@ -1314,12 +1355,20 @@
if (_effectiveTarget == null) {
_effectiveTarget = this;
_effectiveTargetType = enclosingClass.thisType;
+ _effectiveTargetIsMalformed = false;
} else {
_effectiveTargetType = _decoder.getType(Key.EFFECTIVE_TARGET_TYPE);
+ _effectiveTargetIsMalformed =
+ _decoder.getBool(Key.EFFECTIVE_TARGET_IS_MALFORMED);
}
}
}
+ bool get isEffectiveTargetMalformed {
+ _ensureEffectiveTarget();
+ return _effectiveTargetIsMalformed;
+ }
+
@override
ConstructorElement get effectiveTarget {
_ensureEffectiveTarget();
@@ -1327,7 +1376,7 @@
}
@override
- InterfaceType computeEffectiveTargetType(InterfaceType newType) {
+ DartType computeEffectiveTargetType(InterfaceType newType) {
_ensureEffectiveTarget();
return _effectiveTargetType.substByContext(newType);
}
@@ -1497,6 +1546,8 @@
abstract class MemberElementMixin
implements DeserializedElementZ, MemberElement {
+ final List<FunctionElement> nestedClosures = <FunctionElement>[];
+
@override
MemberElement get memberContext => this;
@@ -1504,10 +1555,12 @@
Name get memberName => new Name(name, library);
@override
- List<FunctionElement> get nestedClosures => <FunctionElement>[];
+ bool get isInjected => _decoder.getBool(Key.IS_INJECTED);
@override
- bool get isInjected => _decoder.getBool(Key.IS_INJECTED);
+ void forgetElement() {
+ nestedClosures.clear();
+ }
}
abstract class FieldElementZ extends DeserializedElementZ
@@ -1634,6 +1687,9 @@
Element get enclosingElement => executableContext;
@override
+ Element get enclosingClass => memberContext.enclosingClass;
+
+ @override
ExecutableElement get executableContext {
if (_executableContext == null) {
_executableContext = _decoder.getElement(Key.EXECUTABLE_CONTEXT);
@@ -1712,7 +1768,9 @@
bool get isAbstract => _decoder.getBool(Key.IS_ABSTRACT);
@override
- AsyncMarker get asyncMarker => AsyncMarker.SYNC;
+ AsyncMarker get asyncMarker {
+ return _decoder.getEnum(Key.ASYNC_MARKER, AsyncMarker.values);
+ }
}
class TopLevelGetterElementZ extends GetterElementZ with LibraryMemberMixin {
@@ -1871,7 +1929,7 @@
class TypeVariableElementZ extends DeserializedElementZ
with AnalyzableElementMixin, AstElementMixinZ, TypedElementMixin
implements TypeVariableElement {
- TypeDeclarationElement _typeDeclaration;
+ GenericElement _typeDeclaration;
TypeVariableType _type;
DartType _bound;
Name _memberName;
@@ -1908,7 +1966,7 @@
int get index => _decoder.getInt(Key.INDEX);
@override
- TypeDeclarationElement get typeDeclaration {
+ GenericElement get typeDeclaration {
if (_typeDeclaration == null) {
_typeDeclaration = _decoder.getElement(Key.TYPE_DECLARATION);
}
@@ -2259,12 +2317,16 @@
bool _isDeferred;
ImportElement _deferredImport;
GetterElement _loadLibrary;
+ ListedContainer _members;
PrefixElementZ(ObjectDecoder decoder) : super(decoder);
@override
accept(ElementVisitor visitor, arg) => visitor.visitPrefixElement(this, arg);
+ @override
+ bool get isTopLevel => false;
+
void _ensureDeferred() {
if (_isDeferred == null) {
_isDeferred = _decoder.getBool(Key.IS_DEFERRED);
@@ -2295,9 +2357,23 @@
@override
ElementKind get kind => ElementKind.PREFIX;
+ void _ensureMembers() {
+ if (_members == null) {
+ _members = new ListedContainer(
+ _decoder.getElements(Key.MEMBERS, isOptional: true));
+ }
+ }
+
@override
Element lookupLocalMember(String memberName) {
- return _unsupported('lookupLocalMember');
+ _ensureMembers();
+ return _members.lookup(memberName);
+ }
+
+ @override
+ void forEachLocalMember(void f(Element member)) {
+ _ensureMembers();
+ _members.forEach(f);
}
}
diff --git a/pkg/compiler/lib/src/serialization/resolved_ast_serialization.dart b/pkg/compiler/lib/src/serialization/resolved_ast_serialization.dart
index b5d6cae..bce66ac 100644
--- a/pkg/compiler/lib/src/serialization/resolved_ast_serialization.dart
+++ b/pkg/compiler/lib/src/serialization/resolved_ast_serialization.dart
@@ -166,21 +166,25 @@
serializeLabelDefinition(labelDefinition, list.createObject());
}
}
+
if (element is FunctionElement) {
- FunctionElement function = element;
- function.functionSignature.forEachParameter((ParameterElement parameter) {
- ParameterElement parameterImpl = parameter.implementation;
- // TODO(johnniwinther): Should we support element->node mapping as well?
- getNodeDataEncoder(parameterImpl.node)
- .setElement(PARAMETER_NODE, parameter);
- if (parameter.initializer != null) {
- getNodeDataEncoder(parameterImpl.initializer)
- .setElement(PARAMETER_INITIALIZER, parameter);
- }
- });
+ serializeParameterNodes(element);
}
}
+ void serializeParameterNodes(FunctionElement function) {
+ function.functionSignature.forEachParameter((ParameterElement parameter) {
+ ParameterElement parameterImpl = parameter.implementation;
+ // TODO(johnniwinther): Should we support element->node mapping as well?
+ getNodeDataEncoder(parameterImpl.node)
+ .setElement(PARAMETER_NODE, parameter);
+ if (parameter.initializer != null) {
+ getNodeDataEncoder(parameterImpl.initializer)
+ .setElement(PARAMETER_INITIALIZER, parameter);
+ }
+ });
+ }
+
/// Serialize [target] into [encoder].
void serializeJumpTarget(JumpTarget jumpTarget, ObjectEncoder encoder) {
encoder.setElement(Key.EXECUTABLE_CONTEXT, jumpTarget.executableContext);
@@ -318,6 +322,7 @@
if (function != null && function.isFunction && function.isLocal) {
// Mark root nodes of local functions; these need their own ResolvedAst.
getNodeDataEncoder(node).setElement(Key.FUNCTION, function);
+ serializeParameterNodes(function);
}
}
}
diff --git a/pkg/compiler/lib/src/serialization/serialization.dart b/pkg/compiler/lib/src/serialization/serialization.dart
index 1b97c3d..4230ca0 100644
--- a/pkg/compiler/lib/src/serialization/serialization.dart
+++ b/pkg/compiler/lib/src/serialization/serialization.dart
@@ -692,6 +692,7 @@
/// Helper used to check that external references are serialized by
/// the right kind.
bool verifyElement(var found, var expected) {
+ if (found == null) return false;
found = found.declaration;
if (found == expected) return true;
if (found.isAbstractField && expected.isGetter) {
diff --git a/pkg/compiler/lib/src/serialization/serialization_util.dart b/pkg/compiler/lib/src/serialization/serialization_util.dart
index 1e40000..4883adb 100644
--- a/pkg/compiler/lib/src/serialization/serialization_util.dart
+++ b/pkg/compiler/lib/src/serialization/serialization_util.dart
@@ -7,7 +7,9 @@
import '../common.dart';
import '../constants/expressions.dart';
import '../dart_types.dart';
+import '../diagnostics/messages.dart';
import '../elements/elements.dart';
+import '../elements/modelx.dart' show WrappedMessage;
import '../resolution/access_semantics.dart';
import '../resolution/operators.dart';
import '../resolution/send_structure.dart';
@@ -526,3 +528,63 @@
}
return element;
}
+
+void serializeMessageArguments(
+ ObjectEncoder encoder, Key key, Map<String, dynamic> messageArguments) {
+ if (messageArguments.isNotEmpty) {
+ MapEncoder mapEncoder = encoder.createMap(Key.ARGUMENTS);
+ messageArguments.forEach((String key, var value) {
+ mapEncoder.setString(key, Message.convertToString(value));
+ });
+ }
+}
+
+Map<String, String> deserializeMessageArguments(
+ ObjectDecoder decoder, Key key) {
+ Map<String, String> arguments = <String, String>{};
+ MapDecoder mapDecoder = decoder.getMap(key, isOptional: true);
+ if (mapDecoder != null) {
+ mapDecoder.forEachKey((String key) {
+ arguments[key] = mapDecoder.getString(key);
+ });
+ }
+ return arguments;
+}
+
+void serializeSourceSpan(ObjectEncoder encoder, SourceSpan sourceSpan) {
+ encoder.setUri(Key.URI, sourceSpan.uri, sourceSpan.uri);
+ encoder.setInt(Key.OFFSET, sourceSpan.begin);
+ encoder.setInt(Key.LENGTH, sourceSpan.end - sourceSpan.begin);
+}
+
+SourceSpan deserializeSourceSpan(ObjectDecoder decoder) {
+ Uri uri = decoder.getUri(Key.URI);
+ int offset = decoder.getInt(Key.OFFSET);
+ int length = decoder.getInt(Key.LENGTH);
+ return new SourceSpan(uri, offset, offset + length);
+}
+
+void serializeWrappedMessage(
+ ObjectEncoder encoder, Key key, WrappedMessage message) {
+ ObjectEncoder object = encoder.createObject(key);
+ if (message.sourceSpan != null) {
+ serializeSourceSpan(
+ object.createObject(Key.SOURCE_SPAN), message.sourceSpan);
+ }
+ object.setEnum(Key.KIND, message.messageKind);
+ serializeMessageArguments(object, Key.ARGUMENTS, message.messageArguments);
+}
+
+WrappedMessage deserializeWrappedMessage(ObjectDecoder decoder, Key key) {
+ ObjectDecoder object = decoder.getObject(key);
+ SourceSpan sourceSpan;
+ ObjectDecoder sourceSpanDecoder =
+ object.getObject(Key.SOURCE_SPAN, isOptional: true);
+ if (sourceSpanDecoder != null) {
+ sourceSpan = deserializeSourceSpan(sourceSpanDecoder);
+ }
+ MessageKind messageKind = object.getEnum(Key.KIND, MessageKind.values);
+ Map<String, dynamic> messageArguments =
+ deserializeMessageArguments(object, Key.ARGUMENTS);
+ return new WrappedMessage(sourceSpan, messageKind, messageArguments);
+}
diff --git a/pkg/compiler/lib/src/serialization/type_serialization.dart b/pkg/compiler/lib/src/serialization/type_serialization.dart
index 24a46ae..ed94ade 100644
--- a/pkg/compiler/lib/src/serialization/type_serialization.dart
+++ b/pkg/compiler/lib/src/serialization/type_serialization.dart
@@ -5,6 +5,7 @@
library dart2js.serialization.types;
import '../dart_types.dart';
+import '../elements/elements.dart';
import 'serialization.dart';
import 'keys.dart';
@@ -24,6 +25,8 @@
void visitTypeVariableType(TypeVariableType type, ObjectEncoder encoder) {
encoder.setElement(Key.ELEMENT, type.element);
+ encoder.setBool(
+ Key.IS_METHOD_TYPE_VARIABLE_TYPE, type is MethodTypeVariableType);
}
void visitFunctionType(FunctionType type, ObjectEncoder encoder) {
@@ -76,7 +79,11 @@
decoder.getStrings(Key.NAMED_PARAMETERS, isOptional: true),
decoder.getTypes(Key.NAMED_PARAMETER_TYPES, isOptional: true));
case TypeKind.TYPE_VARIABLE:
- return new TypeVariableType(decoder.getElement(Key.ELEMENT));
+ TypeVariableElement element = decoder.getElement(Key.ELEMENT);
+ if (decoder.getBool(Key.IS_METHOD_TYPE_VARIABLE_TYPE)) {
+ return new MethodTypeVariableType(element);
+ }
+ return new TypeVariableType(element);
case TypeKind.TYPEDEF:
return new TypedefType(decoder.getElement(Key.ELEMENT),
decoder.getTypes(Key.TYPE_ARGUMENTS, isOptional: true));
diff --git a/pkg/compiler/lib/src/source_file_provider.dart b/pkg/compiler/lib/src/source_file_provider.dart
index 57bc9d3..2e2c7aa 100644
--- a/pkg/compiler/lib/src/source_file_provider.dart
+++ b/pkg/compiler/lib/src/source_file_provider.dart
@@ -168,9 +168,6 @@
@override
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;
-
if (isAborting) return;
isAborting = (kind == api.Diagnostic.CRASH);
diff --git a/pkg/compiler/lib/src/ssa/builder.dart b/pkg/compiler/lib/src/ssa/builder.dart
index 7607077..7148581 100644
--- a/pkg/compiler/lib/src/ssa/builder.dart
+++ b/pkg/compiler/lib/src/ssa/builder.dart
@@ -82,6 +82,10 @@
final String name;
final ExecutableElement executableContext;
+ // Avoid slow Object.hashCode.
+ final int hashCode = _nextHashCode = (_nextHashCode + 1).toUnsigned(30);
+ static int _nextHashCode = 0;
+
SyntheticLocal(this.name, this.executableContext);
toString() => 'SyntheticLocal($name)';
@@ -283,7 +287,7 @@
(LocalVariableElement from, BoxFieldElement to) {
// The [from] can only be a parameter for function-scopes and not
// loop scopes.
- if (from.isParameter && !element.isGenerativeConstructorBody) {
+ if (from.isRegularParameter && !element.isGenerativeConstructorBody) {
// Now that the redirection is set up, the update to the local will
// write the parameter value into the box.
// Store the captured parameter in the box. Get the current value
@@ -1746,7 +1750,8 @@
}
HGraph buildCheckedSetter(VariableElement field) {
- openFunction(field, field.node);
+ ResolvedAst resolvedAst = field.resolvedAst;
+ openFunction(field, resolvedAst.node);
HInstruction thisInstruction = localsHandler.readThis();
// Use dynamic type because the type computed by the inferrer is
// narrowed to the type annotation.
@@ -5614,14 +5619,15 @@
var filteredArguments = <HInstruction>[];
var parameterNameMap = new Map<String, js.Expression>();
params.orderedForEachParameter((ParameterElement parameter) {
- // TODO(jacobr): throw if parameter names do not match names of property
- // names in the class.
+ // TODO(jacobr): consider throwing if parameter names do not match
+ // names of properties in the class.
assert(parameter.isNamed);
HInstruction argument = arguments[i];
if (argument != null) {
filteredArguments.add(argument);
- parameterNameMap[parameter.name] =
- new js.InterpolatedExpression(positions++);
+ var jsName =
+ backend.nativeData.getUnescapedJSInteropName(parameter.name);
+ parameterNameMap[jsName] = new js.InterpolatedExpression(positions++);
}
i++;
});
diff --git a/pkg/compiler/lib/src/ssa/optimize.dart b/pkg/compiler/lib/src/ssa/optimize.dart
index e1eee00c..d89f9de 100644
--- a/pkg/compiler/lib/src/ssa/optimize.dart
+++ b/pkg/compiler/lib/src/ssa/optimize.dart
@@ -450,7 +450,33 @@
node.element = element;
}
}
+ return node;
}
+
+ // Replace method calls through fields with a closure call on the value of
+ // the field. This usually removes the demand for the call-through stub and
+ // makes the field load available to further optimization, e.g. LICM.
+
+ if (element != null &&
+ element.isField &&
+ element.name == node.selector.name) {
+ if (!backend.isNative(element) && !node.isCallOnInterceptor(compiler)) {
+ HInstruction receiver = node.getDartReceiver(compiler);
+ TypeMask type =
+ TypeMaskFactory.inferredTypeForElement(element, compiler);
+ HInstruction load = new HFieldGet(element, receiver, type);
+ node.block.addBefore(node, load);
+ Selector callSelector = new Selector.callClosureFrom(node.selector);
+ List<HInstruction> inputs = <HInstruction>[load]
+ ..addAll(node.inputs.skip(node.isInterceptedCall ? 2 : 1));
+ HInstruction closureCall =
+ new HInvokeClosure(callSelector, inputs, node.instructionType)
+ ..sourceInformation = node.sourceInformation;
+ node.block.addAfter(load, closureCall);
+ return closureCall;
+ }
+ }
+
return node;
}
diff --git a/pkg/compiler/lib/src/tree/nodes.dart b/pkg/compiler/lib/src/tree/nodes.dart
index d2e9d96..1885e0d 100644
--- a/pkg/compiler/lib/src/tree/nodes.dart
+++ b/pkg/compiler/lib/src/tree/nodes.dart
@@ -295,10 +295,10 @@
* "Token".
*/
abstract class Node extends NullTreeElementMixin implements Spannable {
- final int hashCode;
+ final int hashCode = _HASH_COUNTER = (_HASH_COUNTER + 1).toUnsigned(30);
static int _HASH_COUNTER = 0;
- Node() : hashCode = ++_HASH_COUNTER;
+ Node();
accept(Visitor visitor);
diff --git a/pkg/compiler/lib/src/tree/unparser.dart b/pkg/compiler/lib/src/tree/unparser.dart
index 37838eb..12d4141 100644
--- a/pkg/compiler/lib/src/tree/unparser.dart
+++ b/pkg/compiler/lib/src/tree/unparser.dart
@@ -260,6 +260,7 @@
write(' ');
}
unparseFunctionName(node.name);
+ visit(node.typeVariables);
visit(node.parameters);
if (node.initializers != null) {
space();
diff --git a/pkg/compiler/lib/src/typechecker.dart b/pkg/compiler/lib/src/typechecker.dart
index 69137ab..be25edf 100644
--- a/pkg/compiler/lib/src/typechecker.dart
+++ b/pkg/compiler/lib/src/typechecker.dart
@@ -683,7 +683,7 @@
assert(invariant(
node,
element.isVariable ||
- element.isParameter ||
+ element.isRegularParameter ||
element.isField ||
(element.isInitializingFormal &&
compiler.options.enableInitializingFormalAccess),
@@ -772,7 +772,7 @@
}
if (receiverElement != null &&
(receiverElement.isVariable ||
- receiverElement.isParameter ||
+ receiverElement.isRegularParameter ||
(receiverElement.isInitializingFormal &&
compiler.options.enableInitializingFormalAccess))) {
Link<TypePromotion> typePromotions = typePromotionsMap[receiverElement];
@@ -1070,7 +1070,7 @@
// foo() where foo is a method in the same class.
return createResolvedAccess(node, name, element);
} else if (element.isVariable ||
- element.isParameter ||
+ element.isRegularParameter ||
element.isField ||
element.isInitializingFormal) {
// foo() where foo is a field in the same class.
@@ -1091,7 +1091,7 @@
ElementAccess createPromotedAccess(Element element) {
if (element.isVariable ||
- element.isParameter ||
+ element.isRegularParameter ||
(element.isInitializingFormal &&
compiler.options.enableInitializingFormalAccess)) {
TypePromotion typePromotion = getKnownTypePromotion(element);
@@ -1230,7 +1230,7 @@
if (variable != null &&
(variable.isVariable ||
- variable.isParameter ||
+ variable.isRegularParameter ||
(variable.isInitializingFormal &&
compiler.options.enableInitializingFormalAccess))) {
DartType knownType = getKnownType(variable);
@@ -1742,7 +1742,7 @@
DartType visitAwait(Await node) {
DartType expressionType = analyze(node.expression);
- if (compiler.backend.supportsAsyncAwait) {
+ if (resolution.target.supportsAsyncAwait) {
return types.flatten(expressionType);
} else {
return const DynamicType();
@@ -1869,7 +1869,7 @@
visitAsyncForIn(AsyncForIn node) {
DartType elementType = computeForInElementType(node);
DartType expressionType = analyze(node.expression);
- if (compiler.backend.supportsAsyncAwait) {
+ if (resolution.target.supportsAsyncAwait) {
DartType streamOfDynamic = coreTypes.streamType();
if (!types.isAssignable(expressionType, streamOfDynamic)) {
reportMessage(node.expression, MessageKind.NOT_ASSIGNABLE,
diff --git a/pkg/js/CHANGELOG.md b/pkg/js/CHANGELOG.md
index 4ef2ebc..d9695c3 100644
--- a/pkg/js/CHANGELOG.md
+++ b/pkg/js/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 0.6.1
+* Add js_util library of utility methods to efficiently manipulate typed
+ JavaScript interop objects in cases where the member name is not known
+ statically.
+
## 0.6.0
* Version 0.6.0 is a complete rewrite of `package:js`.
diff --git a/pkg/js/lib/js_util.dart b/pkg/js/lib/js_util.dart
new file mode 100644
index 0000000..1e47e5d
--- /dev/null
+++ b/pkg/js/lib/js_util.dart
@@ -0,0 +1,8 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Allows interoperability with Javascript APIs.
+library js_util;
+
+export 'dart:js_util';
diff --git a/pkg/js/pubspec.yaml b/pkg/js/pubspec.yaml
index 7555876..03cecdb 100644
--- a/pkg/js/pubspec.yaml
+++ b/pkg/js/pubspec.yaml
@@ -1,10 +1,10 @@
name: js
-version: 0.6.0
+version: 0.6.1
authors:
- Dart Team <misc@dartlang.org>
description: Access JavaScript from Dart.
homepage: https://github.com/dart-lang/sdk/tree/master/pkg/js
environment:
- sdk: '>=1.13.0 <2.0.0'
+ sdk: '>=1.19.0-dev.0.0 <2.0.0'
dev_dependencies:
browser: '^0.10.0+2'
diff --git a/pkg/pkg.status b/pkg/pkg.status
index 81fe4d1..9e10464 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -27,15 +27,9 @@
[ $runtime == vm && $system == windows]
analysis_server/test/analysis/get_errors_test: Skip # runtime error, Issue 22180
-analysis_server/test/context_manager_test: RuntimeError # Issue 26828
analysis_server/test/integration/analysis/analysis_options_test: RuntimeError # Issue 24796
analyzer/test/generated/all_the_rest_test: Fail # Issue 21772
analyzer/test/generated/source_factory_test: RuntimeError # Issue 26828
-analyzer/test/src/context/builder_test: RuntimeError # Issue 26828
-analyzer/test/src/summary/linker_test: RuntimeError # Issue 26828
-analyzer/test/src/summary/prelinker_test: RuntimeError # Issue 26828
-analyzer/test/src/summary/summarize_elements_strong_test: RuntimeError # Issue 26828
-analyzer/test/src/summary/summarize_elements_test: RuntimeError # Issue 26828
[ $compiler == dart2js ]
analysis_server/test/integration: SkipByDesign # Analysis server integration tests don't make sense to run under dart2js, since the code under test always runs in the Dart vm as a subprocess.
diff --git a/pkg/pkgbuild.status b/pkg/pkgbuild.status
index 2f7a6bd..9d1dfee 100644
--- a/pkg/pkgbuild.status
+++ b/pkg/pkgbuild.status
@@ -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.
-third_party/pkg/scheduled_test: Fail # Issue 26585
-
[ $use_public_packages ]
pkg/compiler: SkipByDesign # js_ast is not published
diff --git a/runtime/BUILD.gn b/runtime/BUILD.gn
index e6794ec..499fc42 100644
--- a/runtime/BUILD.gn
+++ b/runtime/BUILD.gn
@@ -77,11 +77,6 @@
defines += ["DART_PRECOMPILED_RUNTIME"]
}
} else if (dart_runtime_mode == "profile") {
- if (dart_debug) {
- print("Debug and profile mode are mutually exclusive.")
- }
- assert(!dart_debug)
-
if (!dart_experimental_interpreter) {
defines += ["DART_PRECOMPILED_RUNTIME"]
}
@@ -156,7 +151,7 @@
]
}
- if (is_asan) {
+ if (defined(is_asan) && is_asan) {
ldflags = [
"-Wl,-u_sanitizer_options_link_helper",
"-fsanitize=address",
diff --git a/runtime/bin/BUILD.gn b/runtime/bin/BUILD.gn
index bff1387..610115a 100644
--- a/runtime/bin/BUILD.gn
+++ b/runtime/bin/BUILD.gn
@@ -5,7 +5,12 @@
declare_args() {
dart_io_support = false
- dart_boringssl_path = "../../third_party/boringssl"
+
+ # TODO(zra, jamesr): Remove this check once we start building boringssl for
+ # the fuchsia port.
+ if (!defined(is_fuchsia) || !is_fuchsia) {
+ dart_boringssl_path = "../../third_party/boringssl"
+ }
}
@@ -133,6 +138,7 @@
set_sources_assignment_filter(["*_test.cc", "*_test.h"])
sources = [
"log_android.cc",
+ "log_fuchsia.cc",
"log_linux.cc",
"log_macos.cc",
"log_win.cc",
@@ -207,6 +213,13 @@
]
}
+io_impl_sources_gypi =
+ exec_script("../../tools/gypi_to_gn.py",
+ [ rebase_path("io_impl_sources.gypi") ],
+ "scope",
+ [ "io_impl_sources.gypi" ])
+
+if (!defined(is_fuchsia) || (current_toolchain == host_toolchain)) {
executable("gen_snapshot") {
configs += ["..:dart_config",
@@ -244,24 +257,6 @@
]
}
-
-source_set("libdart_embedder_noio") {
- configs += ["..:dart_config",
- "..:dart_product_config",
- "..:dart_precompiled_runtime_config"]
- deps = [
- "..:libdart",
- "../vm:libdart_platform",
- ]
-}
-
-io_impl_sources_gypi =
- exec_script("../../tools/gypi_to_gn.py",
- [ rebase_path("io_impl_sources.gypi") ],
- "scope",
- [ "io_impl_sources.gypi" ])
-
-
# A source set for the implementation of 'dart:io' library
# (without secure sockets) suitable for linking with gen_snapshot.
source_set("gen_snapshot_dart_io") {
@@ -303,6 +298,19 @@
]
}
+} # current_toolchain == host_toolchain
+
+source_set("libdart_embedder_noio") {
+ configs += ["..:dart_config",
+ "..:dart_product_config",
+ "..:dart_precompiled_runtime_config"]
+ deps = [
+ "..:libdart",
+ "../vm:libdart_platform",
+ ]
+}
+
+
# A source set for the implementation of 'dart:io' library
# (without secure sockets).
source_set("embedded_dart_io") {
@@ -329,6 +337,10 @@
libs = [
"Security.framework",
]
+ } else if (defined(is_fuchsia) && is_fuchsia) {
+ defines = [
+ "DART_IO_SECURE_SOCKET_DISABLED"
+ ]
} else {
deps = [
rebase_path(dart_boringssl_path, "."),
@@ -349,9 +361,147 @@
"log_win.cc",
"log.h",
]
+ if (is_linux) {
+ sources += [ "../../third_party/root_certificates/root_certificates.cc"]
+ }
include_dirs = [
"..",
"//third_party"
]
}
+
+
+action("generate_snapshot_bin") {
+ deps = [
+ "../bin:gen_snapshot($host_toolchain)",
+ ]
+
+ vm_isolate_snapshot = "$target_gen_dir/vm_isolate_snapshot.bin"
+ isolate_snapshot = "$target_gen_dir/isolate_snapshot.bin"
+ gen_snapshot_stamp_file = "$target_gen_dir/gen_snapshot.stamp"
+ outputs = [
+ vm_isolate_snapshot,
+ isolate_snapshot,
+ gen_snapshot_stamp_file,
+ ]
+
+ gen_snapshot_dir =
+ get_label_info("../bin:gen_snapshot($host_toolchain)", "root_out_dir")
+
+ script = rebase_path("../tools/create_snapshot_bin.py")
+ args = [
+ "--executable",
+ rebase_path("$gen_snapshot_dir/gen_snapshot"),
+ "--vm_output_bin",
+ rebase_path(vm_isolate_snapshot, root_build_dir),
+ "--output_bin",
+ rebase_path(isolate_snapshot, root_build_dir),
+ "--target_os",
+ current_os,
+ "--timestamp_file",
+ rebase_path(gen_snapshot_stamp_file, root_build_dir),
+ ]
+}
+
+
+action("generate_snapshot_file") {
+ deps = [
+ ":generate_snapshot_bin",
+ ]
+
+ snapshot_in_cc_file = "snapshot_in.cc"
+ inputs = [
+ "../tools/create_snapshot_file.py",
+ snapshot_in_cc_file,
+ "$target_gen_dir/vm_isolate_snapshot.bin",
+ "$target_gen_dir/isolate_snapshot.bin",
+ ]
+ output = "$root_gen_dir/dart_snapshot.cc"
+ outputs = [
+ output,
+ ]
+
+ script = "../tools/create_snapshot_file.py"
+ args = [
+ "--vm_input_bin",
+ rebase_path("$target_gen_dir/vm_isolate_snapshot.bin"),
+ "--input_bin",
+ rebase_path("$target_gen_dir/isolate_snapshot.bin"),
+ "--input_cc",
+ rebase_path(snapshot_in_cc_file),
+ "--output",
+ rebase_path(output),
+ ]
+}
+
+
+source_set("dart_snapshot_cc") {
+ sources = [
+ "$root_gen_dir/dart_snapshot.cc",
+ ]
+
+ deps = [
+ ":generate_snapshot_file",
+ ]
+}
+
+if (defined(is_fuchsia) && is_fuchsia) {
+ executable("fuchsia_test") {
+ configs += ["..:dart_config",
+ "..:dart_product_config",
+ "..:dart_precompiled_runtime_config"]
+ sources = [
+ "fuchsia_test.cc",
+ "log_fuchsia.cc",
+ ]
+
+ include_dirs = [
+ "..",
+ "../include"
+ ]
+
+ deps = [
+ ":dart_snapshot_cc",
+ ":libdart_embedder_noio",
+ ]
+ }
+
+ copy("hello_fuchsia") {
+ sources = [ "../tests/vm/dart/hello_fuchsia_test.dart" ]
+ outputs = [ "$root_out_dir/hello_fuchsia.dart" ]
+ }
+
+ executable("dart_no_observatory") {
+ configs += ["..:dart_config",
+ "..:dart_product_config",
+ "..:dart_precompiled_runtime_config",]
+ deps = [
+ ":hello_fuchsia",
+ ":gen_resources_cc",
+ ":embedded_dart_io",
+ ":libdart_builtin",
+ "../vm:libdart_platform",
+ "..:libdart",
+ ":dart_snapshot_cc",
+ "//third_party/zlib",
+ ]
+
+ defines = [
+ "NO_OBSERVATORY",
+ ]
+
+ sources = [
+ "main.cc",
+ "observatory_assets_empty.cc",
+ "vmservice_impl.cc",
+ "vmservice_impl.h",
+ "$target_gen_dir/resources_gen.cc",
+ ]
+
+ include_dirs = [
+ "..",
+ "//third_party",
+ ]
+ }
+} # defined(is_fuchsia) && is_fuchsia
diff --git a/runtime/bin/bin.gypi b/runtime/bin/bin.gypi
index 2d04720..43b5915 100644
--- a/runtime/bin/bin.gypi
+++ b/runtime/bin/bin.gypi
@@ -11,6 +11,7 @@
'html_cc_file': '<(gen_source_dir)/html_gen.cc',
'html_common_cc_file': '<(gen_source_dir)/html_common_gen.cc',
'js_cc_file': '<(gen_source_dir)/js_gen.cc',
+ 'js_util_cc_file': '<(gen_source_dir)/js_util_gen.cc',
'blink_cc_file': '<(gen_source_dir)/blink_gen.cc',
'indexeddb_cc_file': '<(gen_source_dir)/indexeddb_gen.cc',
'cached_patches_cc_file': '<(gen_source_dir)/cached_patches_gen.cc',
@@ -234,6 +235,38 @@
]
},
{
+ 'target_name': 'generate_js_util_cc_file',
+ 'type': 'none',
+ 'toolsets':['host'],
+ 'sources': [
+ '../../sdk/lib/js_util/dartium/js_util_dartium.dart',
+ ],
+ 'actions': [
+ {
+ 'action_name': 'generate_js_util_cc',
+ 'inputs': [
+ '../tools/gen_library_src_paths.py',
+ '<(builtin_in_cc_file)',
+ '<@(_sources)',
+ ],
+ 'outputs': [
+ '<(js_util_cc_file)',
+ ],
+ 'action': [
+ 'python',
+ 'tools/gen_library_src_paths.py',
+ '--output', '<(js_util_cc_file)',
+ '--input_cc', '<(builtin_in_cc_file)',
+ '--include', 'bin/builtin.h',
+ '--var_name', 'dart::bin::Builtin::js_util_source_paths_',
+ '--library_name', 'dart:js_util',
+ '<@(_sources)',
+ ],
+ 'message': 'Generating ''<(js_util_cc_file)'' file.'
+ },
+ ]
+ },
+ {
'target_name': 'generate_blink_cc_file',
'type': 'none',
'toolsets':['host'],
@@ -500,6 +533,7 @@
'generate_html_cc_file#host',
'generate_html_common_cc_file#host',
'generate_js_cc_file#host',
+ 'generate_js_util_cc_file#host',
'generate_blink_cc_file#host',
'generate_indexeddb_cc_file#host',
'generate_cached_patches_cc_file#host',
@@ -682,6 +716,10 @@
'defines': [
'DART_IO_SECURE_SOCKET_DISABLED'
],
+ }, {
+ 'sources': [
+ '../../third_party/root_certificates/root_certificates.cc',
+ ],
}],
['OS=="win"', {
'sources/' : [
@@ -758,6 +796,10 @@
'defines': [
'DART_IO_SECURE_SOCKET_DISABLED'
],
+ }, {
+ 'sources': [
+ '../../third_party/root_certificates/root_certificates.cc',
+ ],
}],
['OS != "mac" and dart_io_support==1 and dart_io_secure_socket==1', {
'dependencies': [
@@ -818,6 +860,10 @@
'defines': [
'DART_IO_SECURE_SOCKET_DISABLED',
],
+ }, {
+ 'sources': [
+ '../../third_party/root_certificates/root_certificates.cc',
+ ],
}],
['OS != "mac" and dart_io_support==1 and dart_io_secure_socket==1', {
'dependencies': [
@@ -1058,20 +1104,6 @@
]
},
{
- 'target_name': 'fuchsia_test',
- 'type': 'executable',
- 'dependencies': [
- 'libdart_nosnapshot',
- ],
- 'include_dirs': [
- '..',
- '../include',
- ],
- 'sources': [
- 'fuchsia_test.cc',
- ],
- },
- {
# dart binary with a snapshot of corelibs built in.
'target_name': 'dart',
'type': 'executable',
@@ -1264,6 +1296,7 @@
'<(html_cc_file)',
'<(html_common_cc_file)',
'<(js_cc_file)',
+ '<(js_util_cc_file)',
'<(blink_cc_file)',
'<(indexeddb_cc_file)',
'<(cached_patches_cc_file)',
diff --git a/runtime/bin/builtin.cc b/runtime/bin/builtin.cc
index c26a762..04fb060 100644
--- a/runtime/bin/builtin.cc
+++ b/runtime/bin/builtin.cc
@@ -24,6 +24,7 @@
{ "dart:html", html_source_paths_, NULL, NULL, true },
{ "dart:html_common", html_common_source_paths_, NULL, NULL, true},
{ "dart:js", js_source_paths_, NULL, NULL, true},
+ { "dart:js_util", js_util_source_paths_, NULL, NULL, true},
{ "dart:_blink", blink_source_paths_, NULL, NULL, true },
{ "dart:indexed_db", indexeddb_source_paths_, NULL, NULL, true },
{ "cached_patches.dart", cached_patches_source_paths_, NULL, NULL, true },
diff --git a/runtime/bin/builtin.h b/runtime/bin/builtin.h
index 5029cf1..d90223a 100644
--- a/runtime/bin/builtin.h
+++ b/runtime/bin/builtin.h
@@ -74,6 +74,7 @@
static const char* html_source_paths_[];
static const char* html_common_source_paths_[];
static const char* js_source_paths_[];
+ static const char* js_util_source_paths_[];
static const char* blink_source_paths_[];
static const char* indexeddb_source_paths_[];
static const char* cached_patches_source_paths_[];
diff --git a/runtime/bin/builtin_impl_sources.gypi b/runtime/bin/builtin_impl_sources.gypi
index f775ffc..2e6ae0c 100644
--- a/runtime/bin/builtin_impl_sources.gypi
+++ b/runtime/bin/builtin_impl_sources.gypi
@@ -10,6 +10,7 @@
'crypto.cc',
'crypto.h',
'crypto_android.cc',
+ 'crypto_fuchsia.cc',
'crypto_linux.cc',
'crypto_macos.cc',
'crypto_win.cc',
@@ -19,6 +20,7 @@
'directory.cc',
'directory.h',
'directory_android.cc',
+ 'directory_fuchsia.cc',
'directory_linux.cc',
'directory_macos.cc',
'directory_unsupported.cc',
@@ -27,6 +29,7 @@
'extensions.h',
'extensions.cc',
'extensions_android.cc',
+ 'extensions_fuchsia.cc',
'extensions_linux.cc',
'extensions_macos.cc',
'extensions_win.cc',
@@ -37,6 +40,7 @@
'file.cc',
'file.h',
'file_android.cc',
+ 'file_fuchsia.cc',
'file_linux.cc',
'file_macos.cc',
'file_support.cc',
@@ -53,6 +57,8 @@
'thread.h',
'thread_android.cc',
'thread_android.h',
+ 'thread_fuchsia.cc',
+ 'thread_fuchsia.h',
'thread_linux.cc',
'thread_linux.h',
'thread_macos.cc',
@@ -61,6 +67,7 @@
'thread_win.h',
'utils.h',
'utils_android.cc',
+ 'utils_fuchsia.cc',
'utils_linux.cc',
'utils_macos.cc',
'utils_win.cc',
diff --git a/runtime/bin/crypto_fuchsia.cc b/runtime/bin/crypto_fuchsia.cc
new file mode 100644
index 0000000..9423f7c
--- /dev/null
+++ b/runtime/bin/crypto_fuchsia.cc
@@ -0,0 +1,31 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "platform/globals.h"
+#if defined(TARGET_OS_FUCHSIA)
+
+#include "bin/crypto.h"
+
+namespace dart {
+namespace bin {
+
+bool Crypto::GetRandomBytes(intptr_t count, uint8_t* buffer) {
+ uint32_t num;
+ intptr_t read = 0;
+ while (read < count) {
+ if (rand_r(&num) != 0) {
+ return false;
+ }
+ for (int i = 0; i < 4 && read < count; i++) {
+ buffer[read] = num >> (i * 8);
+ read++;
+ }
+ }
+ return true;
+}
+
+} // namespace bin
+} // namespace dart
+
+#endif // defined(TARGET_OS_FUCHSIA)
diff --git a/runtime/bin/directory.cc b/runtime/bin/directory.cc
index a9b2331..ccf5918 100644
--- a/runtime/bin/directory.cc
+++ b/runtime/bin/directory.cc
@@ -14,6 +14,8 @@
namespace dart {
namespace bin {
+char* Directory::system_temp_path_override_ = NULL;
+
void FUNCTION_NAME(Directory_Current)(Dart_NativeArguments args) {
const char* current = Directory::Current();
if (current != NULL) {
@@ -187,6 +189,17 @@
}
+void Directory::SetSystemTemp(const char* path) {
+ if (system_temp_path_override_ != NULL) {
+ free(system_temp_path_override_);
+ system_temp_path_override_ = NULL;
+ }
+ if (path != NULL) {
+ system_temp_path_override_ = strdup(path);
+ }
+}
+
+
CObject* Directory::CreateRequest(const CObjectArray& request) {
if ((request.Length() == 1) && request[0]->IsString()) {
CObjectString path(request[0]);
diff --git a/runtime/bin/directory.h b/runtime/bin/directory.h
index f455710..ee1f389 100644
--- a/runtime/bin/directory.h
+++ b/runtime/bin/directory.h
@@ -274,6 +274,8 @@
static const char* Current();
static const char* SystemTemp();
static const char* CreateTemp(const char* path);
+ // Set the system temporary directory.
+ static void SetSystemTemp(const char* path);
static bool SetCurrent(const char* path);
static bool Create(const char* path);
static bool Delete(const char* path, bool recursive);
@@ -290,6 +292,7 @@
static CObject* RenameRequest(const CObjectArray& request);
private:
+ static char* system_temp_path_override_;
DISALLOW_ALLOCATION();
DISALLOW_IMPLICIT_CONSTRUCTORS(Directory);
};
diff --git a/runtime/bin/directory_android.cc b/runtime/bin/directory_android.cc
index 95f42da..75ca974 100644
--- a/runtime/bin/directory_android.cc
+++ b/runtime/bin/directory_android.cc
@@ -403,6 +403,9 @@
const char* Directory::SystemTemp() {
+ if (Directory::system_temp_path_override_ != NULL) {
+ return DartUtils::ScopedCopyCString(Directory::system_temp_path_override_);
+ }
// Android does not have a /tmp directory. A partial substitute,
// suitable for bring-up work and tests, is to create a tmp
// directory in /data/local/tmp.
diff --git a/runtime/bin/directory_fuchsia.cc b/runtime/bin/directory_fuchsia.cc
new file mode 100644
index 0000000..a1387b0
--- /dev/null
+++ b/runtime/bin/directory_fuchsia.cc
@@ -0,0 +1,154 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "platform/globals.h"
+#if defined(TARGET_OS_FUCHSIA)
+
+#include "bin/directory.h"
+
+#include <errno.h> // NOLINT
+#include <stdlib.h> // NOLINT
+#include <string.h> // NOLINT
+#include <unistd.h> // NOLINT
+
+namespace dart {
+namespace bin {
+
+PathBuffer::PathBuffer() : length_(0) {
+ data_ = calloc(PATH_MAX + 1, sizeof(char)); // NOLINT
+}
+
+
+PathBuffer::~PathBuffer() {
+ free(data_);
+}
+
+
+bool PathBuffer::AddW(const wchar_t* name) {
+ UNREACHABLE();
+ return false;
+}
+
+
+char* PathBuffer::AsString() const {
+ return reinterpret_cast<char*>(data_);
+}
+
+
+wchar_t* PathBuffer::AsStringW() const {
+ UNREACHABLE();
+ return NULL;
+}
+
+
+const char* PathBuffer::AsScopedString() const {
+ return DartUtils::ScopedCopyCString(AsString());
+}
+
+
+bool PathBuffer::Add(const char* name) {
+ const intptr_t name_length = strnlen(name, PATH_MAX + 1);
+ if (name_length == 0) {
+ errno = EINVAL;
+ return false;
+ }
+ char* data = AsString();
+ int written = snprintf(data + length_,
+ PATH_MAX - length_,
+ "%s",
+ name);
+ data[PATH_MAX] = '\0';
+ if ((written <= (PATH_MAX - length_)) &&
+ (written > 0) &&
+ (static_cast<size_t>(written) == strnlen(name, PATH_MAX + 1))) {
+ length_ += written;
+ return true;
+ } else {
+ errno = ENAMETOOLONG;
+ return false;
+ }
+}
+
+
+void PathBuffer::Reset(intptr_t new_length) {
+ length_ = new_length;
+ AsString()[length_] = '\0';
+}
+
+
+ListType DirectoryListingEntry::Next(DirectoryListing* listing) {
+ UNIMPLEMENTED();
+ return kListError;
+}
+
+
+DirectoryListingEntry::~DirectoryListingEntry() {
+ UNIMPLEMENTED();
+}
+
+
+void DirectoryListingEntry::ResetLink() {
+ UNIMPLEMENTED();
+}
+
+
+Directory::ExistsResult Directory::Exists(const char* dir_name) {
+ UNIMPLEMENTED();
+ return UNKNOWN;
+}
+
+
+char* Directory::CurrentNoScope() {
+ return getcwd(NULL, 0);
+}
+
+
+const char* Directory::Current() {
+ char buffer[PATH_MAX];
+ if (getcwd(buffer, PATH_MAX) == NULL) {
+ return NULL;
+ }
+ return DartUtils::ScopedCopyCString(buffer);
+}
+
+
+bool Directory::SetCurrent(const char* path) {
+ UNIMPLEMENTED();
+ return false;
+}
+
+
+bool Directory::Create(const char* dir_name) {
+ UNIMPLEMENTED();
+ return false;
+}
+
+
+const char* Directory::SystemTemp() {
+ UNIMPLEMENTED();
+ return NULL;
+}
+
+
+const char* Directory::CreateTemp(const char* prefix) {
+ UNIMPLEMENTED();
+ return NULL;
+}
+
+
+bool Directory::Delete(const char* dir_name, bool recursive) {
+ UNIMPLEMENTED();
+ return false;
+}
+
+
+bool Directory::Rename(const char* path, const char* new_path) {
+ UNIMPLEMENTED();
+ return false;
+}
+
+} // namespace bin
+} // namespace dart
+
+#endif // defined(TARGET_OS_LINUX)
diff --git a/runtime/bin/embedded_dart_io.cc b/runtime/bin/embedded_dart_io.cc
index 9e38f02..8b1b7fb 100644
--- a/runtime/bin/embedded_dart_io.cc
+++ b/runtime/bin/embedded_dart_io.cc
@@ -4,6 +4,7 @@
#include "bin/embedded_dart_io.h"
+#include "bin/directory.h"
#include "bin/eventhandler.h"
#include "bin/utils.h"
#include "bin/thread.h"
@@ -18,5 +19,10 @@
EventHandler::Start();
}
+
+void SetSystemTempDirectory(const char* system_temp) {
+ Directory::SetSystemTemp(system_temp);
+}
+
} // namespace bin
} // namespace dart
diff --git a/runtime/bin/embedded_dart_io.h b/runtime/bin/embedded_dart_io.h
index a5b069d..56dbba8 100644
--- a/runtime/bin/embedded_dart_io.h
+++ b/runtime/bin/embedded_dart_io.h
@@ -11,6 +11,10 @@
// Bootstraps 'dart:io'.
void BootstrapDartIo();
+// Lets dart:io know where the system temporary directory is located.
+// Currently only wired up on Android.
+void SetSystemTempDirectory(const char* system_temp);
+
// Tells the system whether to capture Stdout events.
void SetCaptureStdout(bool value);
diff --git a/runtime/bin/eventhandler.h b/runtime/bin/eventhandler.h
index 34f6c65..ab5b590 100644
--- a/runtime/bin/eventhandler.h
+++ b/runtime/bin/eventhandler.h
@@ -605,6 +605,8 @@
// The event handler delegation class is OS specific.
#if defined(TARGET_OS_ANDROID)
#include "bin/eventhandler_android.h"
+#elif defined(TARGET_OS_FUCHSIA)
+#include "bin/eventhandler_fuchsia.h"
#elif defined(TARGET_OS_LINUX)
#include "bin/eventhandler_linux.h"
#elif defined(TARGET_OS_MACOS)
diff --git a/runtime/bin/eventhandler_fuchsia.cc b/runtime/bin/eventhandler_fuchsia.cc
new file mode 100644
index 0000000..69c2190
--- /dev/null
+++ b/runtime/bin/eventhandler_fuchsia.cc
@@ -0,0 +1,172 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#if !defined(DART_IO_DISABLED)
+
+#include "platform/globals.h"
+#if defined(TARGET_OS_FUCHSIA)
+
+#include "bin/eventhandler.h"
+#include "bin/eventhandler_fuchsia.h"
+
+#include <magenta/syscalls.h>
+#include <runtime/status.h>
+
+#include "bin/thread.h"
+#include "bin/utils.h"
+
+namespace dart {
+namespace bin {
+
+EventHandlerImplementation::EventHandlerImplementation() {
+ mx_status_t status = mx_message_pipe_create(interrupt_handles_, 0);
+ if (status != NO_ERROR) {
+ FATAL1("mx_message_pipe_create failed: %s\n", mx_strstatus(status));
+ }
+}
+
+
+EventHandlerImplementation::~EventHandlerImplementation() {
+ mx_status_t status = mx_handle_close(interrupt_handles_[0]);
+ if (status != NO_ERROR) {
+ FATAL1("mx_handle_close failed: %s\n", mx_strstatus(status));
+ }
+ status = mx_handle_close(interrupt_handles_[1]);
+ if (status != NO_ERROR) {
+ FATAL1("mx_handle_close failed: %s\n", mx_strstatus(status));
+ }
+}
+
+
+void EventHandlerImplementation::WakeupHandler(intptr_t id,
+ Dart_Port dart_port,
+ int64_t data) {
+ InterruptMessage msg;
+ msg.id = id;
+ msg.dart_port = dart_port;
+ msg.data = data;
+
+ mx_status_t status =
+ mx_message_write(interrupt_handles_[1], &msg, sizeof(msg), NULL, 0, 0);
+ if (status != NO_ERROR) {
+ FATAL1("mx_message_write failed: %s\n", mx_strstatus(status));
+ }
+}
+
+
+void EventHandlerImplementation::HandleInterruptFd() {
+ InterruptMessage msg;
+ uint32_t bytes = kInterruptMessageSize;
+ mx_status_t status;
+ while (true) {
+ status = mx_message_read(
+ interrupt_handles_[0], &msg, &bytes, NULL, NULL, 0);
+ if (status != NO_ERROR) {
+ break;
+ }
+ ASSERT(bytes == kInterruptMessageSize);
+ if (msg.id == kTimerId) {
+ timeout_queue_.UpdateTimeout(msg.dart_port, msg.data);
+ } else if (msg.id == kShutdownId) {
+ shutdown_ = true;
+ } else {
+ UNIMPLEMENTED();
+ }
+ }
+ // status == ERR_BAD_STATE when we try to read and there are no messages
+ // available, so it is an error if we get here and status != ERR_BAD_STATE.
+ if (status != ERR_BAD_STATE) {
+ FATAL1("mx_message_read failed: %s\n", mx_strstatus(status));
+ }
+}
+
+
+void EventHandlerImplementation::HandleEvents() {
+ // TODO(zra): Handle events from other handles. At the moment we are only
+ // interrupted when there is a message on interrupt_handles_[0].
+ HandleInterruptFd();
+}
+
+
+int64_t EventHandlerImplementation::GetTimeout() const {
+ if (!timeout_queue_.HasTimeout()) {
+ return kInfinityTimeout;
+ }
+ int64_t millis = timeout_queue_.CurrentTimeout() -
+ TimerUtils::GetCurrentMonotonicMillis();
+ return (millis < 0) ? 0 : millis;
+}
+
+
+void EventHandlerImplementation::HandleTimeout() {
+ if (timeout_queue_.HasTimeout()) {
+ int64_t millis = timeout_queue_.CurrentTimeout() -
+ TimerUtils::GetCurrentMonotonicMillis();
+ if (millis <= 0) {
+ DartUtils::PostNull(timeout_queue_.CurrentPort());
+ timeout_queue_.RemoveCurrent();
+ }
+ }
+}
+
+
+void EventHandlerImplementation::Poll(uword args) {
+ EventHandler* handler = reinterpret_cast<EventHandler*>(args);
+ EventHandlerImplementation* handler_impl = &handler->delegate_;
+ ASSERT(handler_impl != NULL);
+
+ while (!handler_impl->shutdown_) {
+ int64_t millis = handler_impl->GetTimeout();
+ ASSERT((millis == kInfinityTimeout) || (millis >= 0));
+
+ mx_time_t timeout =
+ millis * kMicrosecondsPerMillisecond * kNanosecondsPerMicrosecond;
+ mx_signals_state_t signals_state;
+ mx_status_t status = mx_handle_wait_one(
+ handler_impl->interrupt_handles_[0],
+ MX_SIGNAL_READABLE | MX_SIGNAL_PEER_CLOSED,
+ timeout,
+ &signals_state);
+ if ((status != NO_ERROR) && (status != ERR_TIMED_OUT)) {
+ FATAL1("mx_handle_wait_one failed: %s\n", mx_strstatus(status));
+ } else {
+ handler_impl->HandleTimeout();
+ if ((signals_state.satisfied & MX_SIGNAL_READABLE) != 0) {
+ handler_impl->HandleEvents();
+ }
+ if ((signals_state.satisfied & MX_SIGNAL_PEER_CLOSED) != 0) {
+ FATAL("EventHandlerImplementation::Poll: Unexpected peer closed\n");
+ }
+ }
+ }
+ handler->NotifyShutdownDone();
+}
+
+
+void EventHandlerImplementation::Start(EventHandler* handler) {
+ int result = Thread::Start(&EventHandlerImplementation::Poll,
+ reinterpret_cast<uword>(handler));
+ if (result != 0) {
+ FATAL1("Failed to start event handler thread %d", result);
+ }
+}
+
+
+void EventHandlerImplementation::Shutdown() {
+ SendData(kShutdownId, 0, 0);
+}
+
+
+void EventHandlerImplementation::SendData(intptr_t id,
+ Dart_Port dart_port,
+ int64_t data) {
+ WakeupHandler(id, dart_port, data);
+}
+
+} // namespace bin
+} // namespace dart
+
+#endif // defined(TARGET_OS_FUCHSIA)
+
+#endif // !defined(DART_IO_DISABLED)
diff --git a/runtime/bin/eventhandler_fuchsia.h b/runtime/bin/eventhandler_fuchsia.h
new file mode 100644
index 0000000..0130992
--- /dev/null
+++ b/runtime/bin/eventhandler_fuchsia.h
@@ -0,0 +1,44 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#ifndef BIN_EVENTHANDLER_FUCHSIA_H_
+#define BIN_EVENTHANDLER_FUCHSIA_H_
+
+#if !defined(BIN_EVENTHANDLER_H_)
+#error Do not include eventhandler_fuchsia.h directly; use eventhandler.h instead.
+#endif
+
+#include <magenta/syscalls.h>
+
+namespace dart {
+namespace bin {
+
+class EventHandlerImplementation {
+ public:
+ EventHandlerImplementation();
+ ~EventHandlerImplementation();
+
+ void SendData(intptr_t id, Dart_Port dart_port, int64_t data);
+ void Start(EventHandler* handler);
+ void Shutdown();
+
+ private:
+ int64_t GetTimeout() const;
+ void HandleEvents();
+ void HandleTimeout();
+ void WakeupHandler(intptr_t id, Dart_Port dart_port, int64_t data);
+ void HandleInterruptFd();
+ static void Poll(uword args);
+
+ TimeoutQueue timeout_queue_;
+ bool shutdown_;
+ mx_handle_t interrupt_handles_[2];
+
+ DISALLOW_COPY_AND_ASSIGN(EventHandlerImplementation);
+};
+
+} // namespace bin
+} // namespace dart
+
+#endif // BIN_EVENTHANDLER_FUCHSIA_H_
diff --git a/runtime/bin/extensions_fuchsia.cc b/runtime/bin/extensions_fuchsia.cc
new file mode 100644
index 0000000..d474672
--- /dev/null
+++ b/runtime/bin/extensions_fuchsia.cc
@@ -0,0 +1,38 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "platform/globals.h"
+#if defined(TARGET_OS_FUCHSIA)
+
+#include "bin/extensions.h"
+#include <dlfcn.h> // NOLINT
+
+namespace dart {
+namespace bin {
+
+const char* kPrecompiledLibraryName = "libprecompiled.so";
+const char* kPrecompiledInstructionsSymbolName = "_kInstructionsSnapshot";
+const char* kPrecompiledDataSymbolName = "_kDataSnapshot";
+
+void* Extensions::LoadExtensionLibrary(const char* library_file) {
+ return dlopen(library_file, RTLD_LAZY);
+}
+
+void* Extensions::ResolveSymbol(void* lib_handle, const char* symbol) {
+ dlerror();
+ return dlsym(lib_handle, symbol);
+}
+
+Dart_Handle Extensions::GetError() {
+ const char* err_str = dlerror();
+ if (err_str != NULL) {
+ return Dart_NewApiError(err_str);
+ }
+ return Dart_Null();
+}
+
+} // namespace bin
+} // namespace dart
+
+#endif // defined(TARGET_OS_FUCHSIA)
diff --git a/runtime/bin/file_fuchsia.cc b/runtime/bin/file_fuchsia.cc
new file mode 100644
index 0000000..fdc2623
--- /dev/null
+++ b/runtime/bin/file_fuchsia.cc
@@ -0,0 +1,452 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "platform/globals.h"
+#if defined(TARGET_OS_FUCHSIA)
+
+#include "bin/file.h"
+
+#include <errno.h> // NOLINT
+#include <fcntl.h> // NOLINT
+#include <libgen.h> // NOLINT
+#include <sys/mman.h> // NOLINT
+#include <sys/stat.h> // NOLINT
+#include <sys/types.h> // NOLINT
+#include <unistd.h> // NOLINT
+
+#include "bin/builtin.h"
+#include "bin/log.h"
+#include "platform/signal_blocker.h"
+#include "platform/utils.h"
+
+namespace dart {
+namespace bin {
+
+class FileHandle {
+ public:
+ explicit FileHandle(int fd) : fd_(fd) { }
+ ~FileHandle() { }
+ int fd() const { return fd_; }
+ void set_fd(int fd) { fd_ = fd; }
+
+ private:
+ int fd_;
+
+ DISALLOW_COPY_AND_ASSIGN(FileHandle);
+};
+
+
+File::~File() {
+ if (!IsClosed()) {
+ Close();
+ }
+ delete handle_;
+}
+
+
+void File::Close() {
+ ASSERT(handle_->fd() >= 0);
+ if (handle_->fd() == STDOUT_FILENO) {
+ // If stdout, redirect fd to /dev/null.
+ int null_fd = NO_RETRY_EXPECTED(open("/dev/null", O_WRONLY));
+ ASSERT(null_fd >= 0);
+ VOID_NO_RETRY_EXPECTED(dup2(null_fd, handle_->fd()));
+ VOID_NO_RETRY_EXPECTED(close(null_fd));
+ } else {
+ int err = NO_RETRY_EXPECTED(close(handle_->fd()));
+ if (err != 0) {
+ const int kBufferSize = 1024;
+ char error_buf[kBufferSize];
+ Log::PrintErr("%s\n", Utils::StrError(errno, error_buf, kBufferSize));
+ }
+ }
+ handle_->set_fd(kClosedFd);
+}
+
+
+intptr_t File::GetFD() {
+ return handle_->fd();
+}
+
+
+bool File::IsClosed() {
+ return handle_->fd() == kClosedFd;
+}
+
+
+void* File::MapExecutable(intptr_t* len) {
+ UNIMPLEMENTED();
+ return NULL;
+}
+
+
+int64_t File::Read(void* buffer, int64_t num_bytes) {
+ ASSERT(handle_->fd() >= 0);
+ return NO_RETRY_EXPECTED(read(handle_->fd(), buffer, num_bytes));
+}
+
+
+int64_t File::Write(const void* buffer, int64_t num_bytes) {
+ ASSERT(handle_->fd() >= 0);
+ return NO_RETRY_EXPECTED(write(handle_->fd(), buffer, num_bytes));
+}
+
+
+int64_t File::Position() {
+ ASSERT(handle_->fd() >= 0);
+ return NO_RETRY_EXPECTED(lseek(handle_->fd(), 0, SEEK_CUR));
+}
+
+
+bool File::SetPosition(int64_t position) {
+ ASSERT(handle_->fd() >= 0);
+ return NO_RETRY_EXPECTED(lseek(handle_->fd(), position, SEEK_SET)) >= 0;
+}
+
+
+bool File::Truncate(int64_t length) {
+ ASSERT(handle_->fd() >= 0);
+ return NO_RETRY_EXPECTED(ftruncate(handle_->fd(), length) != -1);
+}
+
+
+bool File::Flush() {
+ ASSERT(handle_->fd() >= 0);
+ return NO_RETRY_EXPECTED(fsync(handle_->fd())) != -1;
+}
+
+
+bool File::Lock(File::LockType lock, int64_t start, int64_t end) {
+ ASSERT(handle_->fd() >= 0);
+ ASSERT((end == -1) || (end > start));
+ struct flock fl;
+ switch (lock) {
+ case File::kLockUnlock:
+ fl.l_type = F_UNLCK;
+ break;
+ case File::kLockShared:
+ case File::kLockBlockingShared:
+ fl.l_type = F_RDLCK;
+ break;
+ case File::kLockExclusive:
+ case File::kLockBlockingExclusive:
+ fl.l_type = F_WRLCK;
+ break;
+ default:
+ return false;
+ }
+ fl.l_whence = SEEK_SET;
+ fl.l_start = start;
+ fl.l_len = end == -1 ? 0 : end - start;
+ int cmd = F_SETLK;
+ if ((lock == File::kLockBlockingShared) ||
+ (lock == File::kLockBlockingExclusive)) {
+ cmd = F_SETLKW;
+ }
+ return NO_RETRY_EXPECTED(fcntl(handle_->fd(), cmd, &fl)) != -1;
+}
+
+
+int64_t File::Length() {
+ ASSERT(handle_->fd() >= 0);
+ struct stat st;
+ if (NO_RETRY_EXPECTED(fstat(handle_->fd(), &st)) == 0) {
+ return st.st_size;
+ }
+ return -1;
+}
+
+
+File* File::FileOpenW(const wchar_t* system_name, FileOpenMode mode) {
+ UNREACHABLE();
+ return NULL;
+}
+
+
+File* File::ScopedOpen(const char* name, FileOpenMode mode) {
+ // Report errors for non-regular files.
+ struct stat st;
+ if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) {
+ if (!S_ISREG(st.st_mode)) {
+ errno = (S_ISDIR(st.st_mode)) ? EISDIR : ENOENT;
+ return NULL;
+ }
+ }
+ int flags = O_RDONLY;
+ if ((mode & kWrite) != 0) {
+ ASSERT((mode & kWriteOnly) == 0);
+ flags = (O_RDWR | O_CREAT);
+ }
+ if ((mode & kWriteOnly) != 0) {
+ ASSERT((mode & kWrite) == 0);
+ flags = (O_WRONLY | O_CREAT);
+ }
+ if ((mode & kTruncate) != 0) {
+ flags = flags | O_TRUNC;
+ }
+ flags |= O_CLOEXEC;
+ int fd = NO_RETRY_EXPECTED(open(name, flags, 0666));
+ if (fd < 0) {
+ return NULL;
+ }
+ if ((((mode & kWrite) != 0) && ((mode & kTruncate) == 0)) ||
+ (((mode & kWriteOnly) != 0) && ((mode & kTruncate) == 0))) {
+ int64_t position = lseek(fd, 0, SEEK_END);
+ if (position < 0) {
+ return NULL;
+ }
+ }
+ return new File(new FileHandle(fd));
+}
+
+
+File* File::Open(const char* path, FileOpenMode mode) {
+ // ScopedOpen doesn't actually need a scope.
+ return ScopedOpen(path, mode);
+}
+
+
+File* File::OpenStdio(int fd) {
+ return ((fd < 0) || (2 < fd)) ? NULL : new File(new FileHandle(fd));
+}
+
+
+bool File::Exists(const char* name) {
+ struct stat st;
+ if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) {
+ return S_ISREG(st.st_mode);
+ } else {
+ return false;
+ }
+}
+
+
+bool File::Create(const char* name) {
+ int fd = NO_RETRY_EXPECTED(open(name, O_RDONLY | O_CREAT | O_CLOEXEC, 0666));
+ if (fd < 0) {
+ return false;
+ }
+ return (close(fd) == 0);
+}
+
+
+bool File::CreateLink(const char* name, const char* target) {
+ return NO_RETRY_EXPECTED(symlink(target, name)) == 0;
+}
+
+
+bool File::Delete(const char* name) {
+ File::Type type = File::GetType(name, true);
+ if (type == kIsFile) {
+ return NO_RETRY_EXPECTED(unlink(name)) == 0;
+ } else if (type == kIsDirectory) {
+ errno = EISDIR;
+ } else {
+ errno = ENOENT;
+ }
+ return false;
+}
+
+
+bool File::DeleteLink(const char* name) {
+ File::Type type = File::GetType(name, false);
+ if (type == kIsLink) {
+ return NO_RETRY_EXPECTED(unlink(name)) == 0;
+ }
+ errno = EINVAL;
+ return false;
+}
+
+
+bool File::Rename(const char* old_path, const char* new_path) {
+ File::Type type = File::GetType(old_path, true);
+ if (type == kIsFile) {
+ return NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0;
+ } else if (type == kIsDirectory) {
+ errno = EISDIR;
+ } else {
+ errno = ENOENT;
+ }
+ return false;
+}
+
+
+bool File::RenameLink(const char* old_path, const char* new_path) {
+ File::Type type = File::GetType(old_path, false);
+ if (type == kIsLink) {
+ return NO_RETRY_EXPECTED(rename(old_path, new_path)) == 0;
+ } else if (type == kIsDirectory) {
+ errno = EISDIR;
+ } else {
+ errno = EINVAL;
+ }
+ return false;
+}
+
+
+bool File::Copy(const char* old_path, const char* new_path) {
+ UNIMPLEMENTED();
+ return false;
+}
+
+
+int64_t File::LengthFromPath(const char* name) {
+ struct stat st;
+ if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) {
+ return st.st_size;
+ }
+ return -1;
+}
+
+
+void File::Stat(const char* name, int64_t* data) {
+ struct stat st;
+ if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) {
+ if (S_ISREG(st.st_mode)) {
+ data[kType] = kIsFile;
+ } else if (S_ISDIR(st.st_mode)) {
+ data[kType] = kIsDirectory;
+ } else if (S_ISLNK(st.st_mode)) {
+ data[kType] = kIsLink;
+ } else {
+ data[kType] = kDoesNotExist;
+ }
+ data[kCreatedTime] = static_cast<int64_t>(st.st_ctime) * 1000;
+ data[kModifiedTime] = static_cast<int64_t>(st.st_mtime) * 1000;
+ data[kAccessedTime] = static_cast<int64_t>(st.st_atime) * 1000;
+ data[kMode] = st.st_mode;
+ data[kSize] = st.st_size;
+ } else {
+ data[kType] = kDoesNotExist;
+ }
+}
+
+
+time_t File::LastModified(const char* name) {
+ struct stat st;
+ if (NO_RETRY_EXPECTED(stat(name, &st)) == 0) {
+ return st.st_mtime;
+ }
+ return -1;
+}
+
+
+const char* File::LinkTarget(const char* pathname) {
+ struct stat link_stats;
+ if (lstat(pathname, &link_stats) != 0) {
+ return NULL;
+ }
+ if (!S_ISLNK(link_stats.st_mode)) {
+ errno = ENOENT;
+ return NULL;
+ }
+ size_t target_size = link_stats.st_size;
+ char* target_name = DartUtils::ScopedCString(target_size + 1);
+ ASSERT(target_name != NULL);
+ size_t read_size = readlink(pathname, target_name, target_size + 1);
+ if (read_size != target_size) {
+ return NULL;
+ }
+ target_name[target_size] = '\0';
+ return target_name;
+}
+
+
+bool File::IsAbsolutePath(const char* pathname) {
+ return ((pathname != NULL) && (pathname[0] == '/'));
+}
+
+
+const char* File::GetCanonicalPath(const char* pathname) {
+ char* abs_path = NULL;
+ if (pathname != NULL) {
+ char* resolved_path = DartUtils::ScopedCString(PATH_MAX + 1);
+ ASSERT(resolved_path != NULL);
+ do {
+ abs_path = realpath(pathname, resolved_path);
+ } while ((abs_path == NULL) && (errno == EINTR));
+ ASSERT((abs_path == NULL) || IsAbsolutePath(abs_path));
+ ASSERT((abs_path == NULL) || (abs_path == resolved_path));
+ }
+ return abs_path;
+}
+
+
+const char* File::PathSeparator() {
+ return "/";
+}
+
+
+const char* File::StringEscapedPathSeparator() {
+ return "/";
+}
+
+
+File::StdioHandleType File::GetStdioHandleType(int fd) {
+ ASSERT((0 <= fd) && (fd <= 2));
+ struct stat buf;
+ int result = fstat(fd, &buf);
+ if (result == -1) {
+ const int kBufferSize = 1024;
+ char error_message[kBufferSize];
+ Utils::StrError(errno, error_message, kBufferSize);
+ FATAL2("Failed stat on file descriptor %d: %s", fd, error_message);
+ }
+ if (S_ISCHR(buf.st_mode)) {
+ return kTerminal;
+ }
+ if (S_ISFIFO(buf.st_mode)) {
+ return kPipe;
+ }
+ if (S_ISSOCK(buf.st_mode)) {
+ return kSocket;
+ }
+ if (S_ISREG(buf.st_mode)) {
+ return kFile;
+ }
+ return kOther;
+}
+
+
+File::Type File::GetType(const char* pathname, bool follow_links) {
+ struct stat entry_info;
+ int stat_success;
+ if (follow_links) {
+ stat_success = NO_RETRY_EXPECTED(stat(pathname, &entry_info));
+ } else {
+ stat_success = NO_RETRY_EXPECTED(lstat(pathname, &entry_info));
+ }
+ if (stat_success == -1) {
+ return File::kDoesNotExist;
+ }
+ if (S_ISDIR(entry_info.st_mode)) {
+ return File::kIsDirectory;
+ }
+ if (S_ISREG(entry_info.st_mode)) {
+ return File::kIsFile;
+ }
+ if (S_ISLNK(entry_info.st_mode)) {
+ return File::kIsLink;
+ }
+ return File::kDoesNotExist;
+}
+
+
+File::Identical File::AreIdentical(const char* file_1, const char* file_2) {
+ struct stat file_1_info;
+ struct stat file_2_info;
+ if ((NO_RETRY_EXPECTED(lstat(file_1, &file_1_info)) == -1) ||
+ (NO_RETRY_EXPECTED(lstat(file_2, &file_2_info)) == -1)) {
+ return File::kError;
+ }
+ return ((file_1_info.st_ino == file_2_info.st_ino) &&
+ (file_1_info.st_dev == file_2_info.st_dev)) ?
+ File::kIdentical :
+ File::kDifferent;
+}
+
+} // namespace bin
+} // namespace dart
+
+#endif // defined(TARGET_OS_FUCHSIA)
diff --git a/runtime/bin/file_system_watcher_fuchsia.cc b/runtime/bin/file_system_watcher_fuchsia.cc
new file mode 100644
index 0000000..abfbaa8
--- /dev/null
+++ b/runtime/bin/file_system_watcher_fuchsia.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#if !defined(DART_IO_DISABLED)
+
+#include "platform/globals.h"
+#if defined(TARGET_OS_FUCHSIA)
+
+#include "bin/file_system_watcher.h"
+
+namespace dart {
+namespace bin {
+
+Dart_Handle FileSystemWatcher::ReadEvents(intptr_t id, intptr_t path_id) {
+ UNIMPLEMENTED();
+ return DartUtils::NewDartOSError();
+}
+
+
+intptr_t FileSystemWatcher::GetSocketId(intptr_t id, intptr_t path_id) {
+ UNIMPLEMENTED();
+ return -1;
+}
+
+
+bool FileSystemWatcher::IsSupported() {
+ return false;
+}
+
+
+void FileSystemWatcher::UnwatchPath(intptr_t id, intptr_t path_id) {
+ UNIMPLEMENTED();
+}
+
+
+intptr_t FileSystemWatcher::Init() {
+ return 0;
+}
+
+
+void FileSystemWatcher::Close(intptr_t id) {
+ UNIMPLEMENTED();
+}
+
+
+intptr_t FileSystemWatcher::WatchPath(intptr_t id,
+ const char* path,
+ int events,
+ bool recursive) {
+ UNIMPLEMENTED();
+ return -1;
+}
+
+} // namespace bin
+} // namespace dart
+
+#endif // defined(TARGET_OS_FUCHSIA)
+
+#endif // !defined(DART_IO_DISABLED)
diff --git a/runtime/bin/fuchsia_test.cc b/runtime/bin/fuchsia_test.cc
index 802ff31..d063612 100644
--- a/runtime/bin/fuchsia_test.cc
+++ b/runtime/bin/fuchsia_test.cc
@@ -2,23 +2,152 @@
// for 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 <dart_api.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
-#include <dart_api.h>
+#include "bin/log.h"
+#include "platform/assert.h"
-int main(void) {
- fprintf(stderr, "Calling Dart_SetVMFlags\n");
- fflush(stderr);
- if (!Dart_SetVMFlags(0, NULL)) {
- fprintf(stderr, "Failed to set flags\n");
- fflush(stderr);
- return -1;
+const char* kBuiltinScript =
+ "_printString(String line) native \"Builtin_PrintString\";\n"
+ "_getPrintClosure() => _printString;\n";
+
+const char* kHelloWorldScript = "main() { print(\"Hello, Fuchsia!\"); }";
+
+namespace dart {
+namespace bin {
+
+// vm_isolate_snapshot_buffer points to a snapshot for the vm isolate if we
+// link in a snapshot otherwise it is initialized to NULL.
+extern const uint8_t* vm_isolate_snapshot_buffer;
+
+// isolate_snapshot_buffer points to a snapshot for an isolate if we link in a
+// snapshot otherwise it is initialized to NULL.
+extern const uint8_t* isolate_snapshot_buffer;
+
+static void Builtin_PrintString(Dart_NativeArguments args) {
+ intptr_t length = 0;
+ uint8_t* chars = NULL;
+ Dart_Handle str = Dart_GetNativeArgument(args, 0);
+ Dart_Handle result = Dart_StringToUTF8(str, &chars, &length);
+ if (Dart_IsError(result)) {
+ Dart_PropagateError(result);
}
- fprintf(stderr, "Calling Dart_Initialize\n");
- fflush(stderr);
+ // Uses fwrite to support printing NUL bytes.
+ intptr_t res = fwrite(chars, 1, length, stdout);
+ ASSERT(res == length);
+ fputs("\n", stdout);
+ fflush(stdout);
+}
+
+static Dart_NativeFunction NativeLookup(Dart_Handle name,
+ int argument_count,
+ bool* auto_setup_scope) {
+ const char* function_name = NULL;
+ Dart_Handle err = Dart_StringToCString(name, &function_name);
+ DART_CHECK_VALID(err);
+ *auto_setup_scope = true;
+ if (strcmp(function_name, "Builtin_PrintString") == 0) {
+ return reinterpret_cast<Dart_NativeFunction>(Builtin_PrintString);
+ }
+ return NULL;
+}
+
+static const uint8_t* NativeSymbol(Dart_NativeFunction nf) {
+ if (reinterpret_cast<Dart_NativeFunction>(Builtin_PrintString) == nf) {
+ return reinterpret_cast<const uint8_t*>("Builtin_PrintString");
+ }
+ return NULL;
+}
+
+static Dart_Handle PrepareBuiltinLibrary(const char* script) {
+ Log::Print("Creating builtin library uri\n");
+ Dart_Handle builtin_uri = Dart_NewStringFromCString("builtin_uri");
+ DART_CHECK_VALID(builtin_uri);
+
+ Log::Print("Creating builtin library script string\n");
+ Dart_Handle builtin_script = Dart_NewStringFromCString(script);
+ DART_CHECK_VALID(builtin_script);
+
+ Log::Print("Loading builtin library\n");
+ Dart_Handle status = Dart_LoadLibrary(builtin_uri, builtin_script, 0, 0);
+ DART_CHECK_VALID(status);
+
+ Log::Print("Looking up builtin library\n");
+ Dart_Handle builtin_library = Dart_LookupLibrary(builtin_uri);
+ DART_CHECK_VALID(builtin_library);
+
+ Log::Print("Setting up native resolver for builtin library\n");
+ status = Dart_SetNativeResolver(builtin_library, NativeLookup, NativeSymbol);
+ DART_CHECK_VALID(status);
+
+ return builtin_library;
+}
+
+static Dart_Handle PrepareScriptLibrary(const char* script) {
+ Log::Print("Creating script URI string\n");
+ Dart_Handle script_uri = Dart_NewStringFromCString("script_uri");
+ DART_CHECK_VALID(script_uri);
+
+ Log::Print("Creating script string\n");
+ Dart_Handle script_string = Dart_NewStringFromCString(script);
+ DART_CHECK_VALID(script_string);
+
+ Log::Print("Loading script into new library\n");
+ Dart_Handle status = Dart_LoadLibrary(script_uri, script_string, 0, 0);
+ DART_CHECK_VALID(status);
+
+ Log::Print("Looking up script library\n");
+ Dart_Handle library = Dart_LookupLibrary(script_uri);
+ DART_CHECK_VALID(library);
+
+ return library;
+}
+
+static Dart_Handle LoadInternalLibrary() {
+ Log::Print("Creating internal library uri string\n");
+ Dart_Handle url = Dart_NewStringFromCString("dart:_internal");
+ DART_CHECK_VALID(url);
+
+ Log::Print("Looking up internal library\n");
+ Dart_Handle internal_library = Dart_LookupLibrary(url);
+ DART_CHECK_VALID(internal_library);
+
+ return internal_library;
+}
+
+static void PreparePrintClosure(Dart_Handle builtin_library,
+ Dart_Handle internal_library) {
+ Log::Print("Creating _getPrintClosure name string\n");
+ Dart_Handle get_print_closure_name =
+ Dart_NewStringFromCString("_getPrintClosure");
+ DART_CHECK_VALID(get_print_closure_name);
+
+ Log::Print("Invoking _getPrintClosure\n");
+ Dart_Handle print_closure = Dart_Invoke(
+ builtin_library, get_print_closure_name, 0, NULL);
+ DART_CHECK_VALID(print_closure);
+
+ Log::Print("Creating _printClosure name string\n");
+ Dart_Handle print_closure_name = Dart_NewStringFromCString("_printClosure");
+ DART_CHECK_VALID(print_closure_name);
+
+ Log::Print("Setting _printClosure to result of _getPrintClosure\n");
+ Dart_Handle status = Dart_SetField(
+ internal_library, print_closure_name, print_closure);
+ DART_CHECK_VALID(status);
+}
+
+int Main() {
+ Log::Print("Calling Dart_SetVMFlags\n");
+ if (!Dart_SetVMFlags(0, NULL)) {
+ FATAL("Failed to set flags\n");
+ }
+ Log::Print("Calling Dart_Initialize\n");
char* error = Dart_Initialize(
- NULL, NULL, NULL,
+ vm_isolate_snapshot_buffer, NULL, NULL,
NULL, NULL, NULL, NULL,
NULL,
NULL,
@@ -28,12 +157,63 @@
NULL,
NULL);
if (error != NULL) {
- fprintf(stderr, "VM initialization failed: %s\n", error);
- fflush(stderr);
- free(error);
- return -1;
+ FATAL1("VM initialization failed: %s\n", error);
}
- fprintf(stderr, "Success!\n");
- fflush(stderr);
+
+ Log::Print("Creating Isolate\n");
+ Dart_Isolate isolate = Dart_CreateIsolate(
+ "script_uri",
+ "main",
+ isolate_snapshot_buffer,
+ NULL,
+ NULL,
+ &error);
+ if (isolate == NULL) {
+ FATAL1("Dart_CreateIsolate failed: %s\n", error);
+ }
+
+ Log::Print("Entering Scope\n");
+ Dart_EnterScope();
+
+ Dart_Handle library = PrepareScriptLibrary(kHelloWorldScript);
+
+ Dart_Handle builtin_library = PrepareBuiltinLibrary(kBuiltinScript);
+
+ Log::Print("Finalizing loading\n");
+ Dart_Handle status = Dart_FinalizeLoading(false);
+ DART_CHECK_VALID(status);
+
+ Dart_Handle internal_library = LoadInternalLibrary();
+
+ PreparePrintClosure(builtin_library, internal_library);
+
+ Log::Print("Creating main string\n");
+ Dart_Handle main_name = Dart_NewStringFromCString("main");
+ DART_CHECK_VALID(main_name);
+
+ Log::Print("---- Invoking main() ----\n");
+ status = Dart_Invoke(library, main_name, 0, NULL);
+ DART_CHECK_VALID(status);
+ Log::Print("---- main() returned ----\n");
+
+ Log::Print("Exiting Scope\n");
+ Dart_ExitScope();
+ Log::Print("Shutting down the isolate\n");
+ Dart_ShutdownIsolate();
+
+ Log::Print("Calling Dart_Cleanup\n");
+ error = Dart_Cleanup();
+ if (error != NULL) {
+ FATAL1("VM Cleanup failed: %s\n", error);
+ }
+
+ Log::Print("Success!\n");
return 0;
}
+
+} // namespace bin
+} // namespace dart
+
+int main(void) {
+ return dart::bin::Main();
+}
diff --git a/runtime/bin/gen_snapshot.cc b/runtime/bin/gen_snapshot.cc
index cc8bb06..d75a347 100644
--- a/runtime/bin/gen_snapshot.cc
+++ b/runtime/bin/gen_snapshot.cc
@@ -1169,7 +1169,10 @@
CHECK_RESULT(result);
ASSERT(Dart_IsServiceIsolate(isolate));
// Load embedder specific bits and return. Will not start http server.
- if (!VmService::Setup("127.0.0.1", -1, false /* running_precompiled */)) {
+ if (!VmService::Setup("127.0.0.1",
+ -1,
+ false /* running_precompiled */,
+ false /* server dev mode */)) {
*error = strdup(VmService::GetErrorMessage());
return NULL;
}
@@ -1201,6 +1204,7 @@
}
Thread::InitOnce();
+ Loader::InitOnce();
DartUtils::SetOriginalWorkingDirectory();
// Start event handler.
TimerUtils::InitOnce();
diff --git a/runtime/bin/io_impl_sources.gypi b/runtime/bin/io_impl_sources.gypi
index c0de4c23..1e5a1a4 100644
--- a/runtime/bin/io_impl_sources.gypi
+++ b/runtime/bin/io_impl_sources.gypi
@@ -10,6 +10,8 @@
'eventhandler.h',
'eventhandler_android.cc',
'eventhandler_android.h',
+ 'eventhandler_fuchsia.cc',
+ 'eventhandler_fuchsia.h',
'eventhandler_linux.cc',
'eventhandler_linux.h',
'eventhandler_macos.cc',
@@ -20,6 +22,7 @@
'file_system_watcher.cc',
'file_system_watcher.h',
'file_system_watcher_android.cc',
+ 'file_system_watcher_fuchsia.cc',
'file_system_watcher_linux.cc',
'file_system_watcher_macos.cc',
'file_system_watcher_unsupported.cc',
@@ -35,6 +38,7 @@
'platform.cc',
'platform.h',
'platform_android.cc',
+ 'platform_fuchsia.cc',
'platform_linux.cc',
'platform_macos.cc',
'platform_unsupported.cc',
@@ -42,12 +46,12 @@
'process.cc',
'process.h',
'process_android.cc',
+ 'process_fuchsia.cc',
'process_linux.cc',
'process_macos.cc',
'process_unsupported.cc',
'process_win.cc',
'reference_counting.h',
- '../../third_party/root_certificates/root_certificates.cc',
'root_certificates_unsupported.cc',
'secure_socket.h',
'secure_socket_boringssl.cc',
@@ -61,6 +65,8 @@
'socket.h',
'socket_android.cc',
'socket_android.h',
+ 'socket_fuchsia.cc',
+ 'socket_fuchsia.h',
'socket_linux.cc',
'socket_linux.h',
'socket_macos.cc',
@@ -71,6 +77,7 @@
'stdio.cc',
'stdio.h',
'stdio_android.cc',
+ 'stdio_fuchsia.cc',
'stdio_linux.cc',
'stdio_macos.cc',
'stdio_unsupported.cc',
diff --git a/runtime/bin/loader.cc b/runtime/bin/loader.cc
index 6a99a4e..cf6f4ec 100644
--- a/runtime/bin/loader.cc
+++ b/runtime/bin/loader.cc
@@ -661,7 +661,12 @@
}
-Mutex Loader::loader_infos_lock_;
+void Loader::InitOnce() {
+ loader_infos_lock_ = new Mutex();
+}
+
+
+Mutex* Loader::loader_infos_lock_;
Loader::LoaderInfo* Loader::loader_infos_ = NULL;
intptr_t Loader::loader_infos_length_ = 0;
intptr_t Loader::loader_infos_capacity_ = 0;
@@ -672,7 +677,7 @@
// correct loader.
// This happens whenever an isolate begins loading.
void Loader::AddLoader(Dart_Port port, IsolateData* isolate_data) {
- MutexLocker ml(&loader_infos_lock_);
+ MutexLocker ml(loader_infos_lock_);
ASSERT(LoaderForLocked(port) == NULL);
if (loader_infos_length_ == loader_infos_capacity_) {
// Grow to an initial capacity or double in size.
@@ -700,7 +705,7 @@
// Remove |port| from the map.
// This happens once an isolate has finished loading.
void Loader::RemoveLoader(Dart_Port port) {
- MutexLocker ml(&loader_infos_lock_);
+ MutexLocker ml(loader_infos_lock_);
const intptr_t index = LoaderIndexFor(port);
ASSERT(index >= 0);
const intptr_t last = loader_infos_length_ - 1;
@@ -733,14 +738,14 @@
Loader* Loader::LoaderFor(Dart_Port port) {
- MutexLocker ml(&loader_infos_lock_);
+ MutexLocker ml(loader_infos_lock_);
return LoaderForLocked(port);
}
void Loader::NativeMessageHandler(Dart_Port dest_port_id,
Dart_CObject* message) {
- MutexLocker ml(&loader_infos_lock_);
+ MutexLocker ml(loader_infos_lock_);
Loader* loader = LoaderForLocked(dest_port_id);
if (loader == NULL) {
return;
diff --git a/runtime/bin/loader.h b/runtime/bin/loader.h
index 034138e..97e87a4 100644
--- a/runtime/bin/loader.h
+++ b/runtime/bin/loader.h
@@ -37,6 +37,8 @@
return error_;
}
+ static void InitOnce();
+
private:
// The port assigned to our native message handler.
Dart_Port port_;
@@ -124,7 +126,7 @@
};
// The map of active loaders.
- static Mutex loader_infos_lock_;
+ static Mutex* loader_infos_lock_;
static LoaderInfo* loader_infos_;
static intptr_t loader_infos_length_;
static intptr_t loader_infos_capacity_;
diff --git a/runtime/bin/log_fuchsia.cc b/runtime/bin/log_fuchsia.cc
new file mode 100644
index 0000000..0c1f7af
--- /dev/null
+++ b/runtime/bin/log_fuchsia.cc
@@ -0,0 +1,28 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "platform/globals.h"
+#if defined(TARGET_OS_FUCHSIA)
+
+#include "bin/log.h"
+
+#include <stdio.h> // NOLINT
+
+namespace dart {
+namespace bin {
+
+void Log::VPrint(const char* format, va_list args) {
+ vfprintf(stdout, format, args);
+ fflush(stdout);
+}
+
+void Log::VPrintErr(const char* format, va_list args) {
+ vfprintf(stderr, format, args);
+ fflush(stdout);
+}
+
+} // namespace bin
+} // namespace dart
+
+#endif // defined(TARGET_OS_FUCHSIA)
diff --git a/runtime/bin/main.cc b/runtime/bin/main.cc
index a1f859a..89c752b 100644
--- a/runtime/bin/main.cc
+++ b/runtime/bin/main.cc
@@ -119,7 +119,9 @@
// The 0 port is a magic value which results in the first available port
// being allocated.
static int vm_service_server_port = -1;
-
+// True when we are running in development mode and cross origin security
+// checks are disabled.
+static bool vm_service_dev_mode = false;
// Exit code indicating an API error.
static const int kApiErrorExitCode = 253;
@@ -130,10 +132,6 @@
// Exit code indicating a vm restart request. Never returned to the user.
static const int kRestartRequestExitCode = 1000;
-// Global flag that is used to indicate that the VM should do a clean
-// shutdown.
-static bool do_vm_shutdown = true;
-
static void ErrorExit(int exit_code, const char* format, ...) {
va_list arguments;
va_start(arguments, format);
@@ -153,9 +151,7 @@
free(error);
}
- if (do_vm_shutdown) {
- EventHandler::Stop();
- }
+ EventHandler::Stop();
Platform::Exit(exit_code);
}
@@ -393,6 +389,16 @@
}
+static bool ProcessDisableServiceOriginCheckOption(
+ const char* option_value, CommandLineOptions* vm_options) {
+ ASSERT(option_value != NULL);
+ Log::PrintErr("WARNING: You are running with the service protocol in an "
+ "insecure mode.\n");
+ vm_service_dev_mode = true;
+ return true;
+}
+
+
static bool ProcessObserveOption(const char* option_value,
CommandLineOptions* vm_options) {
ASSERT(option_value != NULL);
@@ -434,45 +440,18 @@
// Identity reload.
vm_options->AddArgument("--identity_reload");
// Start reloading quickly.
- vm_options->AddArgument("--reload_every=50");
+ vm_options->AddArgument("--reload_every=4");
// Reload from optimized and unoptimized code.
vm_options->AddArgument("--reload_every_optimized=false");
// Reload less frequently as time goes on.
vm_options->AddArgument("--reload_every_back_off");
- // Ensure that an isolate has reloaded once.
+ // Ensure that every isolate has reloaded once before exiting.
vm_options->AddArgument("--check_reloaded");
return true;
}
-static bool ProcessShutdownOption(const char* arg,
- CommandLineOptions* vm_options) {
- ASSERT(arg != NULL);
- if (*arg == '\0') {
- do_vm_shutdown = true;
- vm_options->AddArgument("--shutdown");
- return true;
- }
-
- if ((*arg != '=') && (*arg != ':')) {
- return false;
- }
-
- if (strcmp(arg + 1, "true") == 0) {
- do_vm_shutdown = true;
- vm_options->AddArgument("--shutdown");
- return true;
- } else if (strcmp(arg + 1, "false") == 0) {
- do_vm_shutdown = false;
- vm_options->AddArgument("--no-shutdown");
- return true;
- }
-
- return false;
-}
-
-
static struct {
const char* option_name;
bool (*process)(const char* option, CommandLineOptions* vm_options);
@@ -490,8 +469,8 @@
// VM specific options to the standalone dart program.
{ "--compile_all", ProcessCompileAllOption },
{ "--enable-vm-service", ProcessEnableVmServiceOption },
+ { "--disable-service-origin-check", ProcessDisableServiceOriginCheckOption },
{ "--observe", ProcessObserveOption },
- { "--shutdown", ProcessShutdownOption },
{ "--snapshot=", ProcessSnapshotFilenameOption },
{ "--snapshot-kind=", ProcessSnapshotKindOption },
{ "--run-app-snapshot=", ProcessRunAppSnapshotOption },
@@ -766,7 +745,8 @@
bool skip_library_load = run_app_snapshot;
if (!VmService::Setup(vm_service_server_ip,
vm_service_server_port,
- skip_library_load)) {
+ skip_library_load,
+ vm_service_dev_mode)) {
*error = strdup(VmService::GetErrorMessage());
return NULL;
}
@@ -1131,7 +1111,7 @@
}
DartUtils::CloseFile(file);
if (concat != NULL) {
- delete concat;
+ delete[] concat;
}
}
@@ -1160,7 +1140,7 @@
Platform::Exit(kErrorExitCode);
}
if (concat != NULL) {
- delete concat;
+ delete[] concat;
}
}
@@ -1377,9 +1357,7 @@
Log::PrintErr("VM cleanup failed: %s\n", error);
free(error);
}
- if (do_vm_shutdown) {
- EventHandler::Stop();
- }
+ EventHandler::Stop();
Platform::Exit((exit_code != 0) ? exit_code : kErrorExitCode);
}
delete [] isolate_name;
@@ -1521,7 +1499,7 @@
// Observatory assets are only needed in the regular dart binary.
-#if !defined(DART_PRECOMPILER)
+#if !defined(DART_PRECOMPILER) && !defined(NO_OBSERVATORY)
extern unsigned int observatory_assets_archive_len;
extern const uint8_t* observatory_assets_archive;
@@ -1610,7 +1588,7 @@
void main(int argc, char** argv) {
char* script_name;
- const int EXTRA_VM_ARGUMENTS = 2;
+ const int EXTRA_VM_ARGUMENTS = 8;
CommandLineOptions vm_options(argc + EXTRA_VM_ARGUMENTS);
CommandLineOptions dart_options(argc);
bool print_flags_seen = false;
@@ -1653,6 +1631,8 @@
Thread::InitOnce();
+ Loader::InitOnce();
+
if (!DartUtils::SetOriginalWorkingDirectory()) {
OSError err;
fprintf(stderr, "Error determining current directory: %s\n", err.message());
@@ -1717,9 +1697,7 @@
DartUtils::EntropySource,
GetVMServiceAssetsArchiveCallback);
if (error != NULL) {
- if (do_vm_shutdown) {
- EventHandler::Stop();
- }
+ EventHandler::Stop();
fprintf(stderr, "VM initialization failed: %s\n", error);
fflush(stderr);
free(error);
@@ -1744,9 +1722,7 @@
Log::PrintErr("VM cleanup failed: %s\n", error);
free(error);
}
- if (do_vm_shutdown) {
- EventHandler::Stop();
- }
+ EventHandler::Stop();
// Free copied argument strings if converted.
if (argv_converted) {
diff --git a/runtime/bin/platform_fuchsia.cc b/runtime/bin/platform_fuchsia.cc
new file mode 100644
index 0000000..ace3c37
--- /dev/null
+++ b/runtime/bin/platform_fuchsia.cc
@@ -0,0 +1,75 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "platform/globals.h"
+#if defined(TARGET_OS_FUCHSIA)
+
+#include "bin/platform.h"
+
+#include <runtime/sysinfo.h>
+#include <string.h> // NOLINT
+#include <unistd.h> // NOLINT
+
+#include "bin/fdutils.h"
+#include "bin/file.h"
+
+namespace dart {
+namespace bin {
+
+const char* Platform::executable_name_ = NULL;
+char* Platform::resolved_executable_name_ = NULL;
+int Platform::script_index_ = 1;
+char** Platform::argv_ = NULL;
+
+bool Platform::Initialize() {
+ return true;
+}
+
+
+int Platform::NumberOfProcessors() {
+ return mxr_get_nprocs();
+}
+
+
+const char* Platform::OperatingSystem() {
+ return "fuchsia";
+}
+
+
+const char* Platform::LibraryPrefix() {
+ return "lib";
+}
+
+
+const char* Platform::LibraryExtension() {
+ return "so";
+}
+
+
+bool Platform::LocalHostname(char *buffer, intptr_t buffer_length) {
+ return gethostname(buffer, buffer_length) == 0;
+}
+
+
+char** Platform::Environment(intptr_t* count) {
+ char** result =
+ reinterpret_cast<char**>(Dart_ScopeAllocate(1 * sizeof(*result)));
+ result[0] = NULL;
+ return result;
+}
+
+
+const char* Platform::ResolveExecutablePath() {
+ return "dart";
+}
+
+
+void Platform::Exit(int exit_code) {
+ exit(exit_code);
+}
+
+} // namespace bin
+} // namespace dart
+
+#endif // defined(TARGET_OS_FUCHSIA)
diff --git a/runtime/bin/process_fuchsia.cc b/runtime/bin/process_fuchsia.cc
new file mode 100644
index 0000000..5858800
--- /dev/null
+++ b/runtime/bin/process_fuchsia.cc
@@ -0,0 +1,77 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#if !defined(DART_IO_DISABLED)
+
+#include "platform/globals.h"
+#if defined(TARGET_OS_FUCHSIA)
+
+#include "bin/process.h"
+
+#include "bin/lockers.h"
+#include "platform/assert.h"
+
+
+namespace dart {
+namespace bin {
+
+int Process::global_exit_code_ = 0;
+Mutex* Process::global_exit_code_mutex_ = new Mutex();
+
+void Process::TerminateExitCodeHandler() {
+}
+
+intptr_t Process::CurrentProcessId() {
+ UNIMPLEMENTED();
+ return 0;
+}
+
+intptr_t Process::SetSignalHandler(intptr_t signal) {
+ UNIMPLEMENTED();
+ return -1;
+}
+
+
+void Process::ClearSignalHandler(intptr_t signal) {
+ UNIMPLEMENTED();
+}
+
+bool Process::Wait(intptr_t pid,
+ intptr_t in,
+ intptr_t out,
+ intptr_t err,
+ intptr_t exit_event,
+ ProcessResult* result) {
+ UNIMPLEMENTED();
+ return false;
+}
+
+bool Process::Kill(intptr_t id, int signal) {
+ UNIMPLEMENTED();
+ return false;
+}
+
+int Process::Start(const char* path,
+ char* arguments[],
+ intptr_t arguments_length,
+ const char* working_directory,
+ char* environment[],
+ intptr_t environment_length,
+ ProcessStartMode mode,
+ intptr_t* in,
+ intptr_t* out,
+ intptr_t* err,
+ intptr_t* id,
+ intptr_t* exit_event,
+ char** os_error_message) {
+ UNIMPLEMENTED();
+ return -1;
+}
+
+} // namespace bin
+} // namespace dart
+
+#endif // defined(TARGET_OS_FUCHSIA)
+
+#endif // !defined(DART_IO_DISABLED)
diff --git a/runtime/bin/socket.h b/runtime/bin/socket.h
index bd8ed4b..0b17706 100644
--- a/runtime/bin/socket.h
+++ b/runtime/bin/socket.h
@@ -13,6 +13,8 @@
// Declare the OS-specific types ahead of defining the generic class.
#if defined(TARGET_OS_ANDROID)
#include "bin/socket_android.h"
+#elif defined(TARGET_OS_FUCHSIA)
+#include "bin/socket_fuchsia.h"
#elif defined(TARGET_OS_LINUX)
#include "bin/socket_linux.h"
#elif defined(TARGET_OS_MACOS)
diff --git a/runtime/bin/socket_fuchsia.cc b/runtime/bin/socket_fuchsia.cc
new file mode 100644
index 0000000..78b5071
--- /dev/null
+++ b/runtime/bin/socket_fuchsia.cc
@@ -0,0 +1,242 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#if !defined(DART_IO_DISABLED)
+
+#include "platform/globals.h"
+#if defined(TARGET_OS_FUCHSIA)
+
+#include "bin/socket.h"
+#include "bin/socket_fuchsia.h"
+
+#include "bin/file.h"
+
+namespace dart {
+namespace bin {
+
+SocketAddress::SocketAddress(struct sockaddr* sa) {
+ UNIMPLEMENTED();
+}
+
+
+bool Socket::FormatNumericAddress(const RawAddr& addr, char* address, int len) {
+ UNIMPLEMENTED();
+ return false;
+}
+
+
+bool Socket::Initialize() {
+ UNIMPLEMENTED();
+ return true;
+}
+
+
+intptr_t Socket::CreateConnect(const RawAddr& addr) {
+ UNIMPLEMENTED();
+ return -1;
+}
+
+
+intptr_t Socket::CreateBindConnect(const RawAddr& addr,
+ const RawAddr& source_addr) {
+ UNIMPLEMENTED();
+ return -1;
+}
+
+
+intptr_t Socket::Available(intptr_t fd) {
+ UNIMPLEMENTED();
+ return -1;
+}
+
+
+intptr_t Socket::Read(intptr_t fd, void* buffer, intptr_t num_bytes) {
+ UNIMPLEMENTED();
+ return -1;
+}
+
+
+intptr_t Socket::RecvFrom(
+ intptr_t fd, void* buffer, intptr_t num_bytes, RawAddr* addr) {
+ UNIMPLEMENTED();
+ return -1;
+}
+
+
+intptr_t Socket::Write(intptr_t fd, const void* buffer, intptr_t num_bytes) {
+ UNIMPLEMENTED();
+ return -1;
+}
+
+
+intptr_t Socket::SendTo(
+ intptr_t fd, const void* buffer, intptr_t num_bytes, const RawAddr& addr) {
+ UNIMPLEMENTED();
+ return -1;
+}
+
+
+intptr_t Socket::GetPort(intptr_t fd) {
+ UNIMPLEMENTED();
+ return -1;
+}
+
+
+SocketAddress* Socket::GetRemotePeer(intptr_t fd, intptr_t* port) {
+ UNIMPLEMENTED();
+ return NULL;
+}
+
+
+void Socket::GetError(intptr_t fd, OSError* os_error) {
+ UNIMPLEMENTED();
+}
+
+
+int Socket::GetType(intptr_t fd) {
+ UNIMPLEMENTED();
+ return File::kOther;
+}
+
+
+intptr_t Socket::GetStdioHandle(intptr_t num) {
+ UNIMPLEMENTED();
+ return num;
+}
+
+
+AddressList<SocketAddress>* Socket::LookupAddress(const char* host,
+ int type,
+ OSError** os_error) {
+ UNIMPLEMENTED();
+ return NULL;
+}
+
+
+bool Socket::ReverseLookup(const RawAddr& addr,
+ char* host,
+ intptr_t host_len,
+ OSError** os_error) {
+ UNIMPLEMENTED();
+ return false;
+}
+
+
+bool Socket::ParseAddress(int type, const char* address, RawAddr* addr) {
+ UNIMPLEMENTED();
+ return false;
+}
+
+
+intptr_t Socket::CreateBindDatagram(const RawAddr& addr, bool reuseAddress) {
+ UNIMPLEMENTED();
+ return -1;
+}
+
+
+bool Socket::ListInterfacesSupported() {
+ return false;
+}
+
+
+AddressList<InterfaceSocketAddress>* Socket::ListInterfaces(
+ int type,
+ OSError** os_error) {
+ UNIMPLEMENTED();
+ return NULL;
+}
+
+
+intptr_t ServerSocket::CreateBindListen(const RawAddr& addr,
+ intptr_t backlog,
+ bool v6_only) {
+ UNIMPLEMENTED();
+ return -1;
+}
+
+
+bool ServerSocket::StartAccept(intptr_t fd) {
+ UNIMPLEMENTED();
+ return false;
+}
+
+
+intptr_t ServerSocket::Accept(intptr_t fd) {
+ UNIMPLEMENTED();
+ return -1;
+}
+
+
+void Socket::Close(intptr_t fd) {
+ UNIMPLEMENTED();
+}
+
+
+bool Socket::GetNoDelay(intptr_t fd, bool* enabled) {
+ UNIMPLEMENTED();
+ return false;
+}
+
+
+bool Socket::SetNoDelay(intptr_t fd, bool enabled) {
+ UNIMPLEMENTED();
+ return false;
+}
+
+
+bool Socket::GetMulticastLoop(intptr_t fd, intptr_t protocol, bool* enabled) {
+ UNIMPLEMENTED();
+ return false;
+}
+
+
+bool Socket::SetMulticastLoop(intptr_t fd, intptr_t protocol, bool enabled) {
+ UNIMPLEMENTED();
+ return false;
+}
+
+
+bool Socket::GetMulticastHops(intptr_t fd, intptr_t protocol, int* value) {
+ UNIMPLEMENTED();
+ return false;
+}
+
+
+bool Socket::SetMulticastHops(intptr_t fd, intptr_t protocol, int value) {
+ UNIMPLEMENTED();
+ return false;
+}
+
+
+bool Socket::GetBroadcast(intptr_t fd, bool* enabled) {
+ UNIMPLEMENTED();
+ return false;
+}
+
+
+bool Socket::SetBroadcast(intptr_t fd, bool enabled) {
+ UNIMPLEMENTED();
+ return false;
+}
+
+
+bool Socket::JoinMulticast(
+ intptr_t fd, const RawAddr& addr, const RawAddr&, int interfaceIndex) {
+ UNIMPLEMENTED();
+ return false;
+}
+
+
+bool Socket::LeaveMulticast(
+ intptr_t fd, const RawAddr& addr, const RawAddr&, int interfaceIndex) {
+ UNIMPLEMENTED();
+ return false;
+}
+
+} // namespace bin
+} // namespace dart
+
+#endif // defined(TARGET_OS_FUCHSIA)
+
+#endif // !defined(DART_IO_DISABLED)
diff --git a/runtime/bin/socket_fuchsia.h b/runtime/bin/socket_fuchsia.h
new file mode 100644
index 0000000..82f8916
--- /dev/null
+++ b/runtime/bin/socket_fuchsia.h
@@ -0,0 +1,12 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#ifndef BIN_SOCKET_FUCHSIA_H_
+#define BIN_SOCKET_FUCHSIA_H_
+
+#if !defined(BIN_SOCKET_H_)
+#error Do not include socket_fuchsia.h directly. Use socket.h.
+#endif
+
+#endif // BIN_SOCKET_FUCHSIA_H_
diff --git a/runtime/bin/stdio_fuchsia.cc b/runtime/bin/stdio_fuchsia.cc
new file mode 100644
index 0000000..e297499
--- /dev/null
+++ b/runtime/bin/stdio_fuchsia.cc
@@ -0,0 +1,53 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#if !defined(DART_IO_DISABLED)
+
+#include "platform/globals.h"
+#if defined(TARGET_OS_FUCHSIA)
+
+#include "bin/stdio.h"
+
+namespace dart {
+namespace bin {
+
+int Stdin::ReadByte() {
+ UNIMPLEMENTED();
+ return -1;
+}
+
+
+bool Stdin::GetEchoMode() {
+ UNIMPLEMENTED();
+ return false;
+}
+
+
+void Stdin::SetEchoMode(bool enabled) {
+ UNIMPLEMENTED();
+}
+
+
+bool Stdin::GetLineMode() {
+ UNIMPLEMENTED();
+ return false;
+}
+
+
+void Stdin::SetLineMode(bool enabled) {
+ UNIMPLEMENTED();
+}
+
+
+bool Stdout::GetTerminalSize(intptr_t fd, int size[2]) {
+ UNIMPLEMENTED();
+ return false;
+}
+
+} // namespace bin
+} // namespace dart
+
+#endif // defined(TARGET_OS_FUCHSIA)
+
+#endif // !defined(DART_IO_DISABLED)
diff --git a/runtime/bin/thread.h b/runtime/bin/thread.h
index 979c77f..37a4b9f 100644
--- a/runtime/bin/thread.h
+++ b/runtime/bin/thread.h
@@ -18,6 +18,8 @@
// Declare the OS-specific types ahead of defining the generic classes.
#if defined(TARGET_OS_ANDROID)
#include "bin/thread_android.h"
+#elif defined(TARGET_OS_FUCHSIA)
+#include "bin/thread_fuchsia.h"
#elif defined(TARGET_OS_LINUX)
#include "bin/thread_linux.h"
#elif defined(TARGET_OS_MACOS)
diff --git a/runtime/bin/thread_fuchsia.cc b/runtime/bin/thread_fuchsia.cc
new file mode 100644
index 0000000..57f4cd0
--- /dev/null
+++ b/runtime/bin/thread_fuchsia.cc
@@ -0,0 +1,331 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "platform/globals.h"
+#if defined(TARGET_OS_FUCHSIA)
+
+#include "bin/thread.h"
+#include "bin/thread_fuchsia.h"
+
+#include <errno.h> // NOLINT
+#include <sys/resource.h> // NOLINT
+#include <sys/time.h> // NOLINT
+
+#include "platform/assert.h"
+#include "platform/utils.h"
+
+namespace dart {
+namespace bin {
+
+#define VALIDATE_PTHREAD_RESULT(result) \
+ if (result != 0) { \
+ const int kBufferSize = 1024; \
+ char error_buf[kBufferSize]; \
+ FATAL2("pthread error: %d (%s)", result, \
+ Utils::StrError(result, error_buf, kBufferSize)); \
+ }
+
+
+#ifdef DEBUG
+#define RETURN_ON_PTHREAD_FAILURE(result) \
+ if (result != 0) { \
+ const int kBufferSize = 1024; \
+ char error_buf[kBufferSize]; \
+ fprintf(stderr, "%s:%d: pthread error: %d (%s)\n", \
+ __FILE__, __LINE__, result, \
+ Utils::StrError(result, error_buf, kBufferSize)); \
+ return result; \
+ }
+#else
+#define RETURN_ON_PTHREAD_FAILURE(result) \
+ if (result != 0) { \
+ return result; \
+ }
+#endif
+
+
+static void ComputeTimeSpecMicros(struct timespec* ts, int64_t micros) {
+ int64_t secs = micros / kMicrosecondsPerSecond;
+ int64_t nanos =
+ (micros - (secs * kMicrosecondsPerSecond)) * kNanosecondsPerMicrosecond;
+ int result = clock_gettime(CLOCK_MONOTONIC, ts);
+ ASSERT(result == 0);
+ ts->tv_sec += secs;
+ ts->tv_nsec += nanos;
+ if (ts->tv_nsec >= kNanosecondsPerSecond) {
+ ts->tv_sec += 1;
+ ts->tv_nsec -= kNanosecondsPerSecond;
+ }
+}
+
+
+class ThreadStartData {
+ public:
+ ThreadStartData(Thread::ThreadStartFunction function,
+ uword parameter)
+ : function_(function), parameter_(parameter) {}
+
+ Thread::ThreadStartFunction function() const { return function_; }
+ uword parameter() const { return parameter_; }
+
+ private:
+ Thread::ThreadStartFunction function_;
+ uword parameter_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThreadStartData);
+};
+
+
+// Dispatch to the thread start function provided by the caller. This trampoline
+// is used to ensure that the thread is properly destroyed if the thread just
+// exits.
+static void* ThreadStart(void* data_ptr) {
+ ThreadStartData* data = reinterpret_cast<ThreadStartData*>(data_ptr);
+
+ Thread::ThreadStartFunction function = data->function();
+ uword parameter = data->parameter();
+ delete data;
+
+ // Call the supplied thread start function handing it its parameters.
+ function(parameter);
+
+ return NULL;
+}
+
+
+int Thread::Start(ThreadStartFunction function, uword parameter) {
+ pthread_attr_t attr;
+ int result = pthread_attr_init(&attr);
+ RETURN_ON_PTHREAD_FAILURE(result);
+
+ result = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+ RETURN_ON_PTHREAD_FAILURE(result);
+
+ result = pthread_attr_setstacksize(&attr, Thread::GetMaxStackSize());
+ RETURN_ON_PTHREAD_FAILURE(result);
+
+ ThreadStartData* data = new ThreadStartData(function, parameter);
+
+ pthread_t tid;
+ result = pthread_create(&tid, &attr, ThreadStart, data);
+ RETURN_ON_PTHREAD_FAILURE(result);
+
+ result = pthread_attr_destroy(&attr);
+ RETURN_ON_PTHREAD_FAILURE(result);
+
+ return 0;
+}
+
+
+const ThreadLocalKey Thread::kUnsetThreadLocalKey =
+ static_cast<pthread_key_t>(-1);
+const ThreadId Thread::kInvalidThreadId = static_cast<ThreadId>(0);
+
+ThreadLocalKey Thread::CreateThreadLocal() {
+ pthread_key_t key = kUnsetThreadLocalKey;
+ int result = pthread_key_create(&key, NULL);
+ VALIDATE_PTHREAD_RESULT(result);
+ ASSERT(key != kUnsetThreadLocalKey);
+ return key;
+}
+
+
+void Thread::DeleteThreadLocal(ThreadLocalKey key) {
+ ASSERT(key != kUnsetThreadLocalKey);
+ int result = pthread_key_delete(key);
+ VALIDATE_PTHREAD_RESULT(result);
+}
+
+
+void Thread::SetThreadLocal(ThreadLocalKey key, uword value) {
+ ASSERT(key != kUnsetThreadLocalKey);
+ int result = pthread_setspecific(key, reinterpret_cast<void*>(value));
+ VALIDATE_PTHREAD_RESULT(result);
+}
+
+
+intptr_t Thread::GetMaxStackSize() {
+ const int kStackSize = (128 * kWordSize * KB);
+ return kStackSize;
+}
+
+
+ThreadId Thread::GetCurrentThreadId() {
+ return pthread_self();
+}
+
+
+intptr_t Thread::ThreadIdToIntPtr(ThreadId id) {
+ ASSERT(sizeof(id) == sizeof(intptr_t));
+ return static_cast<intptr_t>(id);
+}
+
+
+bool Thread::Compare(ThreadId a, ThreadId b) {
+ return (pthread_equal(a, b) != 0);
+}
+
+
+void Thread::GetThreadCpuUsage(ThreadId thread_id, int64_t* cpu_usage) {
+ UNIMPLEMENTED();
+}
+
+
+void Thread::InitOnce() {
+ // Nothing to be done.
+}
+
+
+Mutex::Mutex() {
+ pthread_mutexattr_t attr;
+ int result = pthread_mutexattr_init(&attr);
+ VALIDATE_PTHREAD_RESULT(result);
+
+#if defined(DEBUG)
+ result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
+ VALIDATE_PTHREAD_RESULT(result);
+#endif // defined(DEBUG)
+
+ result = pthread_mutex_init(data_.mutex(), &attr);
+ // Verify that creating a pthread_mutex succeeded.
+ VALIDATE_PTHREAD_RESULT(result);
+
+ result = pthread_mutexattr_destroy(&attr);
+ VALIDATE_PTHREAD_RESULT(result);
+}
+
+
+Mutex::~Mutex() {
+ int result = pthread_mutex_destroy(data_.mutex());
+ // Verify that the pthread_mutex was destroyed.
+ VALIDATE_PTHREAD_RESULT(result);
+}
+
+
+void Mutex::Lock() {
+ int result = pthread_mutex_lock(data_.mutex());
+ // Specifically check for dead lock to help debugging.
+ ASSERT(result != EDEADLK);
+ ASSERT(result == 0); // Verify no other errors.
+ // TODO(iposva): Do we need to track lock owners?
+}
+
+
+bool Mutex::TryLock() {
+ int result = pthread_mutex_trylock(data_.mutex());
+ // Return false if the lock is busy and locking failed.
+ if (result == EBUSY) {
+ return false;
+ }
+ ASSERT(result == 0); // Verify no other errors.
+ // TODO(iposva): Do we need to track lock owners?
+ return true;
+}
+
+
+void Mutex::Unlock() {
+ // TODO(iposva): Do we need to track lock owners?
+ int result = pthread_mutex_unlock(data_.mutex());
+ // Specifically check for wrong thread unlocking to aid debugging.
+ ASSERT(result != EPERM);
+ ASSERT(result == 0); // Verify no other errors.
+}
+
+
+Monitor::Monitor() {
+ pthread_mutexattr_t mutex_attr;
+ int result = pthread_mutexattr_init(&mutex_attr);
+ VALIDATE_PTHREAD_RESULT(result);
+
+#if defined(DEBUG)
+ result = pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK);
+ VALIDATE_PTHREAD_RESULT(result);
+#endif // defined(DEBUG)
+
+ result = pthread_mutex_init(data_.mutex(), &mutex_attr);
+ VALIDATE_PTHREAD_RESULT(result);
+
+ result = pthread_mutexattr_destroy(&mutex_attr);
+ VALIDATE_PTHREAD_RESULT(result);
+
+ pthread_condattr_t cond_attr;
+ result = pthread_condattr_init(&cond_attr);
+ VALIDATE_PTHREAD_RESULT(result);
+
+ result = pthread_condattr_setclock(&cond_attr, CLOCK_MONOTONIC);
+ VALIDATE_PTHREAD_RESULT(result);
+
+ result = pthread_cond_init(data_.cond(), &cond_attr);
+ VALIDATE_PTHREAD_RESULT(result);
+
+ result = pthread_condattr_destroy(&cond_attr);
+ VALIDATE_PTHREAD_RESULT(result);
+}
+
+
+Monitor::~Monitor() {
+ int result = pthread_mutex_destroy(data_.mutex());
+ VALIDATE_PTHREAD_RESULT(result);
+
+ result = pthread_cond_destroy(data_.cond());
+ VALIDATE_PTHREAD_RESULT(result);
+}
+
+
+void Monitor::Enter() {
+ int result = pthread_mutex_lock(data_.mutex());
+ VALIDATE_PTHREAD_RESULT(result);
+ // TODO(iposva): Do we need to track lock owners?
+}
+
+
+void Monitor::Exit() {
+ // TODO(iposva): Do we need to track lock owners?
+ int result = pthread_mutex_unlock(data_.mutex());
+ VALIDATE_PTHREAD_RESULT(result);
+}
+
+
+Monitor::WaitResult Monitor::Wait(int64_t millis) {
+ return WaitMicros(millis * kMicrosecondsPerMillisecond);
+}
+
+
+Monitor::WaitResult Monitor::WaitMicros(int64_t micros) {
+ // TODO(iposva): Do we need to track lock owners?
+ Monitor::WaitResult retval = kNotified;
+ if (micros == kNoTimeout) {
+ // Wait forever.
+ int result = pthread_cond_wait(data_.cond(), data_.mutex());
+ VALIDATE_PTHREAD_RESULT(result);
+ } else {
+ struct timespec ts;
+ ComputeTimeSpecMicros(&ts, micros);
+ int result = pthread_cond_timedwait(data_.cond(), data_.mutex(), &ts);
+ ASSERT((result == 0) || (result == ETIMEDOUT));
+ if (result == ETIMEDOUT) {
+ retval = kTimedOut;
+ }
+ }
+ return retval;
+}
+
+
+void Monitor::Notify() {
+ // TODO(iposva): Do we need to track lock owners?
+ int result = pthread_cond_signal(data_.cond());
+ VALIDATE_PTHREAD_RESULT(result);
+}
+
+
+void Monitor::NotifyAll() {
+ // TODO(iposva): Do we need to track lock owners?
+ int result = pthread_cond_broadcast(data_.cond());
+ VALIDATE_PTHREAD_RESULT(result);
+}
+
+} // namespace bin
+} // namespace dart
+
+#endif // defined(TARGET_OS_FUCHSIA)
diff --git a/runtime/bin/thread_fuchsia.h b/runtime/bin/thread_fuchsia.h
new file mode 100644
index 0000000..6168719
--- /dev/null
+++ b/runtime/bin/thread_fuchsia.h
@@ -0,0 +1,77 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#ifndef BIN_THREAD_FUCHSIA_H_
+#define BIN_THREAD_FUCHSIA_H_
+
+#if !defined(BIN_THREAD_H_)
+#error Do not include thread_fuchsia.h directly; use thread.h instead.
+#endif
+
+#include <pthread.h>
+
+#include "platform/assert.h"
+#include "platform/globals.h"
+
+namespace dart {
+namespace bin {
+
+typedef pthread_key_t ThreadLocalKey;
+typedef pthread_t ThreadId;
+
+class ThreadInlineImpl {
+ private:
+ ThreadInlineImpl() {}
+ ~ThreadInlineImpl() {}
+
+ static uword GetThreadLocal(ThreadLocalKey key) {
+ static ThreadLocalKey kUnsetThreadLocalKey = static_cast<pthread_key_t>(-1);
+ ASSERT(key != kUnsetThreadLocalKey);
+ return reinterpret_cast<uword>(pthread_getspecific(key));
+ }
+
+ friend class Thread;
+
+ DISALLOW_ALLOCATION();
+ DISALLOW_COPY_AND_ASSIGN(ThreadInlineImpl);
+};
+
+
+class MutexData {
+ private:
+ MutexData() {}
+ ~MutexData() {}
+
+ pthread_mutex_t* mutex() { return &mutex_; }
+
+ pthread_mutex_t mutex_;
+
+ friend class Mutex;
+
+ DISALLOW_ALLOCATION();
+ DISALLOW_COPY_AND_ASSIGN(MutexData);
+};
+
+
+class MonitorData {
+ private:
+ MonitorData() {}
+ ~MonitorData() {}
+
+ pthread_mutex_t* mutex() { return &mutex_; }
+ pthread_cond_t* cond() { return &cond_; }
+
+ pthread_mutex_t mutex_;
+ pthread_cond_t cond_;
+
+ friend class Monitor;
+
+ DISALLOW_ALLOCATION();
+ DISALLOW_COPY_AND_ASSIGN(MonitorData);
+};
+
+} // namespace bin
+} // namespace dart
+
+#endif // BIN_THREAD_FUCHSIA_H_
diff --git a/runtime/bin/utils_fuchsia.cc b/runtime/bin/utils_fuchsia.cc
new file mode 100644
index 0000000..1df2aba
--- /dev/null
+++ b/runtime/bin/utils_fuchsia.cc
@@ -0,0 +1,99 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "platform/globals.h"
+#if defined(TARGET_OS_FUCHSIA)
+
+#include <errno.h>
+#include <magenta/syscalls.h>
+#include <magenta/types.h>
+
+#include "bin/utils.h"
+#include "platform/assert.h"
+#include "platform/utils.h"
+
+namespace dart {
+namespace bin {
+
+OSError::OSError() : sub_system_(kSystem), code_(0), message_(NULL) {
+ set_sub_system(kSystem);
+ set_code(errno);
+ const int kBufferSize = 1024;
+ char error_buf[kBufferSize];
+ SetMessage(Utils::StrError(errno, error_buf, kBufferSize));
+}
+
+
+void OSError::SetCodeAndMessage(SubSystem sub_system, int code) {
+ set_sub_system(sub_system);
+ set_code(code);
+ if (sub_system == kSystem) {
+ const int kBufferSize = 1024;
+ char error_buf[kBufferSize];
+ SetMessage(Utils::StrError(code, error_buf, kBufferSize));
+ } else if (sub_system == kGetAddressInfo) {
+ UNIMPLEMENTED();
+ } else {
+ UNREACHABLE();
+ }
+}
+
+
+const char* StringUtils::ConsoleStringToUtf8(
+ const char* str, intptr_t len, intptr_t* result_len) {
+ UNIMPLEMENTED();
+ return NULL;
+}
+
+
+const char* StringUtils::Utf8ToConsoleString(
+ const char* utf8, intptr_t len, intptr_t* result_len) {
+ UNIMPLEMENTED();
+ return NULL;
+}
+
+
+char* StringUtils::ConsoleStringToUtf8(
+ char* str, intptr_t len, intptr_t* result_len) {
+ UNIMPLEMENTED();
+ return NULL;
+}
+
+
+char* StringUtils::Utf8ToConsoleString(
+ char* utf8, intptr_t len, intptr_t* result_len) {
+ UNIMPLEMENTED();
+ return NULL;
+}
+
+
+bool ShellUtils::GetUtf8Argv(int argc, char** argv) {
+ return false;
+}
+
+
+void TimerUtils::InitOnce() {
+}
+
+
+int64_t TimerUtils::GetCurrentMonotonicMillis() {
+ return GetCurrentMonotonicMicros() / 1000;
+}
+
+
+int64_t TimerUtils::GetCurrentMonotonicMicros() {
+ int64_t ticks = mx_current_time();
+ return ticks / kNanosecondsPerMicrosecond;
+}
+
+
+void TimerUtils::Sleep(int64_t millis) {
+ mx_nanosleep(
+ millis * kMicrosecondsPerMillisecond * kNanosecondsPerMicrosecond);
+}
+
+} // namespace bin
+} // namespace dart
+
+#endif // defined(TARGET_OS_FUCHSIA)
diff --git a/runtime/bin/vmservice/server.dart b/runtime/bin/vmservice/server.dart
index c8334da..4e4c54a 100644
--- a/runtime/bin/vmservice/server.dart
+++ b/runtime/bin/vmservice/server.dart
@@ -105,21 +105,64 @@
final VMService _service;
final String _ip;
final int _port;
-
+ final bool _originCheckDisabled;
+ final List<String> _allowedOrigins = <String>[];
HttpServer _server;
bool get running => _server != null;
bool _displayMessages = false;
- Server(this._service, this._ip, this._port) {
+ Server(this._service, this._ip, this._port, this._originCheckDisabled) {
_displayMessages = (_ip != '127.0.0.1' || _port != 8181);
}
- void _requestHandler(HttpRequest request) {
- // Allow cross origin requests with 'observatory' header.
- request.response.headers.add('Access-Control-Allow-Origin', '*');
- request.response.headers.add('Access-Control-Allow-Headers',
- 'Observatory-Version');
+ void _addOrigin(String host, String port) {
+ if (port == null) {
+ String origin = 'http://$host';
+ _allowedOrigins.add(origin);
+ } else {
+ String origin = 'http://$host:$port';
+ _allowedOrigins.add(origin);
+ }
+ }
+ bool _isAllowedOrigin(String origin) {
+ for (String allowedOrigin in _allowedOrigins) {
+ if (origin.startsWith(allowedOrigin)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool _originCheck(HttpRequest request) {
+ if (_originCheckDisabled) {
+ // Always allow.
+ return true;
+ }
+ // First check the web-socket specific origin.
+ List<String> origins = request.headers["Sec-WebSocket-Origin"];
+ if (origins == null) {
+ // Fall back to the general Origin field.
+ origins = request.headers["Origin"];
+ }
+ if (origins == null) {
+ // No origin sent. This is a non-browser client or a same-origin request.
+ return true;
+ }
+ for (String origin in origins) {
+ if (_isAllowedOrigin(origin)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void _requestHandler(HttpRequest request) {
+ if (!_originCheck(request)) {
+ // This is a cross origin attempt to connect
+ request.response.close();
+ return;
+ }
if (request.method != 'GET') {
// Not a GET request. Do nothing.
request.response.close();
@@ -130,8 +173,7 @@
request.uri.path == '/' ? ROOT_REDIRECT_PATH : request.uri.path;
if (path == WEBSOCKET_PATH) {
- WebSocketTransformer.upgrade(request,
- compression: CompressionOptions.OFF).then(
+ WebSocketTransformer.upgrade(request).then(
(WebSocket webSocket) {
new WebSocketClient(webSocket, _service);
});
@@ -165,6 +207,9 @@
return new Future.value(this);
}
+ // Clear allowed origins.
+ _allowedOrigins.clear();
+
var address = new InternetAddress(_ip);
// Startup HTTP server.
return HttpServer.bind(address, _port).then((s) {
@@ -172,6 +217,13 @@
_server.listen(_requestHandler, cancelOnError: true);
var ip = _server.address.address.toString();
var port = _server.port.toString();
+ // Add the numeric ip and host name to our allowed origins.
+ _addOrigin(ip, port);
+ _addOrigin(_server.address.host.toString(), port);
+ // Explicitly add localhost and 127.0.0.1 on any port (necessary for
+ // adb port forwarding).
+ _addOrigin('127.0.0.1', null);
+ _addOrigin('localhost', null);
if (_displayMessages) {
print('Observatory listening on http://$ip:$port');
}
diff --git a/runtime/bin/vmservice/vmservice_io.dart b/runtime/bin/vmservice/vmservice_io.dart
index 3e1bee4..4e5ccab 100644
--- a/runtime/bin/vmservice/vmservice_io.dart
+++ b/runtime/bin/vmservice/vmservice_io.dart
@@ -19,8 +19,10 @@
String _ip;
// Should the HTTP server auto start?
bool _autoStart;
-
+// Should the HTTP server run in devmode?
+bool _originCheckDisabled;
bool _isWindows = false;
+bool _isFuchsia = false;
var _signalWatch;
var _signalSubscription;
@@ -35,7 +37,7 @@
// Lazily create service.
var service = new VMService();
// Lazily create server.
- server = new Server(service, _ip, _port);
+ server = new Server(service, _ip, _port, _originCheckDisabled);
}
Future cleanupCallback() async {
@@ -70,13 +72,63 @@
await dir.delete(recursive: true);
}
+class PendingWrite {
+ PendingWrite(this.uri, this.bytes);
+ final Completer completer = new Completer();
+ final Uri uri;
+ final List<int> bytes;
+
+ Future write() async {
+ var file = new File.fromUri(uri);
+ var parent_directory = file.parent;
+ await parent_directory.create(recursive: true);
+ var result = await file.writeAsBytes(bytes);
+ completer.complete(null);
+ WriteLimiter._writeCompleted();
+ }
+}
+
+class WriteLimiter {
+ static final List<PendingWrite> pendingWrites = new List<PendingWrite>();
+
+ // non-rooted Android devices have a very low limit for the number of
+ // open files. Artificially cap ourselves to 16.
+ static const kMaxOpenWrites = 16;
+ static int openWrites = 0;
+
+ static Future scheduleWrite(Uri path, List<int> bytes) async {
+ // Create a new pending write.
+ PendingWrite pw = new PendingWrite(path, bytes);
+ pendingWrites.add(pw);
+ _maybeWriteFiles();
+ return pw.completer.future;
+ }
+
+ static _maybeWriteFiles() {
+ while (openWrites < kMaxOpenWrites) {
+ if (pendingWrites.length > 0) {
+ PendingWrite pw = pendingWrites.removeLast();
+ pw.write();
+ openWrites++;
+ } else {
+ break;
+ }
+ }
+ }
+
+ static _writeCompleted() {
+ openWrites--;
+ assert(openWrites >= 0);
+ _maybeWriteFiles();
+ }
+}
+
Future writeFileCallback(Uri path, List<int> bytes) async {
- var file = await new File.fromUri(path);
- await file.writeAsBytes(bytes);
+ return WriteLimiter.scheduleWrite(path, bytes);
}
Future<List<int>> readFileCallback(Uri path) async {
- var file = await new File.fromUri(path);
+ var file = new File.fromUri(path);
return await file.readAsBytes();
}
@@ -126,8 +178,8 @@
// Cannot register for signals.
return;
}
- if (_isWindows) {
- // Cannot register for signals on Windows.
+ if (_isWindows || _isFuchsia) {
+ // Cannot register for signals on Windows or Fuchsia.
return;
}
_signalSubscription = _signalWatch(ProcessSignal.SIGQUIT).listen(_onSignal);
diff --git a/runtime/bin/vmservice_dartium.cc b/runtime/bin/vmservice_dartium.cc
index 535fb41..cd40dd7 100644
--- a/runtime/bin/vmservice_dartium.cc
+++ b/runtime/bin/vmservice_dartium.cc
@@ -65,7 +65,8 @@
ASSERT(Dart_IsServiceIsolate(isolate));
if (!VmService::Setup(DEFAULT_VM_SERVICE_SERVER_IP,
DEFAULT_VM_SERVICE_SERVER_PORT,
- false /* running_precompiled */)) {
+ false /* running_precompiled */,
+ false /* disable origin checks */)) {
fprintf(stderr,
"Vmservice::Setup failed: %s\n", VmService::GetErrorMessage());
isolate = NULL;
diff --git a/runtime/bin/vmservice_impl.cc b/runtime/bin/vmservice_impl.cc
index b7f4df4..d851863 100644
--- a/runtime/bin/vmservice_impl.cc
+++ b/runtime/bin/vmservice_impl.cc
@@ -176,7 +176,8 @@
bool VmService::Setup(const char* server_ip,
intptr_t server_port,
- bool running_precompiled) {
+ bool running_precompiled,
+ bool dev_mode_server) {
Dart_Isolate isolate = Dart_CurrentIsolate();
ASSERT(isolate != NULL);
SetServerIPAndPort("", 0);
@@ -241,6 +242,9 @@
DartUtils::NewString("_autoStart"),
Dart_NewBoolean(auto_start));
SHUTDOWN_ON_ERROR(result);
+ result = Dart_SetField(library,
+ DartUtils::NewString("_originCheckDisabled"),
+ Dart_NewBoolean(dev_mode_server));
// Are we running on Windows?
#if defined(TARGET_OS_WINDOWS)
@@ -252,6 +256,16 @@
Dart_SetField(library, DartUtils::NewString("_isWindows"), is_windows);
SHUTDOWN_ON_ERROR(result);
+ // Are we running on Fuchsia?
+#if defined(TARGET_OS_FUCHSIA)
+ Dart_Handle is_fuchsia = Dart_True();
+#else
+ Dart_Handle is_fuchsia = Dart_False();
+#endif
+ result =
+ Dart_SetField(library, DartUtils::NewString("_isFuchsia"), is_fuchsia);
+ SHUTDOWN_ON_ERROR(result);
+
// Get _getWatchSignalInternal from dart:io.
Dart_Handle dart_io_str = Dart_NewStringFromCString(DartUtils::kIOLibURL);
SHUTDOWN_ON_ERROR(dart_io_str);
diff --git a/runtime/bin/vmservice_impl.h b/runtime/bin/vmservice_impl.h
index f373b4b..f499abf 100644
--- a/runtime/bin/vmservice_impl.h
+++ b/runtime/bin/vmservice_impl.h
@@ -18,7 +18,8 @@
static bool Setup(const char* server_ip,
intptr_t server_port,
- bool running_precompiled);
+ bool running_precompiled,
+ bool dev_mode_server);
// Error message if startup failed.
static const char* GetErrorMessage();
diff --git a/runtime/lib/bigint.dart b/runtime/lib/bigint.dart
index c21b04a..0c562d7 100644
--- a/runtime/lib/bigint.dart
+++ b/runtime/lib/bigint.dart
@@ -1206,9 +1206,9 @@
return r_used;
}
- int get _identityHashCode {
- return this;
- }
+ int get hashCode => this;
+ int get _identityHashCode => this;
+
int operator ~() {
return _not()._toValidInt();
}
diff --git a/runtime/lib/bool_patch.dart b/runtime/lib/bool_patch.dart
index 274b153..bbcbdb4 100644
--- a/runtime/lib/bool_patch.dart
+++ b/runtime/lib/bool_patch.dart
@@ -10,8 +10,6 @@
{bool defaultValue: false})
native "Bool_fromEnvironment";
- int get _identityHashCode {
- return this ? 1231 : 1237;
- }
- int get hashCode => _identityHashCode;
+ int get hashCode => this ? 1231 : 1237;
+ int get _identityHashCode => this ? 1231 : 1237;
}
diff --git a/runtime/lib/core_patch.dart b/runtime/lib/core_patch.dart
index 13f7513..6c792d2 100644
--- a/runtime/lib/core_patch.dart
+++ b/runtime/lib/core_patch.dart
@@ -11,13 +11,9 @@
// The members of this class are cloned and added to each class that
// represents an enum type.
class _EnumHelper {
- // Declare the list of enum value names private. When this field is
- // cloned into a user-defined enum class, the field will be inaccessible
- // because of the library-specific name suffix. The toString() function
- // below can access it because it uses the same name suffix.
- static const List<String> _enum_names = null;
- String toString() => _enum_names[index];
- int get hashCode => _enum_names[index].hashCode;
+ String _name;
+ String toString() => _name;
+ int get hashCode => _name.hashCode;
}
// _SyncIterable and _syncIterator are used by the compiler to
diff --git a/runtime/lib/developer.cc b/runtime/lib/developer.cc
index a2811ee..57a1a4c 100644
--- a/runtime/lib/developer.cc
+++ b/runtime/lib/developer.cc
@@ -34,14 +34,19 @@
DEFINE_NATIVE_ENTRY(Developer_inspect, 1) {
GET_NATIVE_ARGUMENT(Instance, inspectee, arguments->NativeArgAt(0));
+#ifndef PRODUCT
if (FLAG_support_service) {
Service::SendInspectEvent(isolate, inspectee);
}
+#endif // !PRODUCT
return inspectee.raw();
}
DEFINE_NATIVE_ENTRY(Developer_log, 8) {
+#if defined(PRODUCT)
+ return Object::null();
+#else
if (!FLAG_support_service) {
return Object::null();
}
@@ -63,10 +68,14 @@
error,
stack_trace);
return Object::null();
+#endif // PRODUCT
}
DEFINE_NATIVE_ENTRY(Developer_postEvent, 2) {
+#if defined(PRODUCT)
+ return Object::null();
+#else
if (!FLAG_support_service) {
return Object::null();
}
@@ -74,19 +83,27 @@
GET_NON_NULL_NATIVE_ARGUMENT(String, event_data, arguments->NativeArgAt(1));
Service::SendExtensionEvent(isolate, event_kind, event_data);
return Object::null();
+#endif // PRODUCT
}
DEFINE_NATIVE_ENTRY(Developer_lookupExtension, 1) {
+#if defined(PRODUCT)
+ return Object::null();
+#else
if (!FLAG_support_service) {
return Object::null();
}
GET_NON_NULL_NATIVE_ARGUMENT(String, name, arguments->NativeArgAt(0));
return isolate->LookupServiceExtensionHandler(name);
+#endif // PRODUCT
}
DEFINE_NATIVE_ENTRY(Developer_registerExtension, 2) {
+#if defined(PRODUCT)
+ return Object::null();
+#else
if (!FLAG_support_service) {
return Object::null();
}
@@ -100,6 +117,7 @@
isolate->RegisterServiceExtensionHandler(name, handler);
}
return Object::null();
+#endif // PRODUCT
}
} // namespace dart
diff --git a/runtime/lib/double.dart b/runtime/lib/double.dart
index cbf955d..ade4b93 100644
--- a/runtime/lib/double.dart
+++ b/runtime/lib/double.dart
@@ -8,10 +8,12 @@
Type get runtimeType => double;
- int get _identityHashCode {
- if (isNaN || isInfinite) return 0;
- return toInt();
- }
+ // TODO: Make a stared static method for hashCode and _identityHashCode
+ // when semantics are corrected as described in:
+ // https://github.com/dart-lang/sdk/issues/2884
+ int get hashCode => (isNaN || isInfinite) ? 0 : toInt();
+ int get _identityHashCode => (isNaN || isInfinite) ? 0 : toInt();
+
double operator +(num other) {
return _add(other.toDouble());
}
diff --git a/runtime/lib/growable_array.dart b/runtime/lib/growable_array.dart
index 016a454..271c71a 100644
--- a/runtime/lib/growable_array.dart
+++ b/runtime/lib/growable_array.dart
@@ -104,12 +104,6 @@
return new _GrowableList<T>.withData(data);
}
- factory _GrowableList.from(Iterable<T> other) {
- List<T> result = new _GrowableList<T>();
- result.addAll(other);
- return result;
- }
-
factory _GrowableList.withData(_List data)
native "GrowableList_allocate";
diff --git a/runtime/lib/integers.dart b/runtime/lib/integers.dart
index b86b71c..0c5b119 100644
--- a/runtime/lib/integers.dart
+++ b/runtime/lib/integers.dart
@@ -408,8 +408,8 @@
throw new UnsupportedError(
"_Smi can only be allocated by the VM");
}
- int get _identityHashCode => this;
int get hashCode => this;
+ int get _identityHashCode => this;
int operator ~() native "Smi_bitNegate";
int get bitLength native "Smi_bitLength";
@@ -608,8 +608,8 @@
throw new UnsupportedError(
"_Mint can only be allocated by the VM");
}
- int get _identityHashCode => this;
int get hashCode => this;
+ int get _identityHashCode => this;
int operator ~() native "Mint_bitNegate";
int get bitLength native "Mint_bitLength";
diff --git a/runtime/lib/null_patch.dart b/runtime/lib/null_patch.dart
index 61972d1..047039b 100644
--- a/runtime/lib/null_patch.dart
+++ b/runtime/lib/null_patch.dart
@@ -11,10 +11,8 @@
}
static const _HASH_CODE = 2011; // The year Dart was announced and a prime.
- int get _identityHashCode => _HASH_CODE;
int get hashCode => _HASH_CODE;
+ int get _identityHashCode => _HASH_CODE;
- String toString() {
- return 'null';
- }
+ String toString() => 'null';
}
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index b450038..e1b7a71 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -39,9 +39,12 @@
DEFINE_NATIVE_ENTRY(Object_getHash, 1) {
- const Instance& instance = Instance::CheckedHandle(arguments->NativeArgAt(0));
+ // Please note that no handle is created for the argument.
+ // This is safe since the argument is only used in a tail call.
+ // The performance benefit is more than 5% when using hashCode.
Heap* heap = isolate->heap();
- return Smi::New(heap->GetHash(instance.raw()));
+ ASSERT(arguments->NativeArgAt(0)->IsDartInstance());
+ return Smi::New(heap->GetHash(arguments->NativeArgAt(0)));
}
@@ -163,6 +166,37 @@
return Bool::Get(negate.value() ? !is_instance_of : is_instance_of).raw();
}
+DEFINE_NATIVE_ENTRY(Object_simpleInstanceOf, 2) {
+ // This native is only called when the right hand side passes
+ // simpleInstanceOfType and it is a non-negative test.
+ const Instance& instance =
+ Instance::CheckedHandle(zone, arguments->NativeArgAt(0));
+ const AbstractType& type =
+ AbstractType::CheckedHandle(zone, arguments->NativeArgAt(1));
+ const TypeArguments& instantiator_type_arguments =
+ TypeArguments::Handle(TypeArguments::null());
+ ASSERT(type.IsFinalized());
+ ASSERT(!type.IsMalformed());
+ ASSERT(!type.IsMalbounded());
+ Error& bound_error = Error::Handle(zone, Error::null());
+ const bool is_instance_of = instance.IsInstanceOf(type,
+ instantiator_type_arguments,
+ &bound_error);
+ if (!is_instance_of && !bound_error.IsNull()) {
+ // Throw a dynamic type error only if the instanceof test fails.
+ DartFrameIterator iterator;
+ StackFrame* caller_frame = iterator.NextFrame();
+ ASSERT(caller_frame != NULL);
+ const TokenPosition location = caller_frame->GetTokenPos();
+ String& bound_error_message = String::Handle(
+ zone, String::New(bound_error.ToErrorCString()));
+ Exceptions::CreateAndThrowTypeError(
+ location, AbstractType::Handle(zone), AbstractType::Handle(zone),
+ Symbols::Empty(), bound_error_message);
+ UNREACHABLE();
+ }
+ return Bool::Get(is_instance_of).raw();
+}
DEFINE_NATIVE_ENTRY(Object_instanceOfNum, 2) {
const Instance& instance =
diff --git a/runtime/lib/object_patch.dart b/runtime/lib/object_patch.dart
index 7c4f5f5..719e592 100644
--- a/runtime/lib/object_patch.dart
+++ b/runtime/lib/object_patch.dart
@@ -15,21 +15,23 @@
static _getHash(obj) native "Object_getHash";
static _setHash(obj, hash) native "Object_setHash";
- /* patch */ int get hashCode => _identityHashCode;
-
- int get _identityHashCode {
- var result = _getHash(this);
+ // Shared static implentation for hashCode and _identityHashCode.
+ static int _objectHashCode(obj) {
+ var result = _getHash(obj);
if (result == 0) {
// We want the hash to be a Smi value greater than 0.
result = _hashCodeRnd.nextInt(0x40000000);
while (result == 0) {
result = _hashCodeRnd.nextInt(0x40000000);
}
- _setHash(this, result);
+ _setHash(obj, result);
}
return result;
}
+ /* patch */ int get hashCode => _objectHashCode(this);
+ int get _identityHashCode => _objectHashCode(this);
+
/* patch */ String toString() native "Object_toString";
// A statically dispatched version of Object.toString.
static String _toString(obj) native "Object_toString";
@@ -56,6 +58,11 @@
bool _instanceOf(instantiator_type_arguments, type, bool negate)
native "Object_instanceOf";
+ // Group of functions for implementing fast simple instance of.
+ bool _simpleInstanceOf(type) native "Object_simpleInstanceOf";
+ bool _simpleInstanceOfTrue(type) => true;
+ bool _simpleInstanceOfFalse(type) => false;
+
bool _instanceOfDouble(bool negate) native "Object_instanceOfDouble";
bool _instanceOfNum(bool negate) native "Object_instanceOfNum";
bool _instanceOfInt(bool negate) native "Object_instanceOfInt";
diff --git a/runtime/lib/timeline.cc b/runtime/lib/timeline.cc
index 6923e6f..300d6e3 100644
--- a/runtime/lib/timeline.cc
+++ b/runtime/lib/timeline.cc
@@ -16,12 +16,14 @@
// Native implementations for the dart:developer library.
DEFINE_NATIVE_ENTRY(Timeline_isDartStreamEnabled, 0) {
+#ifndef PRODUCT
if (!FLAG_support_timeline) {
return Bool::False().raw();
}
if (Timeline::GetDartStream()->enabled()) {
return Bool::True().raw();
}
+#endif // !PRODUCT
return Bool::False().raw();
}
diff --git a/runtime/lib/vmservice.cc b/runtime/lib/vmservice.cc
index 831b9b8..584ceb8 100644
--- a/runtime/lib/vmservice.cc
+++ b/runtime/lib/vmservice.cc
@@ -13,6 +13,7 @@
#include "vm/native_entry.h"
#include "vm/object.h"
#include "vm/port.h"
+#include "vm/service_event.h"
#include "vm/service_isolate.h"
#include "vm/symbols.h"
@@ -450,4 +451,43 @@
#endif
}
+
+
+DEFINE_NATIVE_ENTRY(VMService_spawnUriNotify, 2) {
+#ifndef PRODUCT
+ if (!FLAG_support_service) {
+ return Object::null();
+ }
+ GET_NON_NULL_NATIVE_ARGUMENT(Instance, result, arguments->NativeArgAt(0));
+ GET_NON_NULL_NATIVE_ARGUMENT(String, token, arguments->NativeArgAt(1));
+
+ if (result.IsSendPort()) {
+ Dart_Port id = SendPort::Cast(result).Id();
+ Isolate* isolate = PortMap::GetIsolate(id);
+ if (isolate != NULL) {
+ ServiceEvent spawn_event(isolate, ServiceEvent::kIsolateSpawn);
+ spawn_event.set_spawn_token(&token);
+ Service::HandleEvent(&spawn_event);
+ } else {
+ // There is no isolate at the control port anymore. Must have
+ // died already.
+ ServiceEvent spawn_event(NULL, ServiceEvent::kIsolateSpawn);
+ const String& error = String::Handle(String::New(
+ "spawned isolate exited before notification completed"));
+ spawn_event.set_spawn_token(&token);
+ spawn_event.set_spawn_error(&error);
+ Service::HandleEvent(&spawn_event);
+ }
+ } else {
+ // The isolate failed to spawn.
+ ASSERT(result.IsString());
+ ServiceEvent spawn_event(NULL, ServiceEvent::kIsolateSpawn);
+ spawn_event.set_spawn_token(&token);
+ spawn_event.set_spawn_error(&String::Cast(result));
+ Service::HandleEvent(&spawn_event);
+ }
+#endif // PRODUCT
+ return Object::null();
+}
+
} // namespace dart
diff --git a/runtime/lib/vmservice_patch.dart b/runtime/lib/vmservice_patch.dart
index e0a85ae..498bda2 100644
--- a/runtime/lib/vmservice_patch.dart
+++ b/runtime/lib/vmservice_patch.dart
@@ -34,3 +34,5 @@
patch bool _vmListenStream(String streamId) native "VMService_ListenStream";
patch void _vmCancelStream(String streamId) native "VMService_CancelStream";
patch Uint8List _requestAssets() native "VMService_RequestAssets";
+patch void _spawnUriNotify(obj, String token)
+ native "VMService_spawnUriNotify";
diff --git a/runtime/observatory/HACKING.md b/runtime/observatory/HACKING.md
index af74bda..e8c5500 100644
--- a/runtime/observatory/HACKING.md
+++ b/runtime/observatory/HACKING.md
@@ -69,7 +69,7 @@
```
Start the script:
```
-$ dart --observe clock.dart
+$ dart --disable-service-origin-check --observe clock.dart
```
## Code Reviews
diff --git a/runtime/observatory/lib/app.dart b/runtime/observatory/lib/app.dart
index 15e802d..6212eb3 100644
--- a/runtime/observatory/lib/app.dart
+++ b/runtime/observatory/lib/app.dart
@@ -12,6 +12,9 @@
import 'package:logging/logging.dart';
import 'package:observatory/service_html.dart';
import 'package:observatory/elements.dart';
+import 'package:observatory/mocks.dart';
+import 'package:observatory/models.dart' as M;
+import 'package:observatory/repositories.dart';
import 'package:observatory/tracer.dart';
import 'package:observatory/utils.dart';
import 'package:polymer/polymer.dart';
@@ -21,6 +24,7 @@
part 'src/app/application.dart';
part 'src/app/location_manager.dart';
+part 'src/app/notification.dart';
part 'src/app/page.dart';
part 'src/app/settings.dart';
part 'src/app/target_manager.dart';
diff --git a/runtime/observatory/lib/elements.dart b/runtime/observatory/lib/elements.dart
index 9ee5cf2..e1889ac 100644
--- a/runtime/observatory/lib/elements.dart
+++ b/runtime/observatory/lib/elements.dart
@@ -10,7 +10,6 @@
export 'package:observatory/src/elements/context_ref.dart';
export 'package:observatory/src/elements/context_view.dart';
export 'package:observatory/src/elements/cpu_profile.dart';
-export 'package:observatory/src/elements/curly_block.dart';
export 'package:observatory/src/elements/debugger.dart';
export 'package:observatory/src/elements/error_view.dart';
export 'package:observatory/src/elements/eval_box.dart';
@@ -30,7 +29,6 @@
export 'package:observatory/src/elements/instructions_view.dart';
export 'package:observatory/src/elements/io_view.dart';
export 'package:observatory/src/elements/isolate_reconnect.dart';
-export 'package:observatory/src/elements/isolate_ref.dart';
export 'package:observatory/src/elements/isolate_summary.dart';
export 'package:observatory/src/elements/isolate_view.dart';
export 'package:observatory/src/elements/json_view.dart';
@@ -39,7 +37,6 @@
export 'package:observatory/src/elements/logging.dart';
export 'package:observatory/src/elements/megamorphiccache_view.dart';
export 'package:observatory/src/elements/metrics.dart';
-export 'package:observatory/src/elements/nav_bar.dart';
export 'package:observatory/src/elements/object_common.dart';
export 'package:observatory/src/elements/object_view.dart';
export 'package:observatory/src/elements/objectpool_view.dart';
@@ -53,9 +50,89 @@
export 'package:observatory/src/elements/script_view.dart';
export 'package:observatory/src/elements/service_ref.dart';
export 'package:observatory/src/elements/service_view.dart';
-export 'package:observatory/src/elements/sliding_checkbox.dart';
export 'package:observatory/src/elements/timeline_page.dart';
-export 'package:observatory/src/elements/view_footer.dart';
export 'package:observatory/src/elements/vm_connect.dart';
-export 'package:observatory/src/elements/vm_ref.dart';
export 'package:observatory/src/elements/vm_view.dart';
+
+import 'dart:async';
+
+import 'package:observatory/src/elements/curly_block.dart';
+import 'package:observatory/src/elements/curly_block_wrapper.dart';
+import 'package:observatory/src/elements/isolate_ref.dart';
+import 'package:observatory/src/elements/isolate_ref_wrapper.dart';
+import 'package:observatory/src/elements/nav/bar.dart';
+import 'package:observatory/src/elements/nav/class_menu.dart';
+import 'package:observatory/src/elements/nav/class_menu_wrapper.dart';
+import 'package:observatory/src/elements/nav/isolate_menu.dart';
+import 'package:observatory/src/elements/nav/isolate_menu_wrapper.dart';
+import 'package:observatory/src/elements/nav/library_menu.dart';
+import 'package:observatory/src/elements/nav/library_menu_wrapper.dart';
+import 'package:observatory/src/elements/nav/menu.dart';
+import 'package:observatory/src/elements/nav/menu_wrapper.dart';
+import 'package:observatory/src/elements/nav/menu_item.dart';
+import 'package:observatory/src/elements/nav/menu_item_wrapper.dart';
+import 'package:observatory/src/elements/nav/notify.dart';
+import 'package:observatory/src/elements/nav/notify_wrapper.dart';
+import 'package:observatory/src/elements/nav/notify_event.dart';
+import 'package:observatory/src/elements/nav/notify_exception.dart';
+import 'package:observatory/src/elements/nav/refresh.dart';
+import 'package:observatory/src/elements/nav/refresh_wrapper.dart';
+import 'package:observatory/src/elements/nav/top_menu.dart';
+import 'package:observatory/src/elements/nav/top_menu_wrapper.dart';
+import 'package:observatory/src/elements/nav/vm_menu.dart';
+import 'package:observatory/src/elements/nav/vm_menu_wrapper.dart';
+import 'package:observatory/src/elements/view_footer.dart';
+import 'package:observatory/src/elements/vm_connect_target.dart';
+import 'package:observatory/src/elements/vm_connect_target_wrapper.dart';
+
+export 'package:observatory/src/elements/helpers/rendering_queue.dart';
+
+export 'package:observatory/src/elements/curly_block.dart';
+export 'package:observatory/src/elements/isolate_ref.dart';
+export 'package:observatory/src/elements/nav/bar.dart';
+export 'package:observatory/src/elements/nav/class_menu.dart';
+export 'package:observatory/src/elements/nav/isolate_menu.dart';
+export 'package:observatory/src/elements/nav/library_menu.dart';
+export 'package:observatory/src/elements/nav/menu.dart';
+export 'package:observatory/src/elements/nav/menu_item.dart';
+export 'package:observatory/src/elements/nav/notify.dart';
+export 'package:observatory/src/elements/nav/notify_event.dart';
+export 'package:observatory/src/elements/nav/notify_exception.dart';
+export 'package:observatory/src/elements/nav/refresh.dart';
+export 'package:observatory/src/elements/nav/top_menu.dart';
+export 'package:observatory/src/elements/nav/vm_menu.dart';
+export 'package:observatory/src/elements/view_footer.dart';
+export 'package:observatory/src/elements/vm_connect_target.dart';
+
+// Even though this function does not invoke any asynchronous operation
+// it is marked as async to allow future backward compatible changes.
+Future initElements() async {
+ CurlyBlockElement.tag.ensureRegistration();
+ CurlyBlockElementWrapper.tag.ensureRegistration();
+ IsolateRefElement.tag.ensureRegistration();
+ IsolateRefElementWrapper.tag.ensureRegistration();
+ NavBarElement.tag.ensureRegistration();
+ NavClassMenuElement.tag.ensureRegistration();
+ NavClassMenuElementWrapper.tag.ensureRegistration();
+ NavIsolateMenuElement.tag.ensureRegistration();
+ NavIsolateMenuElementWrapper.tag.ensureRegistration();
+ NavLibraryMenuElement.tag.ensureRegistration();
+ NavLibraryMenuElementWrapper.tag.ensureRegistration();
+ NavMenuElement.tag.ensureRegistration();
+ NavMenuElementWrapper.tag.ensureRegistration();
+ NavMenuItemElement.tag.ensureRegistration();
+ NavMenuItemElementWrapper.tag.ensureRegistration();
+ NavNotifyElement.tag.ensureRegistration();
+ NavNotifyElementWrapper.tag.ensureRegistration();
+ NavNotifyEventElement.tag.ensureRegistration();
+ NavNotifyExceptionElement.tag.ensureRegistration();
+ NavRefreshElement.tag.ensureRegistration();
+ NavRefreshElementWrapper.tag.ensureRegistration();
+ NavTopMenuElement.tag.ensureRegistration();
+ NavTopMenuElementWrapper.tag.ensureRegistration();
+ NavVMMenuElement.tag.ensureRegistration();
+ NavVMMenuElementWrapper.tag.ensureRegistration();
+ ViewFooterElement.tag.ensureRegistration();
+ VMConnectTargetElement.tag.ensureRegistration();
+ VMConnectTargetElementWrapper.tag.ensureRegistration();
+}
diff --git a/runtime/observatory/lib/elements.html b/runtime/observatory/lib/elements.html
index 52b59b4..b1d51fa 100644
--- a/runtime/observatory/lib/elements.html
+++ b/runtime/observatory/lib/elements.html
@@ -5,7 +5,6 @@
<link rel="import" href="src/elements/code_ref.html">
<link rel="import" href="src/elements/code_view.html">
<link rel="import" href="src/elements/cpu_profile.html">
-<link rel="import" href="src/elements/curly_block.html">
<link rel="import" href="src/elements/debugger.html">
<link rel="import" href="src/elements/error_view.html">
<link rel="import" href="src/elements/eval_box.html">
@@ -23,7 +22,6 @@
<link rel="import" href="src/elements/icdata_view.html">
<link rel="import" href="src/elements/instructions_view.html">
<link rel="import" href="src/elements/isolate_reconnect.html">
-<link rel="import" href="src/elements/isolate_ref.html">
<link rel="import" href="src/elements/isolate_summary.html">
<link rel="import" href="src/elements/isolate_view.html">
<link rel="import" href="src/elements/json_view.html">
@@ -32,22 +30,17 @@
<link rel="import" href="src/elements/logging.html">
<link rel="import" href="src/elements/megamorphiccache_view.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">
<link rel="import" href="src/elements/object_view.html">
<link rel="import" href="src/elements/objectpool_view.html">
<link rel="import" href="src/elements/objectstore_view.html">
<link rel="import" href="src/elements/observatory_application.html">
-<link rel="import" href="src/elements/observatory_element.html">
<link rel="import" href="src/elements/persistent_handles.html">
<link rel="import" href="src/elements/ports.html">
<link rel="import" href="src/elements/script_inset.html">
<link rel="import" href="src/elements/script_ref.html">
<link rel="import" href="src/elements/script_view.html">
<link rel="import" href="src/elements/service_ref.html">
-<link rel="import" href="src/elements/sliding_checkbox.html">
<link rel="import" href="src/elements/timeline_page.html">
-<link rel="import" href="src/elements/view_footer.html">
<link rel="import" href="src/elements/vm_connect.html">
-<link rel="import" href="src/elements/vm_ref.html">
<link rel="import" href="src/elements/vm_view.html">
diff --git a/runtime/observatory/lib/mocks.dart b/runtime/observatory/lib/mocks.dart
new file mode 100644
index 0000000..18d8805
--- /dev/null
+++ b/runtime/observatory/lib/mocks.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library mocks;
+
+import 'dart:async';
+
+import 'package:observatory/models.dart' as M;
+
+part 'src/mocks/exceptions/connection_exception.dart';
+
+part 'src/mocks/objects/error.dart';
+part 'src/mocks/objects/event.dart';
+part 'src/mocks/objects/class.dart';
+part 'src/mocks/objects/isolate.dart';
+part 'src/mocks/objects/library.dart';
+part 'src/mocks/objects/notification.dart';
+part 'src/mocks/objects/script.dart';
+part 'src/mocks/objects/source_location.dart';
+part 'src/mocks/objects/target.dart';
+part 'src/mocks/objects/vm.dart';
+
+part 'src/mocks/repositories/notification.dart';
diff --git a/runtime/observatory/lib/models.dart b/runtime/observatory/lib/models.dart
new file mode 100644
index 0000000..c047e9c
--- /dev/null
+++ b/runtime/observatory/lib/models.dart
@@ -0,0 +1,28 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library models;
+
+import 'dart:async';
+
+part 'src/models/exceptions.dart';
+
+part 'src/models/objects/class.dart';
+part 'src/models/objects/breakpoint.dart';
+part 'src/models/objects/error.dart';
+part 'src/models/objects/event.dart';
+part 'src/models/objects/extension_data.dart';
+part 'src/models/objects/frame.dart';
+part 'src/models/objects/instance.dart';
+part 'src/models/objects/isolate.dart';
+part 'src/models/objects/library.dart';
+part 'src/models/objects/notification.dart';
+part 'src/models/objects/object.dart';
+part 'src/models/objects/script.dart';
+part 'src/models/objects/source_location.dart';
+part 'src/models/objects/target.dart';
+part 'src/models/objects/timeline_event.dart';
+part 'src/models/objects/vm.dart';
+
+part 'src/models/repositories/notification.dart';
diff --git a/runtime/observatory/lib/repositories.dart b/runtime/observatory/lib/repositories.dart
new file mode 100644
index 0000000..5e333ad
--- /dev/null
+++ b/runtime/observatory/lib/repositories.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library repositories;
+
+import 'dart:async';
+import 'package:observatory/models.dart' as M;
+
+part 'src/repositories/notification.dart';
diff --git a/runtime/observatory/lib/service.dart b/runtime/observatory/lib/service.dart
index cb6f317..c3775a3 100644
--- a/runtime/observatory/lib/service.dart
+++ b/runtime/observatory/lib/service.dart
@@ -11,6 +11,7 @@
import 'package:logging/logging.dart';
import 'package:observatory/cpu_profile.dart';
+import 'package:observatory/models.dart' as M;
import 'package:observatory/object_graph.dart';
import 'package:observatory/tracer.dart';
import 'package:observe/observe.dart';
diff --git a/runtime/observatory/lib/service_common.dart b/runtime/observatory/lib/service_common.dart
index ba55349..8e7b5c0 100644
--- a/runtime/observatory/lib/service_common.dart
+++ b/runtime/observatory/lib/service_common.dart
@@ -9,13 +9,14 @@
import 'dart:typed_data';
import 'package:logging/logging.dart';
+import 'package:observatory/models.dart' as M;
import 'package:observatory/service.dart';
// Export the service library.
export 'package:observatory/service.dart';
/// Description of a VM target.
-class WebSocketVMTarget {
+class WebSocketVMTarget implements M.Target {
// Last time this VM has been connected to.
int lastConnectionTime = 0;
bool get hasEverConnected => lastConnectionTime > 0;
diff --git a/runtime/observatory/lib/src/app/application.dart b/runtime/observatory/lib/src/app/application.dart
index be95803..b37eda2 100644
--- a/runtime/observatory/lib/src/app/application.dart
+++ b/runtime/observatory/lib/src/app/application.dart
@@ -4,19 +4,12 @@
part of app;
-class Notification {
- Notification.fromEvent(this.event);
- Notification.fromException(this.exception, this.stacktrace);
-
- ServiceEvent event;
- var exception;
- var stacktrace;
-}
-
/// The observatory application. Instances of this are created and owned
/// by the observatory_application custom element.
class ObservatoryApplication extends Observable {
static ObservatoryApplication app;
+ final RenderingQueue queue = new RenderingQueue();
+ final NotificationRepository notifications = new NotificationRepository();
final _pageRegistry = new List<Page>();
LocationManager _locationManager;
LocationManager get locationManager => _locationManager;
@@ -31,7 +24,7 @@
}
if (_vm != null) {
// Disconnect from current VM.
- notifications.clear();
+ notifications.deleteAll();
_vm.disconnect();
}
if (vm != null) {
@@ -41,7 +34,7 @@
if (vm is WebSocketVM) {
targets.add(vm.target);
}
- _removeDisconnectEvents();
+ notifications.deleteDisconnectEvents();
});
vm.onDisconnect.then((String reason) {
@@ -50,8 +43,8 @@
return;
}
notifications.add(
- new Notification.fromEvent(
- new ServiceEvent.connectionClosed(reason)));
+ new EventNotification.fromServiceEvent(
+ new ServiceEvent.connectionClosed(reason)));
});
vm.listenEventStream(VM.kIsolateStream, _onEvent);
@@ -65,8 +58,6 @@
TraceViewElement _traceView = null;
@reflectable ServiceObject lastErrorOrException;
- @observable ObservableList<Notification> notifications =
- new ObservableList<Notification>();
void _initOnce() {
assert(app == null);
@@ -77,15 +68,6 @@
locationManager._visit();
}
- void removePauseEvents(Isolate isolate) {
- notifications.removeWhere((notification) {
- var event = notification.event;
- return (event != null &&
- event.isolate == isolate &&
- event.isPauseEvent);
- });
- }
-
void _onEvent(ServiceEvent event) {
assert(event.kind != ServiceEvent.kNone);
@@ -102,12 +84,12 @@
break;
case ServiceEvent.kIsolateReload:
- notifications.add(new Notification.fromEvent(event));
+ notifications.add(new EventNotification.fromServiceEvent(event));
break;
case ServiceEvent.kIsolateExit:
case ServiceEvent.kResume:
- removePauseEvents(event.isolate);
+ notifications.deletePauseEvents(isolate: event.isolate);
break;
case ServiceEvent.kPauseStart:
@@ -115,12 +97,12 @@
case ServiceEvent.kPauseBreakpoint:
case ServiceEvent.kPauseInterrupted:
case ServiceEvent.kPauseException:
- removePauseEvents(event.isolate);
- notifications.add(new Notification.fromEvent(event));
+ notifications.deletePauseEvents(isolate: event.isolate);
+ notifications.add(new EventNotification.fromServiceEvent(event));
break;
case ServiceEvent.kInspect:
- notifications.add(new Notification.fromEvent(event));
+ notifications.add(new EventNotification.fromServiceEvent(event));
break;
default:
@@ -219,14 +201,6 @@
_initOnce();
}
- void _removeDisconnectEvents() {
- notifications.removeWhere((notification) {
- var event = notification.event;
- return (event != null &&
- event.kind == ServiceEvent.kConnectionClosed);
- });
- }
-
loadCrashDump(Map crashDump) {
this.vm = new FakeVM(crashDump['result']);
app.locationManager.go('#/vm');
@@ -242,7 +216,7 @@
// TODO(turnidge): Report this failure via analytics.
Logger.root.warning('Caught exception: ${e}\n${st}');
- notifications.add(new Notification.fromException(e, st));
+ notifications.add(new ExceptionNotification(e, stacktrace: st));
}
// This map keeps track of which curly-blocks have been expanded by the user.
diff --git a/runtime/observatory/lib/src/app/location_manager.dart b/runtime/observatory/lib/src/app/location_manager.dart
index 577cb92..64ea764 100644
--- a/runtime/observatory/lib/src/app/location_manager.dart
+++ b/runtime/observatory/lib/src/app/location_manager.dart
@@ -54,6 +54,11 @@
/// Update the application location. After this function returns,
/// [uri] and [debugArguments] will be updated.
_updateApplicationLocation(String url) {
+ if (url == makeLink('/vm-connect')) {
+ // When we go to the vm-connect page, drop all notifications.
+ _app.notifications.deleteAll();
+ }
+
// Chop off leading '#'.
if (url.startsWith('#')) {
url = url.substring(1);
@@ -115,11 +120,6 @@
url = makeLink('/vm-connect');
}
- if (url == makeLink('/vm-connect')) {
- // When we go to the vm-connect page, drop all notifications.
- _app.notifications.clear();
- }
-
if (addToBrowserHistory) {
_addToBrowserHistory(url);
}
diff --git a/runtime/observatory/lib/src/app/notification.dart b/runtime/observatory/lib/src/app/notification.dart
new file mode 100644
index 0000000..b95c34e
--- /dev/null
+++ b/runtime/observatory/lib/src/app/notification.dart
@@ -0,0 +1,115 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of app;
+
+class ExceptionNotification implements M.ExceptionNotification {
+ final Exception exception;
+ /// [optional]
+ final StackTrace stacktrace;
+ ExceptionNotification(this.exception, {this.stacktrace});
+}
+
+class EventNotification implements M.EventNotification {
+ final M.Event event;
+ EventNotification(this.event);
+ factory EventNotification.fromServiceEvent(ServiceEvent event) {
+ M.Event e;
+ switch(event.kind) {
+ case ServiceEvent.kVMUpdate:
+ e = new VMUpdateEventMock(timestamp: event.timestamp, vm: event.vm);
+ break;
+ case ServiceEvent.kIsolateStart:
+ e = new IsolateStartEventMock(timestamp: event.timestamp,
+ isolate: event.isolate);
+ break;
+ case ServiceEvent.kIsolateRunnable:
+ e = new IsolateRunnableEventMock(timestamp: event.timestamp,
+ isolate: event.isolate);
+ break;
+ case ServiceEvent.kIsolateExit:
+ e = new IsolateExitEventMock(timestamp: event.timestamp,
+ isolate: event.isolate);
+ break;
+ case ServiceEvent.kIsolateUpdate:
+ e = new IsolateUpdateEventMock(timestamp: event.timestamp,
+ isolate: event.isolate);
+ break;
+ case ServiceEvent.kIsolateReload:
+ // TODO(bernaschina) add error: realoadError.
+ e = new IsolateRealodEventMock(timestamp: event.timestamp,
+ isolate: event.isolate);
+ break;
+ case ServiceEvent.kServiceExtensionAdded:
+ e = new ServiceExtensionAddedEventMock(timestamp: event.timestamp,
+ isolate: event.isolate, extensionRPC: event.extensionRPC);
+ break;
+ case ServiceEvent.kPauseStart:
+ e = new PauseStartEventMock(timestamp: event.timestamp,
+ isolate: event.isolate);
+ break;
+ case ServiceEvent.kPauseExit:
+ e = new PauseExitEventMock(timestamp: event.timestamp,
+ isolate: event.isolate);
+ break;
+ case ServiceEvent.kPauseBreakpoint:
+ // TODO(cbernaschina) add pauseBreakpoints.
+ e = new PauseBreakpointEventMock(timestamp: event.timestamp,
+ isolate: event.isolate, breakpoint: event.breakpoint,
+ pauseBreakpoints: const <M.Breakpoint>[],
+ topFrame: event.topFrame,
+ atAsyncSuspension: event.atAsyncSuspension);
+ break;
+ case ServiceEvent.kPauseInterrupted:
+ e = new PauseInterruptedEventMock(timestamp: event.timestamp,
+ isolate: event.isolate, topFrame: event.topFrame,
+ atAsyncSuspension: event.atAsyncSuspension);
+ break;
+ case ServiceEvent.kPauseException:
+ // TODO(cbernaschina) add exception.
+ e = new PauseExceptionEventMock(timestamp: event.timestamp,
+ isolate: event.isolate, topFrame: event.topFrame);
+ break;
+ case ServiceEvent.kNone:
+ e = new NoneEventMock(timestamp: event.timestamp,
+ isolate: event.isolate);
+ break;
+ case ServiceEvent.kResume:
+ e = new ResumeEventMock(timestamp: event.timestamp,
+ isolate: event.isolate);
+ break;
+ case ServiceEvent.kBreakpointAdded:
+ e = new BreakpointAddedEventMock(timestamp: event.timestamp,
+ isolate: event.isolate, breakpoint: event.breakpoint);
+ break;
+ case ServiceEvent.kBreakpointResolved:
+ e = new BreakpointResolvedEventMock(timestamp: event.timestamp,
+ isolate: event.isolate, breakpoint: event.breakpoint);
+ break;
+ case ServiceEvent.kBreakpointRemoved:
+ e = new BreakpointRemovedEventMock(timestamp: event.timestamp,
+ isolate: event.isolate, breakpoint: event.breakpoint);
+ break;
+ case ServiceEvent.kGC:
+ e = new GCEventMock(timestamp: event.timestamp,
+ isolate: event.isolate);
+ break;
+ case ServiceEvent.kInspect:
+ // TODO(cbernaschina) add inspectee: event.inspectee.
+ e = new InspectEventMock(timestamp: event.timestamp,
+ isolate: event.isolate);
+ break;
+ case ServiceEvent.kConnectionClosed:
+ e = new ConnectionClockedEventMock(timestamp: event.timestamp,
+ reason: event.reason);
+ break;
+ case ServiceEvent.kExtension:
+ e = new ExtensionEventMock(timestamp: event.timestamp,
+ isolate: event.isolate, extensionKind: event.extensionKind,
+ extensionData: event.extensionData);
+ break;
+ }
+ return new EventNotification(e);
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/action_link.html b/runtime/observatory/lib/src/elements/action_link.html
index 46ced34..1b0438b 100644
--- a/runtime/observatory/lib/src/elements/action_link.html
+++ b/runtime/observatory/lib/src/elements/action_link.html
@@ -1,8 +1,8 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
<link rel="import" href="instance_ref.html">
-<link rel="import" href="observatory_element.html">
-<polymer-element name="action-link" extends="observatory-element">
+
+<polymer-element name="action-link">
<template>
<style>
.idle {
diff --git a/runtime/observatory/lib/src/elements/class_ref.html b/runtime/observatory/lib/src/elements/class_ref.html
index c3ddec7..1ffe1d1 100644
--- a/runtime/observatory/lib/src/elements/class_ref.html
+++ b/runtime/observatory/lib/src/elements/class_ref.html
@@ -1,9 +1,8 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="curly_block.html">
-<link rel="import" href="observatory_element.html">
+
<link rel="import" href="service_ref.html">
-<polymer-element name="class-ref" extends="service-ref">
+<polymer-element name="class-ref">
<template>
<link rel="stylesheet" href="css/shared.css">
<style>
diff --git a/runtime/observatory/lib/src/elements/class_tree.html b/runtime/observatory/lib/src/elements/class_tree.html
index c1e9635..94e43f7 100644
--- a/runtime/observatory/lib/src/elements/class_tree.html
+++ b/runtime/observatory/lib/src/elements/class_tree.html
@@ -1,9 +1,7 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="nav_bar.html">
-<link rel="import" href="observatory_element.html">
<link rel="import" href="class_ref.html">
-<polymer-element name="class-tree" extends="observatory-element">
+<polymer-element name="class-tree">
<template>
<link rel="stylesheet" href="css/shared.css">
<style>
@@ -31,6 +29,7 @@
<vm-nav-menu vm="{{ isolate.vm }}"></vm-nav-menu>
<isolate-nav-menu isolate="{{ isolate }}"></isolate-nav-menu>
<nav-menu link="{{ makeLink('/class-tree', isolate) }}" anchor="class hierarchy" last="{{ true }}"></nav-menu>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content-centered">
<h1>Class Hierarchy</h1>
diff --git a/runtime/observatory/lib/src/elements/class_view.html b/runtime/observatory/lib/src/elements/class_view.html
index 086b96b..df003cd 100644
--- a/runtime/observatory/lib/src/elements/class_view.html
+++ b/runtime/observatory/lib/src/elements/class_view.html
@@ -1,20 +1,16 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
<link rel="import" href="action_link.html">
<link rel="import" href="cpu_profile.html">
-<link rel="import" href="curly_block.html">
<link rel="import" href="eval_box.html">
<link rel="import" href="eval_link.html">
<link rel="import" href="field_ref.html">
<link rel="import" href="function_ref.html">
<link rel="import" href="instance_ref.html">
<link rel="import" href="library_ref.html">
-<link rel="import" href="nav_bar.html">
-<link rel="import" href="observatory_element.html">
<link rel="import" href="script_inset.html">
<link rel="import" href="script_ref.html">
-<link rel="import" href="view_footer.html">
-<polymer-element name="class-view" extends="observatory-element">
+<polymer-element name="class-view">
<template>
<link rel="stylesheet" href="css/shared.css">
<nav-bar>
@@ -25,6 +21,7 @@
<class-nav-menu cls="{{ cls }}" last="{{ true }}"></class-nav-menu>
<nav-refresh callback="{{ refreshAllocationProfile }}" label="Refresh Allocation Profile"></nav-refresh>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content">
diff --git a/runtime/observatory/lib/src/elements/code_ref.html b/runtime/observatory/lib/src/elements/code_ref.html
index c20fdb5..4a8c7f5 100644
--- a/runtime/observatory/lib/src/elements/code_ref.html
+++ b/runtime/observatory/lib/src/elements/code_ref.html
@@ -1,7 +1,7 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
<link rel="import" href="service_ref.html">
-<polymer-element name="code-ref" extends="service-ref">
+<polymer-element name="code-ref">
<template><link rel="stylesheet" href="css/shared.css"></template>
</polymer-element>
diff --git a/runtime/observatory/lib/src/elements/code_view.html b/runtime/observatory/lib/src/elements/code_view.html
index 95f71e2..10e280c 100644
--- a/runtime/observatory/lib/src/elements/code_view.html
+++ b/runtime/observatory/lib/src/elements/code_view.html
@@ -1,12 +1,9 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
<link rel="import" href="function_ref.html">
<link rel="import" href="instance_ref.html">
-<link rel="import" href="observatory_element.html">
-<link rel="import" href="nav_bar.html">
<link rel="import" href="script_ref.html">
-<link rel="import" href="view_footer.html">
-<polymer-element name="code-view" extends="observatory-element">
+<polymer-element name="code-view">
<template>
<link rel="stylesheet" href="css/shared.css">
<style>
@@ -59,6 +56,7 @@
<nav-menu link="{{ makeLink('/inspect', code) }}" anchor="{{ code.name }}" last="{{ true }}"></nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
<nav-refresh callback="{{ refreshTicks }}" label="Refresh Ticks"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content">
<template if="{{ code.isDartCode && code.isOptimized }}">
diff --git a/runtime/observatory/lib/src/elements/context_ref.html b/runtime/observatory/lib/src/elements/context_ref.html
index 82e313d..9beb691 100644
--- a/runtime/observatory/lib/src/elements/context_ref.html
+++ b/runtime/observatory/lib/src/elements/context_ref.html
@@ -1,9 +1,8 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="curly_block.html">
-<link rel="import" href="observatory_element.html">
+
<link rel="import" href="service_ref.html">
-<polymer-element name="context-ref" extends="service-ref">
+<polymer-element name="context-ref">
<template>
<link rel="stylesheet" href="css/shared.css">
<span>
diff --git a/runtime/observatory/lib/src/elements/context_view.html b/runtime/observatory/lib/src/elements/context_view.html
index 44972f3..f9a2fbf 100644
--- a/runtime/observatory/lib/src/elements/context_view.html
+++ b/runtime/observatory/lib/src/elements/context_view.html
@@ -3,13 +3,10 @@
<link rel="import" href="field_ref.html">
<link rel="import" href="function_ref.html">
<link rel="import" href="instance_ref.html">
-<link rel="import" href="observatory_element.html">
-<link rel="import" href="nav_bar.html">
<link rel="import" href="object_common.html">
<link rel="import" href="context_ref.html">
-<link rel="import" href="view_footer.html">
-<polymer-element name="context-view" extends="observatory-element">
+<polymer-element name="context-view">
<template>
<link rel="stylesheet" href="css/shared.css">
<nav-bar>
@@ -20,6 +17,7 @@
<class-nav-menu cls="{{ context.clazz }}"></class-nav-menu>
<nav-menu link="." anchor="instance" last="{{ true }}"></nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<template if="{{ !context.isError }}">
diff --git a/runtime/observatory/lib/src/elements/cpu_profile.html b/runtime/observatory/lib/src/elements/cpu_profile.html
index 50db2db..05fc581 100644
--- a/runtime/observatory/lib/src/elements/cpu_profile.html
+++ b/runtime/observatory/lib/src/elements/cpu_profile.html
@@ -1,12 +1,8 @@
<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="sample-buffer-control" extends="observatory-element">
+<polymer-element name="sample-buffer-control">
<template>
<link rel="stylesheet" href="css/shared.css">
<style>
@@ -115,7 +111,7 @@
</template>
</polymer-element>
-<polymer-element name="stack-trace-tree-config" extends="observatory-element">
+<polymer-element name="stack-trace-tree-config">
<template>
<link rel="stylesheet" href="css/shared.css">
<style>
@@ -182,7 +178,7 @@
</template>
</polymer-element>
-<polymer-element name="cpu-profile-tree" extends="observatory-element">
+<polymer-element name="cpu-profile-tree">
<template>
<link rel="stylesheet" href="css/shared.css">
<style>
@@ -254,7 +250,7 @@
</template>
</polymer-element>
-<polymer-element name="cpu-profile-virtual-tree" extends="observatory-element">
+<polymer-element name="cpu-profile-virtual-tree">
<template>
<link rel="stylesheet" href="css/shared.css">
<style>
@@ -277,7 +273,7 @@
</polymer-element>
-<polymer-element name="cpu-profile-table" extends="observatory-element">
+<polymer-element name="cpu-profile-table">
<template>
<link rel="stylesheet" href="css/shared.css">
<nav-bar>
@@ -287,6 +283,7 @@
<nav-menu link="{{ makeLink('/profiler-table', isolate) }}" anchor="cpu profile (table)" last="{{ true }}"></nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
<nav-refresh callback="{{ clearCpuProfile }}" label="Clear"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<style>
/* general */
@@ -491,7 +488,7 @@
</template>
</polymer-element>
-<polymer-element name="cpu-profile" extends="observatory-element">
+<polymer-element name="cpu-profile">
<template>
<link rel="stylesheet" href="css/shared.css">
<nav-bar>
@@ -501,6 +498,7 @@
<nav-menu link="{{ makeLink('/profiler', isolate) }}" anchor="cpu profile" last="{{ true }}"></nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
<nav-refresh callback="{{ clearCpuProfile }}" label="Clear"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<style>
.tableWell {
diff --git a/runtime/observatory/lib/src/elements/css/shared.css b/runtime/observatory/lib/src/elements/css/shared.css
index 3442d98..75b35ce 100644
--- a/runtime/observatory/lib/src/elements/css/shared.css
+++ b/runtime/observatory/lib/src/elements/css/shared.css
@@ -7,6 +7,10 @@
box-sizing: border-box;
}
+body {
+ padding-top: 56px;
+}
+
.content {
padding-left: 10%;
font: 400 14px 'Montserrat', sans-serif;
@@ -354,3 +358,131 @@
animation: shake 0.5s;
-webkit-animation: shake 0.5s;
}
+
+/* nav-notify */
+/* TODO(cbernaschina) fix nav-notify-ref-wrapped to nav-notify-ref when wrapper
+removed */
+nav-notify-wrapped > div {
+ float: right;
+}
+nav-notify-wrapped > div > div {
+ display: block;
+ position: absolute;
+ top: 98%;
+ right: 0;
+ margin: 0;
+ padding: 0;
+ width: auto;
+ z-index: 1000;
+ background: none;
+}
+
+/* nav-exception & nav-event */
+
+nav-exception > div, nav-event > div {
+ position: relative;
+ padding: 16px;
+ margin-top: 10px;
+ margin-right: 10px;
+ padding-right: 25px;
+ width: 500px;
+ color: #ddd;
+ background: rgba(0,0,0,.6);
+ border: solid 2px white;
+ box-shadow: 0 0 5px black;
+ border-radius: 5px;
+ animation: fadein 1s;
+}
+
+nav-exception *, nav-event * {
+ color: #ddd;
+ font-size: 12px;
+}
+
+nav-exception > div > a, nav-event > div > a {
+ color: white;
+ text-decoration: none;
+}
+
+nav-exception > div > a:hover, nav-event > div > a:hover {
+ text-decoration: underline;
+}
+
+nav-exception > div > div {
+ margin-left:20px;
+ white-space: pre
+}
+
+nav-exception > div > button, nav-event > div > button {
+ background: transparent;
+ border: none;
+ position: absolute;
+ display: block;
+ top: 4px;
+ right: 4px;
+ height: 18px;
+ width: 18px;
+ line-height: 16px;
+ border-radius: 9px;
+ color: white;
+ font-size: 18px;
+ cursor: pointer;
+ text-align: center;
+}
+
+nav-exception > div > button:hover, nav-event > div > button:hover {
+ background: rgba(255,255,255,0.5);
+}
+
+/* nav-refresh */
+/* TODO(cbernaschina) fix nav-refresh-wrapped to nav-refresh when wrapper
+removed */
+
+nav-refresh-wrapped > li > button {
+ color: #000;
+ margin: 3px;
+ padding: 8px;
+ border-width: 2px;
+ line-height: 13px;
+ font: 400 13px 'Montserrat', sans-serif;
+}
+nav-refresh-wrapped > li > button[disabled] {
+ color: #aaa;
+ cursor: wait;
+}
+nav-refresh-wrapped > li {
+ float: right;
+ margin: 0;
+}
+
+/* view-footer */
+
+view-footer {
+ padding: 1em;
+ padding-top: 10.3em;
+ float: right;
+ align-content: right;
+}
+
+view-footer > a {
+ margin-bottom: 0.17em;
+ font-size: 90%;
+ float: right;
+ clear: both;
+ display: block;
+}
+
+/* vm-connect-target */
+/* TODO(cbernaschina) fix vm-connect-target-wrapped to vm-connect-target
++when wrapper removed */
+
+vm-connect-target-wrapped > button.delete-button {
+ margin-left: 0.28em;
+ padding: 4px;
+ background: transparent;
+ border: none !important;
+}
+
+vm-connect-target-wrapped > button.delete-button:hover {
+ background: #ff0000;
+}
diff --git a/runtime/observatory/lib/src/elements/curly_block.dart b/runtime/observatory/lib/src/elements/curly_block.dart
index 004a02e..9eadd76 100644
--- a/runtime/observatory/lib/src/elements/curly_block.dart
+++ b/runtime/observatory/lib/src/elements/curly_block.dart
@@ -4,52 +4,104 @@
library curly_block_element;
-import 'package:polymer/polymer.dart';
-import 'observatory_element.dart';
+import 'dart:async';
+import 'dart:html';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
-@CustomTag('curly-block')
-class CurlyBlockElement extends ObservatoryElement {
- CurlyBlockElement.created() : super.created();
+class CurlyBlockToggleEvent {
+ final CurlyBlockElement control;
- @observable bool expanded = false;
- @observable bool busy = false;
- @published var callback = null;
- @published bool expand = false;
- @published String expandKey;
+ CurlyBlockToggleEvent(this.control);
+}
- void expandChanged(oldValue) {
- expanded = expand;
+class CurlyBlockElement extends HtmlElement implements Renderable {
+ static final StyleElement _style = () {
+ var style = new StyleElement();
+ style.text = '''span.curly-block {
+ color: #0489c3;
+ cursor: pointer;
+ }
+ span.curly-block.disabled {
+ color: white;
+ cursor: wait;
+ }''';
+ return style;
+ }();
+
+ static const tag = const Tag<CurlyBlockElement>('curly-block-wrapped');
+
+ RenderingScheduler<CurlyBlockElement> _r;
+
+ final StreamController<CurlyBlockToggleEvent> _onToggle =
+ new StreamController<CurlyBlockToggleEvent>.broadcast();
+ Stream<CurlyBlockToggleEvent> get onToggle => _onToggle.stream;
+ Stream<RenderedEvent<CurlyBlockElement>> get onRendered => _r.onRendered;
+
+ bool _expanded;
+ bool _disabled;
+
+ bool get expanded => _expanded;
+ set expanded(bool value) {
+ if (_expanded != value) _onToggle.add(new CurlyBlockToggleEvent(this));
+ _expanded = _r.checkAndReact(_expanded, value);
+ }
+ bool get disabled => _disabled;
+ set disabled(bool value) => _disabled = _r.checkAndReact(_disabled, value);
+
+ factory CurlyBlockElement({bool expanded: false, bool disabled: false,
+ RenderingQueue queue}) {
+ assert(expanded != null);
+ assert(disabled != null);
+ CurlyBlockElement e = document.createElement(tag.name);
+ e._r = new RenderingScheduler(e, queue: queue);
+ e._expanded = expanded;
+ e._disabled = disabled;
+ return e;
}
- void expandKeyChanged(oldValue) {
- if (expandKey != null) {
- var value = app.expansions[expandKey];
- if (value != null) {
- if (expanded != value) {
- toggleExpand(null, null, null);
- }
- }
- }
+ CurlyBlockElement.created() : super.created() { createShadowRoot(); }
+
+ @override
+ void attached() { super.attached(); _r.enable(); }
+
+ @override
+ void detached() {
+ super.detached(); _r.disable(notify: true);
+ shadowRoot.children = [];
}
- 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);
- if (busy) {
+ void toggle() {
+ if (disabled) {
+ _r.scheduleNotification();
return;
}
- busy = true;
- if (callback != null) {
- callback(!expanded, doneCallback);
+ expanded = !expanded;
+ }
+
+ void render() {
+ List<Element> children = [
+ _style.clone(true),
+ new SpanElement()..text = '{'
+ ];
+ SpanElement label = new SpanElement()
+ ..classes = disabled ? ['curly-block', 'disabled'] : ['curly-block']
+ ..innerHtml = expanded ?
+ ' ⊟ ' : ' ⊞ ';
+ if (disabled) {
+ children.add(label);
} else {
- doneCallback();
+ children.add(new AnchorElement()
+ ..onClick.listen((_) { toggle(); })
+ ..children = [label]);
}
+ if (expanded) {
+ children.addAll([
+ new BRElement(),
+ new ContentElement()
+ ]);
+ }
+ children.add(new SpanElement()..text = '}');
+ shadowRoot.children = children;
}
}
diff --git a/runtime/observatory/lib/src/elements/curly_block.html b/runtime/observatory/lib/src/elements/curly_block.html
deleted file mode 100644
index d1702a2..0000000
--- a/runtime/observatory/lib/src/elements/curly_block.html
+++ /dev/null
@@ -1,44 +0,0 @@
-<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="observatory_element.html">
-
-<polymer-element name="curly-block" extends="observatory-element">
- <template>
- <style>
- .idle {
- display: inline-block;
- color: #0489c3;
- cursor: pointer;
- }
- .busy {
- display: inline-block;
- color: white;
- cursor: wait;
- }
- </style>
- <template if="{{ expanded }}">
- <template if="{{ busy }}">
- {<div class="busy"> ⊟ </div>
- <br>
- <content></content>
- }
- </template>
- <template if="{{ !busy }}">
- {<a on-click="{{ toggleExpand }}"><div class="idle"> ⊟ </div></a>
- <br>
- <content></content>
- }
- </template>
- </template>
-
- <template if="{{ !expanded }}">
- <template if="{{ busy }}">
- {<div class="busy"> ⊞ </div>}
- </template>
- <template if="{{ !busy }}">
- {<a on-click="{{ toggleExpand }}"><div class="idle"> ⊞ </div></a>}
- </template>
- </template>
- </template>
-</polymer-element>
-
-<script type="application/dart" src="curly_block.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/curly_block_wrapper.dart b/runtime/observatory/lib/src/elements/curly_block_wrapper.dart
new file mode 100644
index 0000000..2a141b5
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/curly_block_wrapper.dart
@@ -0,0 +1,100 @@
+// 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:html';
+
+import 'package:observatory/app.dart';
+import 'package:observatory/src/elements/curly_block.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/shims/binding.dart';
+
+typedef _callback();
+typedef CurlyBlockToggleCallback(bool a, _callback b);
+
+class CurlyBlockElementWrapper extends HtmlElement {
+
+ static final binder = new Binder<CurlyBlockElementWrapper>(
+ const [const Binding('expand'), const Binding('busy'),
+ const Binding('expandKey'), const Binding('callback')]);
+
+ static const tag = const Tag<CurlyBlockElementWrapper>('curly-block');
+
+ bool _expand;
+ bool get expand => _expand;
+ set expand(bool expanded) {
+ _expand = !(expanded == null || expanded == false);
+ render();
+ }
+
+ bool _busy;
+ bool get busy => _busy;
+ set busy(bool busy) {
+ _busy = !(busy == null || busy == false);
+ render();
+ }
+
+ String _expandKey;
+ String get expandKey => _expandKey;
+ set expandKey(String expandKey) {
+ _expandKey = expandKey;
+ if (expandKey != null) {
+ var value = application.expansions[expandKey];
+ if (value != null && expand != value) {
+
+ }
+ }
+ render();
+ }
+
+ CurlyBlockToggleCallback _callback;
+ CurlyBlockToggleCallback get callback => _callback;
+ set callback(CurlyBlockToggleCallback callback) {
+ _callback = callback;
+ render();
+ }
+
+ CurlyBlockElementWrapper.created() : super.created() {
+ binder.registerCallback(this);
+ createShadowRoot();
+ _expand = !_isFalseOrNull(getAttribute('expand'));
+ _busy = !_isFalseOrNull(getAttribute('busy'));
+ _expandKey = getAttribute('expandKey');
+ }
+
+ @override
+ void attached() {
+ super.attached();
+ render();
+ }
+
+ void render() {
+ shadowRoot.children = [
+ new CurlyBlockElement(expanded: expand, disabled: busy,
+ queue: ObservatoryApplication.app.queue)
+ ..children = [new ContentElement()]
+ ..onToggle.listen(_toggle)
+ ];
+ }
+
+ ObservatoryApplication get application => ObservatoryApplication.app;
+
+ void _toggle(CurlyBlockToggleEvent e) {
+ _expand = e.control.expanded;
+ if (callback != null) {
+ busy = true;
+ callback(expand, () {
+ if (expandKey != null) {
+ application.expansions[expandKey] = expand;
+ }
+ busy = false;
+ });
+ } else {
+ application.expansions[expandKey] = expand;
+ }
+ }
+
+ bool _isFalseOrNull(String value) {
+ return value == null || value == false;
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/debugger.dart b/runtime/observatory/lib/src/elements/debugger.dart
index 61a8989..4ced2d6 100644
--- a/runtime/observatory/lib/src/elements/debugger.dart
+++ b/runtime/observatory/lib/src/elements/debugger.dart
@@ -8,7 +8,6 @@
import 'dart:html';
import 'dart:math';
import 'observatory_element.dart';
-import 'nav_bar.dart';
import 'package:observatory/app.dart';
import 'package:observatory/cli.dart';
import 'package:observatory/debugger.dart';
@@ -2005,7 +2004,8 @@
var cmdDiv = $['commandDiv'];
// For now, force navbar height to 40px in the debugger.
- int navbarHeight = NavBarElement.height;
+ // TODO (cbernaschina) check if this is needed.
+ const navbarHeight = 40;
int splitterHeight = splitterDiv.clientHeight;
int cmdHeight = cmdDiv.clientHeight;
@@ -2255,7 +2255,8 @@
if (varsDiv == null) {
return minTop;
}
- const navbarHeight = NavBarElement.height;
+ // TODO (cbernaschina) check if this is needed.
+ const navbarHeight = 40;
const bottomPad = 6;
var parent = varsDiv.parent.getBoundingClientRect();
var varsHeight = varsDiv.clientHeight;
diff --git a/runtime/observatory/lib/src/elements/debugger.html b/runtime/observatory/lib/src/elements/debugger.html
index 20e2e4d..54fee31 100644
--- a/runtime/observatory/lib/src/elements/debugger.html
+++ b/runtime/observatory/lib/src/elements/debugger.html
@@ -1,8 +1,6 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
<link rel="import" href="function_ref.html">
-<link rel="import" href="nav_bar.html">
<link rel="import" href="eval_link.html">
-<link rel="import" href="observatory_element.html">
<link rel="import" href="script_inset.html">
<link rel="import" href="script_ref.html">
@@ -72,7 +70,7 @@
</template>
</polymer-element>
-<polymer-element name="debugger-page" extends="observatory-element">
+<polymer-element name="debugger-page">
<template>
<link rel="stylesheet" href="css/shared.css">
<style>
@@ -109,11 +107,13 @@
</style>
<div class="container">
- <nav-bar id="navbarDiv" notifyOnPause="{{ false }}">
+ <nav-bar id="navbarDiv" >
<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('/debugger', isolate) }}" anchor="debugger" last="{{ true }}"></nav-menu>
+ <nav-notify notifications="{{ app.notifications }}"
+ notifyOnPause="{{ false }}"></nav-notify>
</nav-bar>
<div id="stackDiv" class="stack">
<debugger-stack id="stackElement" isolate="{{ isolate }}"></debugger-stack>
@@ -132,7 +132,7 @@
</template>
</polymer-element>
-<polymer-element name="debugger-stack" extends="observatory-element">
+<polymer-element name="debugger-stack">
<template>
<link rel="stylesheet" href="css/shared.css">
<style>
@@ -183,7 +183,7 @@
</polymer-element>
-<polymer-element name="debugger-frame" extends="observatory-element">
+<polymer-element name="debugger-frame">
<template>
<link rel="stylesheet" href="css/shared.css">
<style>
@@ -299,7 +299,7 @@
</template>
</polymer-element>
-<polymer-element name="debugger-message" extends="observatory-element">
+<polymer-element name="debugger-message">
<template>
<link rel="stylesheet" href="css/shared.css">
<style>
@@ -404,7 +404,7 @@
</template>
</polymer-element>
-<polymer-element name="debugger-console" extends="observatory-element">
+<polymer-element name="debugger-console">
<template>
<link rel="stylesheet" href="css/shared.css">
<style>
@@ -443,7 +443,7 @@
</template>
</polymer-element>
-<polymer-element name="debugger-input" extends="observatory-element">
+<polymer-element name="debugger-input">
<template>
<link rel="stylesheet" href="css/shared.css">
<style>
diff --git a/runtime/observatory/lib/src/elements/error_ref.html b/runtime/observatory/lib/src/elements/error_ref.html
index 57de134..a132039 100644
--- a/runtime/observatory/lib/src/elements/error_ref.html
+++ b/runtime/observatory/lib/src/elements/error_ref.html
@@ -1,9 +1,8 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="curly_block.html">
-<link rel="import" href="observatory_element.html">
+
<link rel="import" href="service_ref.html">
-<polymer-element name="error-ref" extends="service-ref">
+<polymer-element name="error-ref">
<template>
<link rel="stylesheet" href="css/shared.css">
<style>
diff --git a/runtime/observatory/lib/src/elements/error_view.html b/runtime/observatory/lib/src/elements/error_view.html
index 818ba1e..aa40472 100644
--- a/runtime/observatory/lib/src/elements/error_view.html
+++ b/runtime/observatory/lib/src/elements/error_view.html
@@ -1,13 +1,11 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="nav_bar.html">
-<link rel="import" href="observatory_element.html">
-<link rel="import" href="view_footer.html">
-<polymer-element name="error-view" extends="observatory-element">
+<polymer-element name="error-view">
<template>
<link rel="stylesheet" href="css/shared.css">
<nav-bar>
<top-nav-menu last="{{ true }}"></top-nav-menu>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content-centered">
<h1>{{ error.kind }}</h1>
diff --git a/runtime/observatory/lib/src/elements/eval_box.html b/runtime/observatory/lib/src/elements/eval_box.html
index f01a995..eb1e639 100644
--- a/runtime/observatory/lib/src/elements/eval_box.html
+++ b/runtime/observatory/lib/src/elements/eval_box.html
@@ -1,9 +1,9 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
<link rel="import" href="instance_ref.html">
<link rel="import" href="error_ref.html">
-<link rel="import" href="observatory_element.html">
-<polymer-element name="eval-box" extends="observatory-element">
+
+<polymer-element name="eval-box">
<template>
<style>
.textbox {
diff --git a/runtime/observatory/lib/src/elements/eval_link.html b/runtime/observatory/lib/src/elements/eval_link.html
index 1fdb584..38d2981 100644
--- a/runtime/observatory/lib/src/elements/eval_link.html
+++ b/runtime/observatory/lib/src/elements/eval_link.html
@@ -1,9 +1,9 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
<link rel="import" href="instance_ref.html">
<link rel="import" href="error_ref.html">
-<link rel="import" href="observatory_element.html">
-<polymer-element name="eval-link" extends="observatory-element">
+
+<polymer-element name="eval-link">
<template>
<style>
.idle {
diff --git a/runtime/observatory/lib/src/elements/field_ref.html b/runtime/observatory/lib/src/elements/field_ref.html
index 762362a..a593d31 100644
--- a/runtime/observatory/lib/src/elements/field_ref.html
+++ b/runtime/observatory/lib/src/elements/field_ref.html
@@ -1,9 +1,9 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
<link rel="import" href="instance_ref.html">
-<link rel="import" href="observatory_element.html">
+
<link rel="import" href="service_ref.html">
-<polymer-element name="field-ref" extends="service-ref">
+<polymer-element name="field-ref">
<template>
<link rel="stylesheet" href="css/shared.css">
<span>
diff --git a/runtime/observatory/lib/src/elements/field_view.html b/runtime/observatory/lib/src/elements/field_view.html
index d9cdefd..4df7b24 100644
--- a/runtime/observatory/lib/src/elements/field_view.html
+++ b/runtime/observatory/lib/src/elements/field_view.html
@@ -2,12 +2,9 @@
<link rel="import" href="class_ref.html">
<link rel="import" href="instance_ref.html">
<link rel="import" href="library_ref.html">
-<link rel="import" href="nav_bar.html">
<link rel="import" href="script_ref.html">
-<link rel="import" href="observatory_element.html">
-<link rel="import" href="view_footer.html">
-<polymer-element name="field-view" extends="observatory-element">
+<polymer-element name="field-view">
<template>
<link rel="stylesheet" href="css/shared.css">
<nav-bar>
@@ -20,6 +17,7 @@
</template>
<nav-menu link="{{ makeLink('/inspect', field) }}" anchor="{{ field.name }}" last="{{ true }}"></nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content">
diff --git a/runtime/observatory/lib/src/elements/flag_list.html b/runtime/observatory/lib/src/elements/flag_list.html
index 9a39cbb..2c21db0 100644
--- a/runtime/observatory/lib/src/elements/flag_list.html
+++ b/runtime/observatory/lib/src/elements/flag_list.html
@@ -1,9 +1,6 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="nav_bar.html">
-<link rel="import" href="observatory_element.html">
-<link rel="import" href="view_footer.html">
-<polymer-element name="flag-list" extends="observatory-element">
+<polymer-element name="flag-list">
<template>
<link rel="stylesheet" href="css/shared.css">
<nav-bar>
@@ -11,6 +8,7 @@
<vm-nav-menu vm="{{ app.vm }}"></vm-nav-menu>
<nav-menu link="{{ makeLink('/flags') }}" anchor="flags" last="{{ true }}"></nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content-centered">
@@ -40,7 +38,7 @@
</template>
</polymer-element>
-<polymer-element name="flag-item" extends="observatory-element">
+<polymer-element name="flag-item">
<template>
<link rel="stylesheet" href="css/shared.css">
<span style="color:#aaa">// {{ flag['comment'] }}</span>
diff --git a/runtime/observatory/lib/src/elements/function_ref.html b/runtime/observatory/lib/src/elements/function_ref.html
index c9499b3..4669386 100644
--- a/runtime/observatory/lib/src/elements/function_ref.html
+++ b/runtime/observatory/lib/src/elements/function_ref.html
@@ -2,7 +2,7 @@
<link rel="import" href="class_ref.html">
<link rel="import" href="service_ref.html">
-<polymer-element name="function-ref" extends="service-ref">
+<polymer-element name="function-ref">
<template><link rel="stylesheet" href="css/shared.css"></template>
</polymer-element>
diff --git a/runtime/observatory/lib/src/elements/function_view.html b/runtime/observatory/lib/src/elements/function_view.html
index a087382..70accd2 100644
--- a/runtime/observatory/lib/src/elements/function_view.html
+++ b/runtime/observatory/lib/src/elements/function_view.html
@@ -3,13 +3,10 @@
<link rel="import" href="code_ref.html">
<link rel="import" href="function_ref.html">
<link rel="import" href="library_ref.html">
-<link rel="import" href="observatory_element.html">
-<link rel="import" href="nav_bar.html">
<link rel="import" href="script_inset.html">
<link rel="import" href="script_ref.html">
-<link rel="import" href="view_footer.html">
-<polymer-element name="function-view" extends="observatory-element">
+<polymer-element name="function-view">
<template>
<link rel="stylesheet" href="css/shared.css">
<nav-bar>
@@ -22,6 +19,7 @@
</template>
<nav-menu link="{{ makeLink('/inspect', function) }}" anchor="{{ function.name }}" last="{{ true }}"></nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content">
diff --git a/runtime/observatory/lib/src/elements/general_error.html b/runtime/observatory/lib/src/elements/general_error.html
index ef1e004..ef809d1 100644
--- a/runtime/observatory/lib/src/elements/general_error.html
+++ b/runtime/observatory/lib/src/elements/general_error.html
@@ -1,12 +1,11 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="nav_bar.html">
-<link rel="import" href="observatory_element.html">
-<polymer-element name="general-error" extends="observatory-element">
+<polymer-element name="general-error">
<template>
<link rel="stylesheet" href="css/shared.css">
<nav-bar>
<top-nav-menu last="{{ true }}"></top-nav-menu>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content-centered">
<h1>Error</h1>
diff --git a/runtime/observatory/lib/src/elements/heap_map.html b/runtime/observatory/lib/src/elements/heap_map.html
index 8c95e22..82aad68 100644
--- a/runtime/observatory/lib/src/elements/heap_map.html
+++ b/runtime/observatory/lib/src/elements/heap_map.html
@@ -1,10 +1,7 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
<link rel="import" href="class_ref.html">
-<link rel="import" href="observatory_element.html">
-<link rel="import" href="nav_bar.html">
-<link rel="import" href="view_footer.html">
-<polymer-element name="heap-map" extends="observatory-element">
+<polymer-element name="heap-map">
<template>
<link rel="stylesheet" href="css/shared.css">
<style>
@@ -30,6 +27,7 @@
<isolate-nav-menu isolate="{{ fragmentation.isolate }}"></isolate-nav-menu>
<nav-menu link="{{ makeLink('/heap-map', fragmentation.isolate) }}" anchor="heap map" last="{{ true }}"></nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="hover">
<p style="text-align:center">{{ status }}</p>
diff --git a/runtime/observatory/lib/src/elements/heap_profile.html b/runtime/observatory/lib/src/elements/heap_profile.html
index 5e05d55..47ac16b 100644
--- a/runtime/observatory/lib/src/elements/heap_profile.html
+++ b/runtime/observatory/lib/src/elements/heap_profile.html
@@ -1,10 +1,7 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
<link rel="import" href="class_ref.html">
-<link rel="import" href="observatory_element.html">
-<link rel="import" href="nav_bar.html">
-<link rel="import" href="view_footer.html">
-<polymer-element name="heap-profile" extends="observatory-element">
+<polymer-element name="heap-profile">
<template>
<link rel="stylesheet" href="css/shared.css">
<style>
@@ -76,6 +73,7 @@
<div class="nav-option">
<input type="checkbox" checked="{{ autoRefresh }}">Auto-refresh on GC
</div>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content">
<h1>Allocation Profile</h1>
diff --git a/runtime/observatory/lib/src/elements/heap_snapshot.html b/runtime/observatory/lib/src/elements/heap_snapshot.html
index d593f97..f7a8bf5 100644
--- a/runtime/observatory/lib/src/elements/heap_snapshot.html
+++ b/runtime/observatory/lib/src/elements/heap_snapshot.html
@@ -1,10 +1,7 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
<link rel="import" href="class_ref.html">
-<link rel="import" href="observatory_element.html">
-<link rel="import" href="nav_bar.html">
-<link rel="import" href="view_footer.html">
-<polymer-element name="heap-snapshot" extends="observatory-element">
+<polymer-element name="heap-snapshot">
<template>
<link rel="stylesheet" href="css/shared.css">
<nav-bar>
@@ -13,6 +10,7 @@
<isolate-nav-menu isolate="{{ isolate }}"></isolate-nav-menu>
<nav-menu link="{{ makeLink('/heap-snapshot', isolate) }}" anchor="heap snapshot" last="{{ true }}"></nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<style>
/* general */
diff --git a/runtime/observatory/lib/src/elements/helpers/rendering_queue.dart b/runtime/observatory/lib/src/elements/helpers/rendering_queue.dart
new file mode 100644
index 0000000..a6062c3
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/helpers/rendering_queue.dart
@@ -0,0 +1,72 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+import 'dart:collection';
+import 'dart:async';
+
+/// A generic rendering task that can be scheduled.
+abstract class RenderingTask {
+ /// Rendering synchronous callback.
+ void render();
+}
+
+/// A generic synchronization system for rendering operations.
+abstract class RenderingBarrier {
+ /// Future to the next synchronization barrier (ms from application start).
+ Future<num> get next;
+}
+
+/// Synchronization system based on the AnimationFrame.
+class NextAnimationFrameBarrier implements RenderingBarrier {
+ Future<num> get next => window.animationFrame;
+}
+
+/// MOCK synchronization system for manual barrier triggering.
+class RenderingBarrierMock implements RenderingBarrier {
+ final StreamController<num> _stream = new StreamController<num>.broadcast();
+ num _ms = 0;
+
+ Future<num> get next => _stream.stream.first;
+
+ /// Trigger the next barrier with an optional numer of ms elapsed.
+ void triggerRenderingBarrier({num step: 20}) {
+ assert(step != null);
+ _stream.add(_ms += step);
+ }
+}
+
+/// RenderingTask queuing and synchronization system.
+class RenderingQueue {
+ final RenderingBarrier _barrier;
+ final Queue<RenderingTask> _queue = new Queue<RenderingTask>();
+
+ bool get isEmpty => _queue.isEmpty;
+ bool get isNotEmpty => _queue.isNotEmpty;
+
+ /// Creates a RenderingQueue with the default synchronization barrier.
+ RenderingQueue() : this.fromBarrier(new NextAnimationFrameBarrier());
+
+ /// Creates a RenderingQueue with a custom synchronization barrier.
+ RenderingQueue.fromBarrier(this._barrier) {
+ assert(this._barrier != null);
+ }
+
+ /// Add a task to the queue.
+ /// If the current rendering phase is running it will be executed during this
+ /// rendering cycle, otherwise it will be queued for the next one.
+ void enqueue(RenderingTask r) {
+ assert(r != null);
+ // If no task are in the queue there is no rendering phase scheduled.
+ if (isEmpty) _render();
+ _queue.addLast(r);
+ }
+
+ Future _render() async {
+ await _barrier.next;
+ while (_queue.isNotEmpty) {
+ _queue.removeFirst().render();
+ }
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/helpers/rendering_scheduler.dart b/runtime/observatory/lib/src/elements/helpers/rendering_scheduler.dart
new file mode 100644
index 0000000..562d04b
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/helpers/rendering_scheduler.dart
@@ -0,0 +1,117 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'package:observatory/src/elements/helpers/rendering_queue.dart';
+export 'package:observatory/src/elements/helpers/rendering_queue.dart';
+
+/// A generic renderable object.
+abstract class Renderable {
+ void render();
+}
+
+/// Event related to a Renderable rendering phase.
+class RenderedEvent<T extends Renderable> {
+ /// Renderable to which the event is related
+ final T element;
+ /// Is another rendering scheduled for this element.
+ final bool otherRenderScheduled;
+
+ RenderedEvent(this.element, this.otherRenderScheduled) {
+ assert(element != null);
+ assert(otherRenderScheduled != null);
+ }
+}
+
+/// Scheduler for rendering operations.
+class RenderingScheduler<T extends Renderable> implements RenderingTask {
+ bool _enabled = false;
+ bool _dirty = false;
+ bool _renderingScheduled = false;
+ bool _notificationScheduled = false;
+ /// Element managed by this scheduler.
+ final T element;
+ /// Queue used for rendering operations.
+ final RenderingQueue queue;
+
+ final StreamController<RenderedEvent<T>> _onRendered =
+ new StreamController<RenderedEvent<T>>.broadcast();
+ Stream<RenderedEvent<T>> get onRendered => _onRendered.stream;
+
+ /// Creates a new scheduler for an element.
+ /// If no queue is provided it will create a new default configured queue.
+ factory RenderingScheduler(T element, {RenderingQueue queue}) {
+ assert(element != null);
+ if (queue == null) { queue = new RenderingQueue(); }
+ return new RenderingScheduler<T>._(element, queue);
+ }
+
+ RenderingScheduler._(this.element, this.queue);
+
+ /// Enable the scheduler.
+ /// New dirty or schedule request will be considered.
+ void enable() {
+ if (_enabled) return;
+ _enabled = true;
+ scheduleRendering();
+ }
+
+ /// Disable the scheduler.
+ /// New dirty or schedule request will be discarded.
+ /// [optional] notify: send a final RenderEvent.
+ void disable({bool notify: false}) {
+ assert(notify != null);
+ if (!_enabled) return;
+ _enabled = false;
+ if (notify) scheduleNotification();
+ }
+
+ /// Set the object as dirty. A rendering will be scheduled.
+ void dirty() {
+ if (_dirty) return;
+ _dirty = true;
+ scheduleRendering();
+ }
+
+ /// Checks for modification during attribute set.
+ /// If value changes a new rendering is scheduled.
+ /// set attr(T v) => _attr = _r.checkAndReact(_attr, v);
+ dynamic checkAndReact(dynamic oldValue, dynamic newValue) {
+ if (oldValue != newValue) dirty();
+ else scheduleNotification();
+ return newValue;
+ }
+
+ /// Schedules a new rendering phase.
+ void scheduleRendering() {
+ if (_renderingScheduled) return;
+ if (!_enabled) return;
+ queue.enqueue(this);
+ _renderingScheduled = true;
+ }
+
+ /// Renders the element (if the scheduler is enabled).
+ /// It will clear the dirty flag.
+ void render() {
+ if (!_enabled) return;
+ _dirty = false;
+ element.render();
+ _renderingScheduled = false;
+ scheduleNotification();
+ if (_dirty) scheduleRendering();
+ }
+
+ /// Schedules a notification.
+ void scheduleNotification() {
+ if (_notificationScheduled) return;
+ _notify();
+ _notificationScheduled = true;
+ }
+
+ Future _notify() async {
+ _onRendered.add(new RenderedEvent<T>(element, _dirty));
+ _notificationScheduled = false;
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/helpers/tag.dart b/runtime/observatory/lib/src/elements/helpers/tag.dart
new file mode 100644
index 0000000..177e238
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/helpers/tag.dart
@@ -0,0 +1,36 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+
+/// Utility class for Custom Tags registration.
+class Tag<T extends HtmlElement> {
+ /// Tag name.
+ final String name;
+ /// Dependend tags that need to be registred for this tag to work properly.
+ final Iterable<Tag> dependencies;
+
+ const Tag(this.name, {this.dependencies : const []});
+
+ static final Map<Type, String> _tagByClass = <Type, String>{};
+ static final Map<String, Type> _classByTag = <String, Type>{};
+
+ /// Ensures that the Tag and all the dependencies are registered.
+ void ensureRegistration() {
+ if (!_tagByClass.containsKey(T) && !_classByTag.containsKey(name)) {
+ document.registerElement(name, T);
+ _tagByClass[T] = name;
+ _classByTag[name] = T;
+ dependencies.forEach((tag) => tag.ensureRegistration());
+ }
+ var tag = _tagByClass[T];
+ if (tag != name) {
+ throw new ArgumentError('Class $T is already registered to tag ${tag}');
+ }
+ var c = _classByTag[name];
+ if (c != T) {
+ throw new ArgumentError('Tag $name is already registered by class ${c}');
+ }
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/helpers/uris.dart b/runtime/observatory/lib/src/elements/helpers/uris.dart
new file mode 100644
index 0000000..1c9660c
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/helpers/uris.dart
@@ -0,0 +1,42 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:observatory/models.dart' as M;
+
+/// Utility class for URIs generation.
+abstract class Uris {
+ static String _isolatePage(String path, M.IsolateRef isolate,
+ {M.ObjectRef object}) {
+ final parameters = { 'isolateId': isolate.id };
+ if (object != null) parameters['objectId'] = object.id;
+ return '#' + new Uri(path: path, queryParameters: parameters).toString();
+ }
+
+ static String inspect(M.IsolateRef isolate, {M.ObjectRef object})
+ => _isolatePage('/inspect', isolate, object: object);
+ static String debugger(M.IsolateRef isolate)
+ => _isolatePage('/debugger', isolate);
+ static String classTree(M.IsolateRef isolate)
+ => _isolatePage('/class-tree', isolate);
+ static String cpuProfiler(M.IsolateRef isolate)
+ => _isolatePage('/profiler', isolate);
+ static String cpuProfilerTable(M.IsolateRef isolate)
+ => _isolatePage('/profiler-table', isolate);
+ static String allocationProfiler(M.IsolateRef isolate)
+ => _isolatePage('/allocation-profiler', isolate);
+ static String heapMap(M.IsolateRef isolate)
+ => _isolatePage('/heap-map', isolate);
+ static String metrics(M.IsolateRef isolate)
+ => _isolatePage('/metrics', isolate);
+ static String heapSnapshot(M.IsolateRef isolate)
+ => _isolatePage('/heap-snapshot', isolate);
+ static String persistentHandles(M.IsolateRef isolate)
+ => _isolatePage('/persistent-handles', isolate);
+ static String ports(M.IsolateRef isolate)
+ => _isolatePage('/ports', isolate);
+ static String logging(M.IsolateRef isolate)
+ => _isolatePage('/logging', isolate);
+ static String vm() => '#/vm';
+ static String vmConnect() => '#/vm-connect';
+}
diff --git a/runtime/observatory/lib/src/elements/icdata_view.html b/runtime/observatory/lib/src/elements/icdata_view.html
index d31f14f..9a5cf7b 100644
--- a/runtime/observatory/lib/src/elements/icdata_view.html
+++ b/runtime/observatory/lib/src/elements/icdata_view.html
@@ -5,12 +5,10 @@
<link rel="import" href="function_ref.html">
<link rel="import" href="inbound_reference.html">
<link rel="import" href="instance_ref.html">
-<link rel="import" href="observatory_element.html">
<link rel="import" href="object_common.html">
-<link rel="import" href="nav_bar.html">
<link rel="import" href="eval_link.html">
-<polymer-element name="icdata-view" extends="observatory-element">
+<polymer-element name="icdata-view">
<template>
<link rel="stylesheet" href="css/shared.css">
<nav-bar>
@@ -19,6 +17,7 @@
<isolate-nav-menu isolate="{{ icData.isolate }}"></isolate-nav-menu>
<nav-menu link="." anchor="object" last="{{ true }}"></nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content">
@@ -29,7 +28,7 @@
<div class="memberList">
<div class="memberItem">
<div class="memberName">selector</div>
- <div class="memberValue">
+ <div class="memberValue">
{{ icData.selector }}
</div>
</div>
@@ -54,7 +53,7 @@
</div>
</div>
-
+
<hr>
<view-footer></view-footer>
</template>
diff --git a/runtime/observatory/lib/src/elements/inbound_reference.html b/runtime/observatory/lib/src/elements/inbound_reference.html
index 4ca13c3..cfda665 100644
--- a/runtime/observatory/lib/src/elements/inbound_reference.html
+++ b/runtime/observatory/lib/src/elements/inbound_reference.html
@@ -1,10 +1,9 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="curly_block.html">
<link rel="import" href="field_ref.html">
-<link rel="import" href="observatory_element.html">
+
<link rel="import" href="service_ref.html">
-<polymer-element name="inbound-reference" extends="service-ref">
+<polymer-element name="inbound-reference">
<template>
<link rel="stylesheet" href="css/shared.css">
<div>
diff --git a/runtime/observatory/lib/src/elements/instance_ref.html b/runtime/observatory/lib/src/elements/instance_ref.html
index 311732b..dffa36c 100644
--- a/runtime/observatory/lib/src/elements/instance_ref.html
+++ b/runtime/observatory/lib/src/elements/instance_ref.html
@@ -1,9 +1,8 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="curly_block.html">
-<link rel="import" href="observatory_element.html">
+
<link rel="import" href="service_ref.html">
-<polymer-element name="instance-ref" extends="service-ref">
+<polymer-element name="instance-ref">
<template>
<link rel="stylesheet" href="css/shared.css">
<style>
diff --git a/runtime/observatory/lib/src/elements/instance_view.html b/runtime/observatory/lib/src/elements/instance_view.html
index 5e98824..dd522e5 100644
--- a/runtime/observatory/lib/src/elements/instance_view.html
+++ b/runtime/observatory/lib/src/elements/instance_view.html
@@ -7,13 +7,10 @@
<link rel="import" href="function_ref.html">
<link rel="import" href="inbound_reference.html">
<link rel="import" href="instance_ref.html">
-<link rel="import" href="observatory_element.html">
-<link rel="import" href="nav_bar.html">
<link rel="import" href="object_common.html">
<link rel="import" href="context_ref.html">
-<link rel="import" href="view_footer.html">
-<polymer-element name="instance-view" extends="observatory-element">
+<polymer-element name="instance-view">
<template>
<link rel="stylesheet" href="css/shared.css">
<nav-bar>
@@ -24,6 +21,7 @@
<class-nav-menu cls="{{ instance.clazz }}"></class-nav-menu>
<nav-menu link="." anchor="instance" last="{{ true }}"></nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<template if="{{ instance.isError }}">
diff --git a/runtime/observatory/lib/src/elements/instructions_view.html b/runtime/observatory/lib/src/elements/instructions_view.html
index feb108c..07c5343 100644
--- a/runtime/observatory/lib/src/elements/instructions_view.html
+++ b/runtime/observatory/lib/src/elements/instructions_view.html
@@ -5,12 +5,10 @@
<link rel="import" href="function_ref.html">
<link rel="import" href="inbound_reference.html">
<link rel="import" href="instance_ref.html">
-<link rel="import" href="observatory_element.html">
<link rel="import" href="object_common.html">
-<link rel="import" href="nav_bar.html">
<link rel="import" href="eval_link.html">
-<polymer-element name="instructions-view" extends="observatory-element">
+<polymer-element name="instructions-view">
<template>
<link rel="stylesheet" href="css/shared.css">
<nav-bar>
@@ -19,6 +17,7 @@
<isolate-nav-menu isolate="{{ instructions.isolate }}"></isolate-nav-menu>
<nav-menu link="." anchor="object" last="{{ true }}"></nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content">
@@ -42,7 +41,7 @@
</div>
</div>
-
+
<hr>
<view-footer></view-footer>
</template>
diff --git a/runtime/observatory/lib/src/elements/io_view.html b/runtime/observatory/lib/src/elements/io_view.html
index fcc8399..c858e15 100644
--- a/runtime/observatory/lib/src/elements/io_view.html
+++ b/runtime/observatory/lib/src/elements/io_view.html
@@ -1,15 +1,14 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="nav_bar.html">
-<link rel="import" href="observatory_element.html">
<link rel="import" href="service_ref.html">
-<polymer-element name="io-view" extends="observatory-element">
+<polymer-element name="io-view">
<template>
<link rel="stylesheet" href="css/shared.css">
<nav-bar>
<top-nav-menu last="{{ true }}"></top-nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content">
@@ -61,7 +60,7 @@
</template>
</polymer-element>
-<polymer-element name="io-ref" extends="service-ref">
+<polymer-element name="io-ref">
<template>
<link rel="stylesheet" href="css/shared.css">
<template if="{{ ref.type == 'Socket' }}">
@@ -82,13 +81,14 @@
</template>
</polymer-element>
-<polymer-element name="io-http-server-list-view" extends="observatory-element">
+<polymer-element name="io-http-server-list-view">
<template>
<link rel="stylesheet" href="css/shared.css">
<nav-bar>
<top-nav-menu last="{{ true }}"></top-nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content">
@@ -109,20 +109,21 @@
</template>
</polymer-element>
-<polymer-element name="io-http-server-ref" extends="service-ref">
+<polymer-element name="io-http-server-ref">
<template>
<link rel="stylesheet" href="css/shared.css">
<a on-click="{{ goto }}" _href="{{ url }}">{{ name }}</a>
</template>
</polymer-element>
-<polymer-element name="io-http-server-view" extends="observatory-element">
+<polymer-element name="io-http-server-view">
<template>
<link rel="stylesheet" href="css/shared.css">
<nav-bar>
<top-nav-menu last="{{ true }}"></top-nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content">
@@ -170,20 +171,21 @@
</template>
</polymer-element>
-<polymer-element name="io-http-server-connection-ref" extends="service-ref">
+<polymer-element name="io-http-server-connection-ref">
<template>
<link rel="stylesheet" href="css/shared.css">
<a _href="{{ url }}">{{ name }}</a>
</template>
</polymer-element>
-<polymer-element name="io-http-server-connection-view" extends="observatory-element">
+<polymer-element name="io-http-server-connection-view">
<template>
<link rel="stylesheet" href="css/shared.css">
<nav-bar>
<top-nav-menu last="{{ true }}"></top-nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content">
@@ -211,20 +213,21 @@
</template>
</polymer-element>
-<polymer-element name="io-socket-ref" extends="service-ref">
+<polymer-element name="io-socket-ref">
<template>
<link rel="stylesheet" href="css/shared.css">
<a on-click="{{ goto }}" _href="{{ url }}">{{ name }}</a>
</template>
</polymer-element>
-<polymer-element name="io-socket-list-view" extends="observatory-element">
+<polymer-element name="io-socket-list-view">
<template>
<link rel="stylesheet" href="css/shared.css">
<nav-bar>
<top-nav-menu last="{{ true }}"></top-nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content">
@@ -245,7 +248,7 @@
</template>
</polymer-element>
-<polymer-element name="io-socket-view" extends="observatory-element">
+<polymer-element name="io-socket-view">
<template>
<link rel="stylesheet" href="css/shared.css">
@@ -341,20 +344,21 @@
</template>
</polymer-element>
-<polymer-element name="io-web-socket-ref" extends="service-ref">
+<polymer-element name="io-web-socket-ref">
<template>
<link rel="stylesheet" href="css/shared.css">
<a on-click="{{ goto }}" _href="{{ url }}">{{ name }}</a>
</template>
</polymer-element>
-<polymer-element name="io-web-socket-list-view" extends="observatory-element">
+<polymer-element name="io-web-socket-list-view">
<template>
<link rel="stylesheet" href="css/shared.css">
<nav-bar>
<top-nav-menu last="{{ true }}"></top-nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content">
@@ -375,13 +379,14 @@
</template>
</polymer-element>
-<polymer-element name="io-web-socket-view" extends="observatory-element">
+<polymer-element name="io-web-socket-view">
<template>
<link rel="stylesheet" href="css/shared.css">
<nav-bar>
<top-nav-menu last="{{ true }}"></top-nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content">
@@ -401,20 +406,21 @@
</template>
</polymer-element>
-<polymer-element name="io-random-access-file-ref" extends="service-ref">
+<polymer-element name="io-random-access-file-ref">
<template>
<link rel="stylesheet" href="css/shared.css">
<a on-click="{{ goto }}" _href="{{ url }}">{{ name }}</a>
</template>
</polymer-element>
-<polymer-element name="io-random-access-file-list-view" extends="observatory-element">
+<polymer-element name="io-random-access-file-list-view">
<template>
<link rel="stylesheet" href="css/shared.css">
<nav-bar>
<top-nav-menu last="{{ true }}"></top-nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content">
@@ -435,13 +441,14 @@
</template>
</polymer-element>
-<polymer-element name="io-random-access-file-view" extends="observatory-element">
+<polymer-element name="io-random-access-file-view">
<template>
<link rel="stylesheet" href="css/shared.css">
<nav-bar>
<top-nav-menu last="{{ true }}"></top-nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content">
@@ -469,13 +476,14 @@
</template>
</polymer-element>
-<polymer-element name="io-process-list-view" extends="observatory-element">
+<polymer-element name="io-process-list-view">
<template>
<link rel="stylesheet" href="css/shared.css">
<nav-bar>
<top-nav-menu last="{{ true }}"></top-nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content">
@@ -496,7 +504,7 @@
</template>
</polymer-element>
-<polymer-element name="io-process-ref" extends="service-ref">
+<polymer-element name="io-process-ref">
<template>
<link rel="stylesheet" href="css/shared.css">
<template if="{{ small }}">
@@ -508,13 +516,14 @@
</template>
</polymer-element>
-<polymer-element name="io-process-view" extends="observatory-element">
+<polymer-element name="io-process-view">
<template>
<link rel="stylesheet" href="css/shared.css">
<nav-bar>
<top-nav-menu last="{{ true }}"></top-nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content">
diff --git a/runtime/observatory/lib/src/elements/isolate_reconnect.html b/runtime/observatory/lib/src/elements/isolate_reconnect.html
index 9674038..1f678f5 100644
--- a/runtime/observatory/lib/src/elements/isolate_reconnect.html
+++ b/runtime/observatory/lib/src/elements/isolate_reconnect.html
@@ -1,8 +1,6 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="nav_bar.html">
-<link rel="import" href="observatory_element.html">
-<polymer-element name="isolate-reconnect" extends="observatory-element">
+<polymer-element name="isolate-reconnect">
<template>
<link rel="stylesheet" href="css/shared.css">
<style>
@@ -13,6 +11,7 @@
<nav-bar>
<top-nav-menu last="{{ true }}"></top-nav-menu>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content-centered">
diff --git a/runtime/observatory/lib/src/elements/isolate_ref.dart b/runtime/observatory/lib/src/elements/isolate_ref.dart
index 730a438..f27c8fb 100644
--- a/runtime/observatory/lib/src/elements/isolate_ref.dart
+++ b/runtime/observatory/lib/src/elements/isolate_ref.dart
@@ -4,10 +4,65 @@
library isolate_ref_element;
-import 'package:polymer/polymer.dart';
-import 'service_ref.dart';
+import 'dart:html';
+import 'dart:async';
+import 'package:observatory/models.dart' as M
+ show IsolateRef, IsolateUpdateEvent;
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/helpers/uris.dart';
-@CustomTag('isolate-ref')
-class IsolateRefElement extends ServiceRefElement {
+class IsolateRefElement extends HtmlElement implements Renderable {
+ static const tag = const Tag<IsolateRefElement>('isolate-ref-wrapped');
+
+ RenderingScheduler<IsolateRefElement> _r;
+
+ Stream<RenderedEvent<IsolateRefElement>> get onRendered => _r.onRendered;
+
+ Stream<M.IsolateUpdateEvent> _updates;
+ StreamSubscription _updatesSubscription;
+ M.IsolateRef _isolate;
+
+ M.IsolateRef get isolate => _isolate;
+
+ factory IsolateRefElement(M.IsolateRef isolate,
+ Stream<M.IsolateUpdateEvent> updates, {RenderingQueue queue}) {
+ assert(isolate != null);
+ assert(updates != null);
+ IsolateRefElement e = document.createElement(tag.name);
+ e._r = new RenderingScheduler(e, queue: queue);
+ e._isolate = isolate;
+ e._updates = updates;
+ return e;
+ }
+
IsolateRefElement.created() : super.created();
+
+ @override
+ void attached() {
+ super.attached();
+ assert(_isolate != null);
+ assert(_updates != null);
+ _r.enable();
+ _updatesSubscription = _updates
+ .where((M.IsolateUpdateEvent e) => e.isolate.id == isolate.id)
+ .listen((M.IsolateUpdateEvent e) { _isolate = e.isolate; _r.dirty(); });
+ }
+
+ @override
+ void detached() {
+ super.detached(); _r.disable(notify: true);
+ children = [];
+ assert(_updatesSubscription != null);
+ _updatesSubscription.cancel();
+ _updatesSubscription = null;
+ }
+
+ void render() {
+ children = [
+ new AnchorElement(href: Uris.inspect(isolate))
+ ..text = 'Isolate ${isolate.number} (${isolate.name})'
+ ..classes = ['isolate-ref']
+ ];
+ }
}
diff --git a/runtime/observatory/lib/src/elements/isolate_ref.html b/runtime/observatory/lib/src/elements/isolate_ref.html
deleted file mode 100644
index edfb3ea..0000000
--- a/runtime/observatory/lib/src/elements/isolate_ref.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="service_ref.html">
-<polymer-element name="isolate-ref" extends="service-ref">
-<template><link rel="stylesheet" href="css/shared.css">
- <a on-click="{{ goto }}" _href="{{ url }}">Isolate {{ ref.number }} ({{ ref.name }})</a>
-</template>
-</polymer-element>
-
-<script type="application/dart" src="isolate_ref.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/isolate_ref_wrapper.dart b/runtime/observatory/lib/src/elements/isolate_ref_wrapper.dart
new file mode 100644
index 0000000..dc78739
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/isolate_ref_wrapper.dart
@@ -0,0 +1,78 @@
+// 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:html';
+import 'dart:async';
+
+import 'package:observatory/app.dart';
+import 'package:observatory/models.dart' show IsolateUpdateEvent;
+import 'package:observatory/mocks.dart' show IsolateUpdateEventMock;
+import 'package:observatory/service_html.dart' show Isolate;
+import 'package:observatory/src/elements/isolate_ref.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/shims/binding.dart';
+
+class IsolateRefElementWrapper extends HtmlElement {
+
+ static final binder = new Binder<IsolateRefElementWrapper>(
+ const [const Binding('ref')]);
+
+ static const tag = const Tag<IsolateRefElementWrapper>('isolate-ref');
+
+ final StreamController<IsolateUpdateEvent> _updatesController =
+ new StreamController<IsolateUpdateEvent>();
+ Stream<IsolateUpdateEvent> _updates;
+ StreamSubscription _subscription;
+
+ Isolate _isolate;
+ Isolate get ref => _isolate;
+ void set ref(Isolate ref) { _isolate = ref; _detached(); _attached(); }
+
+ IsolateRefElementWrapper.created() : super.created() {
+ _updates = _updatesController.stream.asBroadcastStream();
+ binder.registerCallback(this);
+ createShadowRoot();
+ render();
+ }
+
+ @override
+ void attached() {
+ super.attached();
+ _attached();
+ }
+
+ void _attached() {
+ if (ref != null) {
+ _subscription = ref.changes.listen((_) {
+ _updatesController.add(new IsolateUpdateEventMock(isolate: ref));
+ });
+ }
+ render();
+ }
+
+ @override
+ void detached() {
+ super.detached();
+ _detached();
+ }
+
+ void _detached() {
+ if (_subscription != null) {
+ _subscription.cancel();
+ _subscription = null;
+ }
+ }
+
+ void render() {
+ shadowRoot.children = [];
+ if (ref == null) return;
+
+ shadowRoot.children = [
+ new StyleElement()
+ ..text = '@import "packages/observatory/src/elements/css/shared.css";',
+ new IsolateRefElement(_isolate, _updates,
+ queue: ObservatoryApplication.app.queue)
+ ];
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/isolate_summary.html b/runtime/observatory/lib/src/elements/isolate_summary.html
index c089da9..7b62b4d 100644
--- a/runtime/observatory/lib/src/elements/isolate_summary.html
+++ b/runtime/observatory/lib/src/elements/isolate_summary.html
@@ -1,11 +1,9 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
<link rel="import" href="action_link.html">
<link rel="import" href="function_ref.html">
-<link rel="import" href="isolate_ref.html">
-<link rel="import" href="observatory_element.html">
<link rel="import" href="script_inset.html">
<link rel="import" href="script_ref.html">
-<polymer-element name="isolate-summary" extends="observatory-element">
+<polymer-element name="isolate-summary">
<template>
<link rel="stylesheet" href="css/shared.css">
<div class="flex-row">
@@ -24,7 +22,7 @@
</template>
</polymer-element>
-<polymer-element name="isolate-run-state" extends="observatory-element">
+<polymer-element name="isolate-run-state">
<template>
<template if="{{ isolate.paused }}">
<strong title="{{ isolate.pauseEvent.timestamp.toString() }}">paused</strong>
@@ -44,7 +42,7 @@
</template>
</polymer-element>
-<polymer-element name="isolate-location" extends="observatory-element">
+<polymer-element name="isolate-location">
<template>
<template if="{{ isolate.pauseEvent != null }}">
<template if="{{ isolate.pauseEvent.kind == 'PauseStart' }}">
@@ -88,7 +86,7 @@
</template>
</polymer-element>
-<polymer-element name="isolate-shared-summary" extends="observatory-element">
+<polymer-element name="isolate-shared-summary">
<template>
<style>
.errorBox {
@@ -201,7 +199,7 @@
</template>
</polymer-element>
-<polymer-element name="isolate-counter-chart" extends="observatory-element">
+<polymer-element name="isolate-counter-chart">
<template>
<link rel="stylesheet" href="../../../../packages/charted/charts/themes/quantum_theme.css">
<style>
diff --git a/runtime/observatory/lib/src/elements/isolate_view.html b/runtime/observatory/lib/src/elements/isolate_view.html
index e7777a7..a414e3f 100644
--- a/runtime/observatory/lib/src/elements/isolate_view.html
+++ b/runtime/observatory/lib/src/elements/isolate_view.html
@@ -1,17 +1,13 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
<link rel="import" href="action_link.html">
-<link rel="import" href="curly_block.html">
<link rel="import" href="eval_box.html">
<link rel="import" href="function_ref.html">
<link rel="import" href="isolate_summary.html">
<link rel="import" href="library_ref.html">
-<link rel="import" href="nav_bar.html">
-<link rel="import" href="observatory_element.html">
<link rel="import" href="script_inset.html">
<link rel="import" href="script_ref.html">
-<link rel="import" href="view_footer.html">
-<polymer-element name="isolate-view" extends="observatory-element">
+<polymer-element name="isolate-view">
<template>
<link rel="stylesheet" href="css/shared.css">
<style>
@@ -29,6 +25,7 @@
<vm-nav-menu vm="{{ isolate.vm }}"></vm-nav-menu>
<isolate-nav-menu isolate="{{ isolate }}" last="{{ true }}"></isolate-nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content-centered">
diff --git a/runtime/observatory/lib/src/elements/json_view.html b/runtime/observatory/lib/src/elements/json_view.html
index 4ef479b..ea4b63f 100644
--- a/runtime/observatory/lib/src/elements/json_view.html
+++ b/runtime/observatory/lib/src/elements/json_view.html
@@ -1,10 +1,10 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="nav_bar.html">
-<link rel="import" href="observatory_element.html">
-<polymer-element name="json-view" extends="observatory-element">
+
+<polymer-element name="json-view">
<template>
<nav-bar>
<top-nav-menu last="{{ true }}"></top-nav-menu>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<pre>{{ mapAsString }}</pre>
</template>
diff --git a/runtime/observatory/lib/src/elements/library_ref.html b/runtime/observatory/lib/src/elements/library_ref.html
index a4313c1..6e8c7a0 100644
--- a/runtime/observatory/lib/src/elements/library_ref.html
+++ b/runtime/observatory/lib/src/elements/library_ref.html
@@ -1,9 +1,8 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="curly_block.html">
-<link rel="import" href="observatory_element.html">
+
<link rel="import" href="service_ref.html">
-<polymer-element name="library-ref" extends="service-ref">
+<polymer-element name="library-ref">
<template>
<link rel="stylesheet" href="css/shared.css">
<style>
diff --git a/runtime/observatory/lib/src/elements/library_view.html b/runtime/observatory/lib/src/elements/library_view.html
index 51d2da8..97417fa 100644
--- a/runtime/observatory/lib/src/elements/library_view.html
+++ b/runtime/observatory/lib/src/elements/library_view.html
@@ -1,17 +1,13 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
<link rel="import" href="class_ref.html">
-<link rel="import" href="curly_block.html">
<link rel="import" href="eval_box.html">
<link rel="import" href="field_ref.html">
<link rel="import" href="function_ref.html">
<link rel="import" href="instance_ref.html">
-<link rel="import" href="observatory_element.html">
<link rel="import" href="library_ref.html">
-<link rel="import" href="nav_bar.html">
<link rel="import" href="script_ref.html">
-<link rel="import" href="view_footer.html">
-<polymer-element name="library-view" extends="observatory-element">
+<polymer-element name="library-view">
<template>
<link rel="stylesheet" href="css/shared.css">
@@ -21,6 +17,7 @@
<isolate-nav-menu isolate="{{ library.isolate }}"></isolate-nav-menu>
<library-nav-menu library="{{ library }}" last="{{ true }}"></library-nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content">
diff --git a/runtime/observatory/lib/src/elements/logging.html b/runtime/observatory/lib/src/elements/logging.html
index a3a36a1..0360c82bf 100644
--- a/runtime/observatory/lib/src/elements/logging.html
+++ b/runtime/observatory/lib/src/elements/logging.html
@@ -1,12 +1,8 @@
<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">
+<polymer-element name="logging-page">
<template>
<link rel="stylesheet" href="css/shared.css">
<style>
@@ -63,6 +59,7 @@
<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-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div id="page" class="content-centered-big">
<span>Show messages with severity <select id="severityLevelSelector" value="{{ severityLevel }}"></select> and higher</span>
diff --git a/runtime/observatory/lib/src/elements/megamorphiccache_view.html b/runtime/observatory/lib/src/elements/megamorphiccache_view.html
index 0454e0d..720dc29 100644
--- a/runtime/observatory/lib/src/elements/megamorphiccache_view.html
+++ b/runtime/observatory/lib/src/elements/megamorphiccache_view.html
@@ -5,12 +5,10 @@
<link rel="import" href="function_ref.html">
<link rel="import" href="inbound_reference.html">
<link rel="import" href="instance_ref.html">
-<link rel="import" href="observatory_element.html">
<link rel="import" href="object_common.html">
-<link rel="import" href="nav_bar.html">
<link rel="import" href="eval_link.html">
-<polymer-element name="megamorphiccache-view" extends="observatory-element">
+<polymer-element name="megamorphiccache-view">
<template>
<link rel="stylesheet" href="css/shared.css">
<nav-bar>
@@ -19,6 +17,7 @@
<isolate-nav-menu isolate="{{ megamorphicCache.isolate }}"></isolate-nav-menu>
<nav-menu link="." anchor="object" last="{{ true }}"></nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content">
@@ -41,7 +40,7 @@
</div>
<div class="memberItem">
<div class="memberName">mask</div>
- <div class="memberValue">
+ <div class="memberValue">
{{ megamorphicCache.mask }}
</div>
</div>
@@ -54,7 +53,7 @@
</div>
</div>
-
+
<hr>
<view-footer></view-footer>
</template>
diff --git a/runtime/observatory/lib/src/elements/metrics.html b/runtime/observatory/lib/src/elements/metrics.html
index a6a0411..a82cea0 100644
--- a/runtime/observatory/lib/src/elements/metrics.html
+++ b/runtime/observatory/lib/src/elements/metrics.html
@@ -1,8 +1,6 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="nav_bar.html">
-<link rel="import" href="observatory_element.html">
-<polymer-element name="metrics-page" extends="observatory-element">
+<polymer-element name="metrics-page">
<template>
<link rel="stylesheet" href="css/shared.css">
<style>
@@ -23,6 +21,7 @@
<nav-menu link="{{ makeLink('/metrics', isolate) }}" anchor="metrics" last="{{ true }}"></nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="flex-row">
<div class="flex-item-20-percent">
@@ -65,7 +64,7 @@
</template>
</polymer-element>
-<polymer-element name="metric-details" extends="observatory-element">
+<polymer-element name="metric-details">
<template>
<link rel="stylesheet" href="css/shared.css">
<div class="content-centered">
@@ -124,7 +123,7 @@
</template>
</polymer-element>
-<polymer-element name="metrics-graph" extends="observatory-element">
+<polymer-element name="metrics-graph">
<template>
<link rel="stylesheet" href="css/shared.css">
<link rel="stylesheet" href="../../../../packages/charted/charts/themes/quantum_theme.css">
diff --git a/runtime/observatory/lib/src/elements/nav/bar.dart b/runtime/observatory/lib/src/elements/nav/bar.dart
new file mode 100644
index 0000000..8bb115e
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/nav/bar.dart
@@ -0,0 +1,83 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+import 'dart:async';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+
+class NavBarElement extends HtmlElement implements Renderable {
+ static final StyleElement _style = () {
+ var style = new StyleElement();
+ style.text = 'nav.nav-bar {'
+ 'position: fixed;'
+ 'top: -56px;'
+ 'width: 100%;'
+ 'z-index: 1000;'
+ '}'
+ 'nav.nav-bar > ul {'
+ 'display: inline-table;'
+ 'position: relative;'
+ 'list-style: none;'
+ 'padding-left: 0;'
+ 'margin-left: 0;'
+ 'width: 100%;'
+ 'z-index: 1000;'
+ 'font: 400 16px \'Montserrat\', sans-serif;'
+ 'color: white;'
+ 'background-color: #0489c3;'
+ '}'
+ 'nav.nav-bar:after {'
+ 'content: ""; clear: both; display: block;'
+ '}'
+ 'nav.nav-bar:before {'
+ 'height: 40px;'
+ 'background-color: #0489c3;'
+ 'content: ""; display: block;'
+ '}';
+ return style;
+ }();
+
+ static const tag = const Tag<NavBarElement>('nav-bar');
+
+ RenderingScheduler _r;
+
+ Stream<RenderedEvent<NavBarElement>> get onRendered => _r.onRendered;
+
+ factory NavBarElement({RenderingQueue queue}) {
+ NavBarElement e = document.createElement(tag.name);
+ e._r = new RenderingScheduler(e, queue: queue);
+ return e;
+ }
+
+ NavBarElement.created() : super.created() {
+ // TODO(cbernaschina) remove when no more needed.
+ _r = new RenderingScheduler(this);
+ createShadowRoot();
+ }
+
+ @override
+ void attached() { super.attached(); _r.enable(); }
+
+ @override
+ void detached() {
+ super.detached(); _r.disable(notify: true);
+ shadowRoot.children = [];
+ }
+
+ void render() {
+ shadowRoot.children = [
+ _style.clone(true),
+ document.createElement('nav')
+ ..classes = ['nav-bar']
+ ..children = [
+ new UListElement()
+ ..children = [
+ new ContentElement()
+ ],
+ ],
+ new DivElement()
+ ];
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/nav/class_menu.dart b/runtime/observatory/lib/src/elements/nav/class_menu.dart
new file mode 100644
index 0000000..d8ed510
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/nav/class_menu.dart
@@ -0,0 +1,64 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+import 'dart:async';
+import 'package:observatory/models.dart' as M show IsolateRef, ClassRef;
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/helpers/uris.dart';
+import 'package:observatory/src/elements/nav/menu.dart';
+
+class NavClassMenuElement extends HtmlElement implements Renderable {
+ static const tag = const Tag<NavClassMenuElement>('nav-class-menu',
+ dependencies: const [NavMenuElement.tag]);
+
+ RenderingScheduler _r;
+
+ Stream<RenderedEvent<NavClassMenuElement>> get onRendered => _r.onRendered;
+
+ bool _last;
+ M.IsolateRef _isolate;
+ M.ClassRef _cls;
+ bool get last => _last;
+ M.IsolateRef get isolate => _isolate;
+ M.ClassRef get cls => _cls;
+ set last(bool value) => _last = _r.checkAndReact(_last, value);
+
+ factory NavClassMenuElement(M.IsolateRef isolate, M.ClassRef cls,
+ {bool last: false, RenderingQueue queue}) {
+ assert(isolate != null);
+ assert(cls != null);
+ assert(last != null);
+ NavClassMenuElement e = document.createElement(tag.name);
+ e._r = new RenderingScheduler(e, queue: queue);
+ e._isolate = isolate;
+ e._cls = cls;
+ e._last = last;
+ return e;
+ }
+
+ NavClassMenuElement.created() : super.created() { createShadowRoot(); }
+
+ @override
+ void attached() {
+ super.attached();
+ _r.enable();
+ }
+
+ @override
+ void detached() {
+ super.detached();
+ _r.disable(notify: true);
+ shadowRoot.children = [];
+ }
+
+ void render() {
+ shadowRoot.children = [
+ new NavMenuElement(cls.name, last: last, queue: _r.queue,
+ link: Uris.inspect(isolate, object: cls))
+ ..children = [new ContentElement()]
+ ];
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/nav/class_menu_wrapper.dart b/runtime/observatory/lib/src/elements/nav/class_menu_wrapper.dart
new file mode 100644
index 0000000..d1e56ac
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/nav/class_menu_wrapper.dart
@@ -0,0 +1,59 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+
+import 'package:observatory/app.dart';
+import 'package:observatory/service.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/shims/binding.dart';
+import 'package:observatory/src/elements/nav/class_menu.dart';
+
+class NavClassMenuElementWrapper extends HtmlElement {
+ static final binder = new Binder<NavClassMenuElementWrapper>(
+ const [const Binding('last'), const Binding('cls')]);
+
+ static const tag =
+ const Tag<NavClassMenuElementWrapper>('class-nav-menu');
+
+ bool _last = false;
+ Class _cls;
+ bool get last => _last;
+ Class get cls => _cls;
+ set last(bool value) {
+ _last = value; render();
+ }
+ set cls(Class value) {
+ _cls = value; render();
+ }
+
+ NavClassMenuElementWrapper.created() : super.created() {
+ binder.registerCallback(this);
+ _last = _getBoolAttribute('last');
+ createShadowRoot();
+ render();
+ }
+
+ @override
+ void attached() {
+ super.attached();
+ render();
+ }
+
+ void render() {
+ shadowRoot.children = [];
+ if (_cls == null || _last == null) return;
+
+ shadowRoot.children = [
+ new NavClassMenuElement(cls.isolate, cls, last: last,
+ queue: ObservatoryApplication.app.queue)
+ ..children = [new ContentElement()]
+ ];
+ }
+
+ bool _getBoolAttribute(String name) {
+ final String value = getAttribute(name);
+ return !(value == null || value == 'false');
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/nav/isolate_menu.dart b/runtime/observatory/lib/src/elements/nav/isolate_menu.dart
new file mode 100644
index 0000000..3f0089a
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/nav/isolate_menu.dart
@@ -0,0 +1,103 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+import 'dart:async';
+import 'package:observatory/models.dart' as M
+ show IsolateRef, IsolateUpdateEvent;
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/helpers/uris.dart';
+import 'package:observatory/src/elements/nav/menu.dart';
+import 'package:observatory/src/elements/nav/menu_item.dart';
+
+class NavIsolateMenuElement extends HtmlElement implements Renderable {
+ static const tag = const Tag<NavIsolateMenuElement>('nav-isolate-menu',
+ dependencies: const [NavMenuElement.tag,
+ NavMenuItemElement.tag]);
+
+ RenderingScheduler _r;
+
+ Stream<RenderedEvent<NavIsolateMenuElement>> get onRendered => _r.onRendered;
+
+ Stream<M.IsolateUpdateEvent> _updates;
+ StreamSubscription _updatesSubscription;
+
+ bool _last;
+ M.IsolateRef _isolate;
+ bool get last => _last;
+ M.IsolateRef get isolate => _isolate;
+ set last(bool value) => _last = _r.checkAndReact(_last, value);
+
+ factory NavIsolateMenuElement(M.IsolateRef isolate,
+ Stream<M.IsolateUpdateEvent> updates, {bool last: false,
+ RenderingQueue queue}) {
+ assert(isolate != null);
+ assert(last != null);
+ NavIsolateMenuElement e = document.createElement(tag.name);
+ e._r = new RenderingScheduler(e, queue: queue);
+ e._isolate = isolate;
+ e._last = last;
+ e._updates = updates;
+ return e;
+ }
+
+ NavIsolateMenuElement.created() : super.created() {
+ _r = new RenderingScheduler(this);
+ createShadowRoot();
+ }
+
+ @override
+ void attached() {
+ super.attached();
+ assert(_isolate != null);
+ assert(_updates != null);
+ _r.enable();
+ _updatesSubscription = _updates
+ .where((M.IsolateUpdateEvent e) => e.isolate.id == isolate.id)
+ .listen((M.IsolateUpdateEvent e) { _isolate = e.isolate; _r.dirty(); });
+ }
+
+ @override
+ void detached() {
+ super.detached();
+ _r.disable(notify: true);
+ shadowRoot.children = [];
+ assert(_updatesSubscription != null);
+ _updatesSubscription.cancel();
+ _updatesSubscription = null;
+ }
+
+ void render() {
+ shadowRoot.children = [
+ new NavMenuElement(isolate.name, last: last, queue: _r.queue,
+ link: Uris.inspect(isolate))
+ ..children = [
+ new NavMenuItemElement('debugger', queue: _r.queue,
+ link: Uris.debugger(isolate)),
+ new NavMenuItemElement('class hierarchy', queue: _r.queue,
+ link: Uris.classTree(isolate)),
+ new NavMenuItemElement('cpu profile', queue: _r.queue,
+ link: Uris.cpuProfiler(isolate)),
+ new NavMenuItemElement('cpu profile (table)', queue: _r.queue,
+ link: Uris.cpuProfilerTable(isolate)),
+ new NavMenuItemElement('allocation profile', queue: _r.queue,
+ link: Uris.allocationProfiler(isolate)),
+ new NavMenuItemElement('heap map', queue: _r.queue,
+ link: Uris.heapMap(isolate)),
+ new NavMenuItemElement('metrics', queue: _r.queue,
+ link: Uris.metrics(isolate)),
+ new NavMenuItemElement('heap snapshot', queue: _r.queue,
+ link: Uris.heapSnapshot(isolate)),
+ new NavMenuItemElement('persistent handles', queue: _r.queue,
+ link: Uris.persistentHandles(isolate)),
+ new NavMenuItemElement('ports', queue: _r.queue,
+ link: Uris.ports(isolate)),
+ new NavMenuItemElement('logging', queue: _r.queue,
+ link: Uris.logging(isolate)),
+ new ContentElement()
+ ]
+ ];
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/nav/isolate_menu_wrapper.dart b/runtime/observatory/lib/src/elements/nav/isolate_menu_wrapper.dart
new file mode 100644
index 0000000..c2cf8f3
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/nav/isolate_menu_wrapper.dart
@@ -0,0 +1,90 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+import 'dart:async';
+
+import 'package:observatory/app.dart';
+import 'package:observatory/service.dart';
+import 'package:observatory/mocks.dart';
+import 'package:observatory/models.dart' as M;
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/shims/binding.dart';
+import 'package:observatory/src/elements/nav/isolate_menu.dart';
+
+class NavIsolateMenuElementWrapper extends HtmlElement {
+ static final binder = new Binder<NavIsolateMenuElementWrapper>(
+ const [const Binding('last'), const Binding('isolate')]);
+
+ static const tag =
+ const Tag<NavIsolateMenuElementWrapper>('isolate-nav-menu');
+
+ final StreamController<M.IsolateUpdateEvent> _updatesController =
+ new StreamController<M.IsolateUpdateEvent>();
+ Stream<M.IsolateUpdateEvent> _updates;
+ StreamSubscription _subscription;
+
+ bool _last = false;
+ Isolate _isolate;
+ bool get last => _last;
+ Isolate get isolate => _isolate;
+ set last(bool value) {
+ _last = value; render();
+ }
+ set isolate(Isolate value) {
+ _isolate = value; _detached(); _attached();
+ }
+
+ NavIsolateMenuElementWrapper.created() : super.created() {
+ _updates = _updatesController.stream.asBroadcastStream();
+ binder.registerCallback(this);
+ _last = _getBoolAttribute('last');
+ createShadowRoot();
+ render();
+ }
+
+ @override
+ void attached() {
+ super.attached();
+ _attached();
+ }
+
+ @override
+ void detached() {
+ super.detached();
+ _detached();
+ }
+
+ void _attached() {
+ if (_isolate != null) {
+ _subscription = _isolate.changes.listen((_) {
+ _updatesController.add(new IsolateUpdateEventMock(isolate: isolate));
+ });
+ }
+ render();
+ }
+
+ void _detached() {
+ if (_subscription != null) {
+ _subscription.cancel();
+ _subscription = null;
+ }
+ }
+
+ void render() {
+ shadowRoot.children = [];
+ if (_isolate == null || _last == null) return;
+
+ shadowRoot.children = [
+ new NavIsolateMenuElement(isolate, _updates, last: last,
+ queue: ObservatoryApplication.app.queue)
+ ..children = [new ContentElement()]
+ ];
+ }
+
+ bool _getBoolAttribute(String name) {
+ final String value = getAttribute(name);
+ return !(value == null || value == 'false');
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/nav/library_menu.dart b/runtime/observatory/lib/src/elements/nav/library_menu.dart
new file mode 100644
index 0000000..0403ac3
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/nav/library_menu.dart
@@ -0,0 +1,60 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+import 'dart:async';
+import 'package:observatory/models.dart' as M show IsolateRef, LibraryRef;
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/helpers/uris.dart';
+import 'package:observatory/src/elements/nav/menu.dart';
+
+class NavLibraryMenuElement extends HtmlElement implements Renderable {
+ static const tag = const Tag<NavLibraryMenuElement>('nav-library-menu',
+ dependencies: const [NavMenuElement.tag]);
+
+ RenderingScheduler _r;
+
+ Stream<RenderedEvent<NavLibraryMenuElement>> get onRendered => _r.onRendered;
+
+ bool _last;
+ M.IsolateRef _isolate;
+ M.LibraryRef _library;
+ bool get last => _last;
+ M.IsolateRef get isolate => _isolate;
+ M.LibraryRef get library => _library;
+ set last(bool value) => _last = _r.checkAndReact(_last, value);
+
+ factory NavLibraryMenuElement(M.IsolateRef isolate, M.LibraryRef library,
+ {bool last: false, RenderingQueue queue}) {
+ assert(isolate != null);
+ assert(library != null);
+ assert(last != null);
+ NavLibraryMenuElement e = document.createElement(tag.name);
+ e._r = new RenderingScheduler(e, queue: queue);
+ e._isolate = isolate;
+ e._library = library;
+ e._last = last;
+ return e;
+ }
+
+ NavLibraryMenuElement.created() : super.created() { createShadowRoot(); }
+
+ @override
+ void attached() { super.attached(); _r.enable(); }
+
+ @override
+ void detached() {
+ super.detached(); _r.disable(notify: true);
+ shadowRoot.children = [];
+ }
+
+ void render() {
+ shadowRoot.children = [
+ new NavMenuElement(library.name, last: last, queue: _r.queue,
+ link: Uris.inspect(isolate, object: library).toString())
+ ..children = [new ContentElement()]
+ ];
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/nav/library_menu_wrapper.dart b/runtime/observatory/lib/src/elements/nav/library_menu_wrapper.dart
new file mode 100644
index 0000000..6e48155
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/nav/library_menu_wrapper.dart
@@ -0,0 +1,59 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+
+import 'package:observatory/app.dart';
+import 'package:observatory/service.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/shims/binding.dart';
+import 'package:observatory/src/elements/nav/library_menu.dart';
+
+class NavLibraryMenuElementWrapper extends HtmlElement {
+ static final binder = new Binder<NavLibraryMenuElementWrapper>(
+ const [const Binding('last'), const Binding('library')]);
+
+ static const tag =
+ const Tag<NavLibraryMenuElementWrapper>('library-nav-menu');
+
+ bool _last = false;
+ Library _library;
+ bool get last => _last;
+ Library get library => _library;
+ set last(bool value) {
+ _last = value; render();
+ }
+ set library(Library value) {
+ _library = value; render();
+ }
+
+ NavLibraryMenuElementWrapper.created() : super.created() {
+ binder.registerCallback(this);
+ _last = _getBoolAttribute('last');
+ createShadowRoot();
+ render();
+ }
+
+ @override
+ void attached() {
+ super.attached();
+ render();
+ }
+
+ void render() {
+ shadowRoot.children = [];
+ if (_library == null || _last == null) return;
+
+ shadowRoot.children = [
+ new NavLibraryMenuElement(library.isolate, library, last: last,
+ queue: ObservatoryApplication.app.queue)
+ ..children = [new ContentElement()]
+ ];
+ }
+
+ bool _getBoolAttribute(String name) {
+ final String value = getAttribute(name);
+ return !(value == null || value == 'false');
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/nav/menu.dart b/runtime/observatory/lib/src/elements/nav/menu.dart
new file mode 100644
index 0000000..bcd9c90
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/nav/menu.dart
@@ -0,0 +1,109 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+import 'dart:async';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+
+class NavMenuElement extends HtmlElement implements Renderable {
+ static final StyleElement _style = () {
+ var style = new StyleElement();
+ style.text = '''li.nav-menu_label, li.nav-menu_spacer {
+ float: left;
+ }
+ li.nav-menu_label > a, li.nav-menu_spacer {
+ display: block;
+ padding: 12px 8px;
+ color: White;
+ text-decoration: none;
+ }
+ li.nav-menu_label:hover {
+ background: #455;
+ }
+ li.nav-menu_label > ul {
+ display: none;
+ position: absolute;
+ top: 98%;
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ width: auto;
+ z-index: 1000;
+ font: 400 16px \'Montserrat\', sans-serif;
+ color: white;
+ background: #567;
+ }
+ li.nav-menu_label > ul:after {
+ content: ""; clear: both; display: block;
+ }
+ li.nav-menu_label:hover > ul {
+ display: block;
+ }''';
+ return style;
+ }();
+
+ static const tag = const Tag<NavMenuElement>('nav-menu-wrapped');
+
+ RenderingScheduler _r;
+
+ Stream<RenderedEvent<NavMenuElement>> get onRendered => _r.onRendered;
+
+ String _label;
+ String _link;
+ bool _last;
+ String get label => _label;
+ String get link => _link;
+ bool get last => _last;
+ set label(String value) => _label = _r.checkAndReact(_label, value);
+ set link(String value) => _link = _r.checkAndReact(_link, value);
+ set last(bool value) => _last = _r.checkAndReact(_link, value);
+
+ factory NavMenuElement(String label, {String link, bool last: false,
+ RenderingQueue queue}) {
+ assert(label != null);
+ assert(last != null);
+ NavMenuElement e = document.createElement(tag.name);
+ e._r = new RenderingScheduler(e, queue: queue);
+ e._label = label;
+ e._link = link;
+ e._last = last;
+ return e;
+ }
+
+ NavMenuElement.created() : super.created() { createShadowRoot(); }
+
+ @override
+ void attached() { super.attached(); _r.enable(); }
+
+ @override
+ void detached() {
+ super.detached(); _r.disable(notify: true);
+ shadowRoot.children = [];
+ }
+
+ void render() {
+ List<Element> children = [
+ _style.clone(true),
+ new LIElement()
+ ..classes = ['nav-menu_label']
+ ..children = [
+ new AnchorElement(href: link)
+ ..text = label,
+ new UListElement()
+ ..children = [
+ new ContentElement()
+ ]
+ ]
+ ];
+ if (!last) {
+ children.add(
+ new LIElement()
+ ..classes = ['nav-menu_spacer']
+ ..innerHtml = '>'
+ );
+ }
+ shadowRoot.children = children;
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/nav/menu_item.dart b/runtime/observatory/lib/src/elements/nav/menu_item.dart
new file mode 100644
index 0000000..2411ee5
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/nav/menu_item.dart
@@ -0,0 +1,100 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+import 'dart:async';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+
+class NavMenuItemElement extends HtmlElement implements Renderable {
+ static final StyleElement _style = () {
+ var style = new StyleElement();
+ style.text = '''li.nav-menu-item {
+ float: none;
+ border-top: 1px solid #677;
+ border-bottom: 1px solid #556; position: relative;
+ }
+ li.nav-menu-item:hover {
+ background: #455;
+ }
+ li.nav-menu-item > a {
+ display: block;
+ padding: 12px 12px;
+ color: white;
+ text-decoration: none;
+ }
+ li.nav-menu-item > ul {
+ display: none;
+ position: absolute;
+ top:0;
+ left: 100%;
+ list-style: none;
+ padding: 0;
+ margin-left: 0;
+ width: auto;
+ z-index: 1000;
+ font: 400 16px \'Montserrat\', sans-serif;
+ color: white;
+ background: #567;
+ }
+ li.nav-menu-item > ul:after {
+ content: ""; clear: both; display: block;
+ }
+ li.nav-menu-item:hover > ul {
+ display: block;
+ }''';
+ return style;
+ }();
+
+ static const tag = const Tag<NavMenuItemElement>('nav-menu-item-wrapped');
+
+ RenderingScheduler _r;
+
+ Stream<RenderedEvent<NavMenuItemElement>> get onRendered => _r.onRendered;
+
+ String _label;
+ String _link;
+ String get label => _label;
+ String get link => _link;
+ set label(String value) => _label = _r.checkAndReact(_label, value);
+ set link(String value) => _link = _r.checkAndReact(_link, value);
+
+
+ factory NavMenuItemElement(String label, {String link,
+ RenderingQueue queue}) {
+ assert(label != null);
+ NavMenuItemElement e = document.createElement(tag.name);
+ e._r = new RenderingScheduler(e, queue: queue);
+ e._label = label;
+ e._link = link;
+ return e;
+ }
+
+ NavMenuItemElement.created() : super.created() { createShadowRoot(); }
+
+ @override
+ void attached() { super.attached(); _r.enable(); }
+
+ @override
+ void detached() {
+ super.detached(); _r.disable(notify: true);
+ shadowRoot.children = [];
+ }
+
+ void render() {
+ shadowRoot.children = [
+ _style.clone(true),
+ new LIElement()
+ ..classes = ['nav-menu-item']
+ ..children = [
+ new AnchorElement(href: link)
+ ..text = label,
+ new UListElement()
+ ..children = [
+ new ContentElement()
+ ]
+ ]
+ ];
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/nav/menu_item_wrapper.dart b/runtime/observatory/lib/src/elements/nav/menu_item_wrapper.dart
new file mode 100644
index 0000000..045d67a
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/nav/menu_item_wrapper.dart
@@ -0,0 +1,54 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+
+import 'package:observatory/app.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/shims/binding.dart';
+import 'package:observatory/src/elements/nav/menu_item.dart';
+
+class NavMenuItemElementWrapper extends HtmlElement {
+ static final binder = new Binder<NavMenuItemElementWrapper>(
+ const [const Binding('anchor'), const Binding('link')]);
+
+ static const tag =
+ const Tag<NavMenuItemElementWrapper>('nav-menu-item');
+
+ String _anchor;
+ String _link;
+ String get anchor => _anchor;
+ String get link => _link;
+ set anchor(String value) {
+ _anchor = value; render();
+ }
+ set link(String value) {
+ _link = value; render();
+ }
+
+ NavMenuItemElementWrapper.created() : super.created() {
+ binder.registerCallback(this);
+ _anchor = getAttribute('anchor');
+ _link = getAttribute('link');
+ createShadowRoot();
+ render();
+ }
+
+ @override
+ void attached() {
+ super.attached();
+ render();
+ }
+
+ void render() {
+ shadowRoot.children = [];
+ if (_anchor == null) return;
+
+ shadowRoot.children = [
+ new NavMenuItemElement(_anchor, link: '#$link',
+ queue: ObservatoryApplication.app.queue)
+ ..children = [new ContentElement()]
+ ];
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/nav/menu_wrapper.dart b/runtime/observatory/lib/src/elements/nav/menu_wrapper.dart
new file mode 100644
index 0000000..c237fed
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/nav/menu_wrapper.dart
@@ -0,0 +1,66 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+
+import 'package:observatory/app.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/shims/binding.dart';
+import 'package:observatory/src/elements/nav/menu.dart';
+
+class NavMenuElementWrapper extends HtmlElement {
+ static final binder = new Binder<NavMenuElementWrapper>(
+ const [const Binding('anchor'), const Binding('link'),
+ const Binding('last')]);
+
+ static const tag =
+ const Tag<NavMenuElementWrapper>('nav-menu');
+
+ String _anchor = '---';
+ String _link;
+ bool _last = false;
+ String get anchor => _anchor;
+ String get link => _link;
+ bool get last => _last;
+ set anchor(String value) {
+ _anchor = value; render();
+ }
+ set link(String value) {
+ _link = value; render();
+ }
+ set last(bool value) {
+ _last = value; render();
+ }
+
+ NavMenuElementWrapper.created() : super.created() {
+ binder.registerCallback(this);
+ _anchor = getAttribute('anchor');
+ _link = getAttribute('link');
+ _last = _getBoolAttribute('last');
+ createShadowRoot();
+ render();
+ }
+
+ @override
+ void attached() {
+ super.attached();
+ render();
+ }
+
+ void render() {
+ shadowRoot.children = [];
+ if (_anchor == null || _last == null) return;
+
+ shadowRoot.children = [
+ new NavMenuElement(_anchor, link: '#$_link', last: last,
+ queue: ObservatoryApplication.app.queue)
+ ..children = [new ContentElement()]
+ ];
+ }
+
+ bool _getBoolAttribute(String name) {
+ final String value = getAttribute(name);
+ return !(value == null || value == 'false');
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/nav/notify.dart b/runtime/observatory/lib/src/elements/nav/notify.dart
new file mode 100644
index 0000000..ba99f01
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/nav/notify.dart
@@ -0,0 +1,90 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+import 'dart:async';
+import 'package:observatory/models.dart' as M;
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/nav/notify_event.dart';
+import 'package:observatory/src/elements/nav/notify_exception.dart';
+
+class NavNotifyElement extends HtmlElement implements Renderable {
+ static const tag = const Tag<NavNotifyElement>('nav-notify-wrapped',
+ dependencies: const [ NavNotifyEventElement.tag,
+ NavNotifyExceptionElement.tag ]);
+
+ RenderingScheduler _r;
+
+ Stream<RenderedEvent<NavNotifyElement>> get onRendered => _r.onRendered;
+
+ M.NotificationRepository _repository;
+ StreamSubscription _subscription;
+
+ bool _notifyOnPause;
+ bool get notifyOnPause => _notifyOnPause;
+ set notifyOnPause(bool value) =>
+ _notifyOnPause = _r.checkAndReact(_notifyOnPause, value);
+
+ factory NavNotifyElement(M.NotificationRepository repository,
+ {bool notifyOnPause: true, RenderingQueue queue}) {
+ assert(repository != null);
+ assert(notifyOnPause != null);
+ NavNotifyElement e = document.createElement(tag.name);
+ e._r = new RenderingScheduler(e, queue: queue);
+ e._repository = repository;
+ e._notifyOnPause = notifyOnPause;
+ return e;
+ }
+
+ NavNotifyElement.created() : super.created();
+
+ @override
+ void attached() {
+ super.attached();
+ _r.enable();
+ _subscription = _repository.onChange.listen((_) => _r.dirty());
+ }
+
+ @override
+ void detached() {
+ super.detached();
+ children = [];
+ _r.disable(notify: true);
+ _subscription.cancel();
+ }
+
+ void render() {
+ children = [
+ new DivElement()
+ ..children = [
+ new DivElement()
+ ..children = _repository.list()
+ .where(_filter).map(_toElement).toList()
+ ]
+ ];
+ }
+
+ bool _filter(M.Notification notification) {
+ if (!_notifyOnPause && notification is M.EventNotification) {
+ return !M.Event.isPauseEvent(notification.event);
+ }
+ return true;
+ }
+
+ HtmlElement _toElement(M.Notification notification) {
+ if (notification is M.EventNotification) {
+ return new NavNotifyEventElement(notification.event, queue: _r.queue)
+ ..onDelete.listen((_) => _repository.delete(notification));
+ } else if (notification is M.ExceptionNotification) {
+ return new NavNotifyExceptionElement(
+ notification.exception, stacktrace: notification.stacktrace,
+ queue: _r.queue)
+ ..onDelete.listen((_) => _repository.delete(notification));
+ } else {
+ assert(false);
+ return new DivElement()..text = 'Invalid Notification Type';
+ }
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/nav/notify_event.dart b/runtime/observatory/lib/src/elements/nav/notify_event.dart
new file mode 100644
index 0000000..0f75062
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/nav/notify_event.dart
@@ -0,0 +1,232 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+import 'dart:async';
+import 'package:observatory/models.dart' as M;
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/helpers/uris.dart';
+
+class EventDeleteEvent{
+ final M.Event event;
+ EventDeleteEvent(this.event);
+}
+
+class NavNotifyEventElement extends HtmlElement implements Renderable {
+ static const tag = const Tag<NavNotifyEventElement>('nav-event');
+
+ RenderingScheduler _r;
+
+ Stream<RenderedEvent<NavNotifyEventElement>> get onRendered => _r.onRendered;
+
+ final StreamController<EventDeleteEvent> _onDelete =
+ new StreamController<EventDeleteEvent>.broadcast();
+ Stream<EventDeleteEvent> get onDelete => _onDelete.stream;
+
+ M.Event _event;
+ M.Event get event => _event;
+
+ factory NavNotifyEventElement(M.Event event, {RenderingQueue queue}) {
+ assert(event != null);
+ NavNotifyEventElement e = document.createElement(tag.name);
+ e._r = new RenderingScheduler(e, queue: queue);
+ e._event = event;
+ return e;
+ }
+
+ NavNotifyEventElement.created() : super.created();
+
+ @override
+ void attached() {
+ super.attached();
+ _r.enable();
+ }
+
+ @override
+ void detached() {
+ super.detached();
+ children = [];
+ _r.disable(notify: true);
+ }
+
+ void render() {
+ children = [];
+ List<Element> content;
+ if (event is M.PauseStartEvent) {
+ content = _managePauseStartEvent(event as M.PauseStartEvent);
+ } else if (event is M.PauseExitEvent) {
+ content = _managePauseExitEvent(event as M.PauseExitEvent);
+ } else if (event is M.PauseBreakpointEvent) {
+ content = _managePauseBreakpointEvent(event as M.PauseBreakpointEvent);
+ } else if (event is M.PauseInterruptedEvent) {
+ content = _managePauseInterruptedEvent(event as M.PauseInterruptedEvent);
+ } else if (event is M.PauseExceptionEvent) {
+ content = _managePauseExceptionEvent(event as M.PauseExceptionEvent);
+ } else if (event is M.NoneEvent) {
+ content = _manageNoneEvent(event as M.NoneEvent);
+ } else if (event is M.ConnectionClosedEvent) {
+ content = _manageConnectionClosedEvent(event as M.ConnectionClosedEvent);
+ } else if (event is M.InspectEvent) {
+ content = _manageInspectEvent(event as M.InspectEvent);
+ } else if (event is M.IsolateReloadEvent) {
+ content = _manageIsolateReloadEvent(event as M.IsolateReloadEvent);
+ } else {
+ return;
+ }
+ children = [
+ new DivElement()
+ ..children = []
+ ..children.addAll(content)
+ ..children.add(new ButtonElement()..innerHtml = '×'
+ ..onClick.map(_toEvent).listen(_delete))
+ ];
+ }
+
+ static List<Element> _managePauseStartEvent(M.PauseStartEvent event) {
+ return [
+ new SpanElement()..text = 'Isolate ',
+ new AnchorElement(
+ href: Uris.inspect(event.isolate))
+ ..text = event.isolate.name,
+ new SpanElement()..text = ' is paused at isolate start',
+ new BRElement(), new BRElement(), new SpanElement()..text = '[',
+ new AnchorElement(
+ href: Uris.debugger(event.isolate))
+ ..text = 'debug',
+ new SpanElement()..text = ']'
+ ];
+ }
+
+ static List<Element> _managePauseExitEvent(M.PauseExitEvent event) {
+ return [
+ new SpanElement()..text = 'Isolate ',
+ new AnchorElement(
+ href: Uris.inspect(event.isolate))
+ ..text = event.isolate.name,
+ new SpanElement()..text = ' is paused at isolate exit',
+ new BRElement(), new BRElement(), new SpanElement()..text = '[',
+ new AnchorElement(
+ href: Uris.debugger(event.isolate))
+ ..text = 'debug',
+ new SpanElement()..text = ']'
+ ];
+ }
+
+ static List<Element> _managePauseBreakpointEvent(M.PauseBreakpointEvent event) {
+ String message = ' is paused';
+ if (event.breakpoint != null) {
+ message += ' at breakpoint ${event.breakpoint.number}';
+ }
+ return [
+ new SpanElement()..text = 'Isolate ',
+ new AnchorElement(
+ href: Uris.inspect(event.isolate))
+ ..text = event.isolate.name,
+ new SpanElement()
+ ..text = message,
+ new BRElement(), new BRElement(), new SpanElement()..text = '[',
+ new AnchorElement(
+ href: Uris.debugger(event.isolate))
+ ..text = 'debug',
+ new SpanElement()..text = ']'
+ ];
+ }
+
+ static List<Element> _managePauseInterruptedEvent(M.PauseInterruptedEvent event) {
+ return [
+ new SpanElement()..text = 'Isolate ',
+ new AnchorElement(
+ href: Uris.inspect(event.isolate))
+ ..text = event.isolate.name,
+ new SpanElement()
+ ..text = ' is paused',
+ new BRElement(), new BRElement(), new SpanElement()..text = '[',
+ new AnchorElement(
+ href: Uris.debugger(event.isolate))
+ ..text = 'debug',
+ new SpanElement()..text = ']'
+ ];
+ }
+
+ static List<Element> _managePauseExceptionEvent(M.PauseExceptionEvent event) {
+ return [
+ new SpanElement()..text = 'Isolate ',
+ new AnchorElement(
+ href: Uris.inspect(event.isolate))
+ ..text = event.isolate.name,
+ new SpanElement()
+ ..text = ' is paused due to exception',
+ new BRElement(), new BRElement(), new SpanElement()..text = '[',
+ new AnchorElement(
+ href: Uris.debugger(event.isolate))
+ ..text = 'debug',
+ new SpanElement()..text = ']'
+ ];
+ }
+
+ static List<Element> _manageNoneEvent(M.NoneEvent event) {
+ return [
+ new SpanElement()..text = 'Isolate ',
+ new AnchorElement(
+ href: Uris.inspect(event.isolate))
+ ..text = event.isolate.name,
+ new SpanElement()
+ ..text = ' is paused',
+ new BRElement(), new BRElement(), new SpanElement()..text = '[',
+ new AnchorElement(
+ href: Uris.debugger(event.isolate))
+ ..text = 'debug',
+ new SpanElement()..text = ']'
+ ];
+ }
+
+ static List<Element> _manageConnectionClosedEvent(M.ConnectionClosedEvent event) {
+ return [
+ new SpanElement()..text = 'Disconnected from VM: ${event.reason}',
+ new BRElement(), new BRElement(), new SpanElement()..text = '[',
+ new AnchorElement(href: Uris.vmConnect())..text = 'Connect to a VM',
+ new SpanElement()..text = ']'
+ ];
+ }
+
+ static List<Element> _manageInspectEvent(M.InspectEvent event) {
+ return [
+ new SpanElement()..text = 'Inspect ${event.inspectee.id}',
+ new BRElement(), new BRElement(), new SpanElement()..text = '[',
+ new AnchorElement(href: Uris.inspect(event.isolate,
+ object: event.inspectee))
+ ..text = 'Inspect',
+ new SpanElement()..text = ']'
+ // TODO(cbernaschina) add InstanceRefElement back.
+ //new InstanceRefElement()..instance = event.inspectee
+ ];
+ }
+
+ static List<Element> _manageIsolateReloadEvent(M.IsolateReloadEvent event) {
+ if (event.error != null) {
+ return [
+ new SpanElement()..text = 'Isolate reload failed:',
+ new BRElement(), new BRElement(),
+ new DivElement()
+ ..classes = ["indent", "error"]
+ ..text = event.error.message.toString()
+ ];
+ } else {
+ return [new SpanElement()..text = 'Isolate reload'];
+ }
+ }
+
+ EventDeleteEvent _toEvent(_) {
+ return new EventDeleteEvent(_event);
+ }
+
+ void _delete(EventDeleteEvent e) {
+ _onDelete.add(e);
+ }
+
+ void delete() {
+ _onDelete.add(new EventDeleteEvent(_event));
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/nav/notify_exception.dart b/runtime/observatory/lib/src/elements/nav/notify_exception.dart
new file mode 100644
index 0000000..cf0a463
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/nav/notify_exception.dart
@@ -0,0 +1,128 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+import 'dart:async';
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/helpers/uris.dart';
+import 'package:observatory/models.dart' show ConnectionException;
+
+
+class ExceptionDeleteEvent{
+ final Exception exception;
+ final StackTrace stacktrace;
+
+ ExceptionDeleteEvent(this.exception, {this.stacktrace});
+}
+
+class NavNotifyExceptionElement extends HtmlElement implements Renderable {
+ static const tag = const Tag<NavNotifyExceptionElement>('nav-exception');
+
+ RenderingScheduler _r;
+
+ Stream<RenderedEvent<NavNotifyExceptionElement>> get onRendered =>
+ _r.onRendered;
+
+ final StreamController<ExceptionDeleteEvent> _onDelete =
+ new StreamController<ExceptionDeleteEvent>.broadcast();
+ Stream<ExceptionDeleteEvent> get onDelete => _onDelete.stream;
+
+ Exception _exception;
+ StackTrace _stacktrace;
+ Exception get exception => _exception;
+ StackTrace get stacktrace => _stacktrace;
+
+ factory NavNotifyExceptionElement(Exception exception,
+ {StackTrace stacktrace: null, RenderingQueue queue}) {
+ assert(exception != null);
+ NavNotifyExceptionElement e = document.createElement(tag.name);
+ e._r = new RenderingScheduler(e, queue: queue);
+ e._exception = exception;
+ e._stacktrace = stacktrace;
+ return e;
+ }
+
+ NavNotifyExceptionElement.created() : super.created();
+
+ @override
+ void attached() {
+ super.attached();
+ _r.enable();
+ }
+
+ @override
+ void detached() {
+ super.detached();
+ children = [];
+ _r.disable(notify: true);
+ }
+
+ void render() {
+ if (exception is ConnectionException) {
+ renderConnectionException();
+ } else {
+ renderGenericException();
+ }
+ }
+
+ void renderConnectionException() {
+ children = [
+ new DivElement()
+ ..children = [
+ new SpanElement()..text = 'The request cannot be completed because the '
+ 'VM is currently disconnected',
+ new BRElement(), new BRElement(),
+ new SpanElement()..text = '[',
+ new AnchorElement(href: Uris.vmConnect())
+ ..text = 'Connect to a different VM',
+ new SpanElement()..text = ']',
+ new ButtonElement()..innerHtml = '×'
+ ..onClick.map(_toEvent).listen(_delete)
+ ]
+ ];
+ }
+
+ void renderGenericException() {
+ List<Node> content;
+ content = [
+ new SpanElement()..text = 'Unexpected exception:',
+ new BRElement(), new BRElement(),
+ new DivElement()..text = exception.toString(),
+ new BRElement()
+ ];
+ if (stacktrace != null) {
+ content.addAll([
+ new SpanElement()..text = 'Stacktrace:',
+ new BRElement(), new BRElement(),
+ new DivElement()..text = stacktrace.toString(),
+ new BRElement()
+ ]);
+ }
+ content.addAll([
+ new SpanElement()..text = '[',
+ new AnchorElement(href: Uris.vmConnect())
+ ..text = 'Connect to a different VM',
+ new SpanElement()..text = ']',
+ new ButtonElement()..innerHtml = '×'
+ ..onClick.map(_toEvent).listen(_delete)
+ ]);
+ children = [
+ new DivElement()
+ ..children = content
+ ];
+ }
+
+ ExceptionDeleteEvent _toEvent(_) {
+ return new ExceptionDeleteEvent(exception, stacktrace: stacktrace);
+ }
+
+ void _delete(ExceptionDeleteEvent e) {
+ _onDelete.add(e);
+ }
+
+ void delete() {
+ _onDelete.add(new ExceptionDeleteEvent(exception, stacktrace: stacktrace));
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/nav/notify_wrapper.dart b/runtime/observatory/lib/src/elements/nav/notify_wrapper.dart
new file mode 100644
index 0000000..97f4ded
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/nav/notify_wrapper.dart
@@ -0,0 +1,123 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+
+import 'package:observatory/app.dart';
+import 'package:observatory/repositories.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/shims/binding.dart';
+import 'package:observatory/src/elements/nav/notify.dart';
+
+class NavNotifyElementWrapper extends HtmlElement {
+ static final binder = new Binder<NavNotifyElementWrapper>(
+ const [const Binding('notifications'), const Binding('notifyOnPause')]);
+
+ static const tag = const Tag<NavNotifyElementWrapper>('nav-notify');
+
+ NotificationRepository _notifications;
+ bool _notifyOnPause = true;
+ NotificationRepository get notifications => _notifications;
+ bool get notifyOnPause => _notifyOnPause;
+ set notifications(NotificationRepository value) {
+ _notifications = value; render();
+ }
+ set notifyOnPause(bool value) {
+ _notifyOnPause = value; render();
+ }
+
+ NavNotifyElementWrapper.created() : super.created() {
+ binder.registerCallback(this);
+ createShadowRoot();
+ render();
+ }
+
+ @override
+ void attached() {
+ super.attached();
+ render();
+ }
+
+ void render() {
+ shadowRoot.children = [];
+ if (_notifications == null) return;
+
+ shadowRoot.children = [
+ new StyleElement()
+ ..text = '''nav-notify-wrapped > div {
+ float: right;
+ }
+ nav-notify-wrapped > div > div {
+ display: block;
+ position: absolute;
+ top: 98%;
+ right: 0;
+ margin: 0;
+ padding: 0;
+ width: auto;
+ z-index: 1000;
+ background: none;
+ }
+
+ /* nav-exception & nav-event */
+
+ nav-exception > div, nav-event > div {
+ position: relative;
+ padding: 16px;
+ margin-top: 10px;
+ margin-right: 10px;
+ padding-right: 25px;
+ width: 500px;
+ color: #ddd;
+ background: rgba(0,0,0,.6);
+ border: solid 2px white;
+ box-shadow: 0 0 5px black;
+ border-radius: 5px;
+ animation: fadein 1s;
+ }
+
+ nav-exception *, nav-event * {
+ color: #ddd;
+ font-size: 12px;
+ }
+
+ nav-exception > div > a, nav-event > div > a {
+ color: white;
+ text-decoration: none;
+ }
+
+ nav-exception > div > a:hover, nav-event > div > a:hover {
+ text-decoration: underline;
+ }
+
+ nav-exception > div > div {
+ margin-left:20px;
+ white-space: pre
+ }
+
+ nav-exception > div > button, nav-event > div > button {
+ background: transparent;
+ border: none;
+ position: absolute;
+ display: block;
+ top: 4px;
+ right: 4px;
+ height: 18px;
+ width: 18px;
+ line-height: 16px;
+ border-radius: 9px;
+ color: white;
+ font-size: 18px;
+ cursor: pointer;
+ text-align: center;
+ }
+
+ nav-exception > div > button:hover, nav-event > div > button:hover {
+ background: rgba(255,255,255,0.5);
+ }''',
+ new NavNotifyElement(_notifications, notifyOnPause: notifyOnPause,
+ queue: ObservatoryApplication.app.queue)
+ ];
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/nav/refresh.dart b/runtime/observatory/lib/src/elements/nav/refresh.dart
new file mode 100644
index 0000000..795c7bd
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/nav/refresh.dart
@@ -0,0 +1,77 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+import 'dart:async';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+
+class RefreshEvent {
+ final NavRefreshElement element;
+ RefreshEvent(this.element);
+}
+
+class NavRefreshElement extends HtmlElement implements Renderable {
+ static const tag = const Tag<NavRefreshElement>('nav-refresh-wrapped');
+
+ RenderingScheduler _r;
+
+ Stream<RenderedEvent<NavRefreshElement>> get onRendered => _r.onRendered;
+
+ final StreamController<RefreshEvent> _onRefresh =
+ new StreamController<RefreshEvent>.broadcast();
+ Stream<RefreshEvent> get onRefresh => _onRefresh.stream;
+
+ bool _disabled;
+ String _label;
+ bool get disabled => _disabled;
+ String get label => _label;
+ set disabled(bool value) => _disabled = _r.checkAndReact(_disabled, value);
+ set label(String value) => _label = _r.checkAndReact(_label, value);
+
+ factory NavRefreshElement({String label: 'Refresh', bool disabled: false,
+ RenderingQueue queue}) {
+ assert(label != null);
+ assert(disabled != null);
+ NavRefreshElement e = document.createElement(tag.name);
+ e._r = new RenderingScheduler(e, queue: queue);
+ e._label = label;
+ e._disabled = disabled;
+ return e;
+ }
+
+ NavRefreshElement.created() : super.created();
+
+ @override
+ void attached() { super.attached(); _r.enable(); }
+
+ @override
+ void detached() { super.detached(); children = []; _r.disable(notify: true); }
+
+ void render() {
+ children = [
+ new LIElement()
+ ..children = [
+ new ButtonElement()
+ ..text = label
+ ..disabled = disabled
+ ..onClick.map(_toEvent).listen(_refresh)
+ ]
+ ];
+ }
+
+ RefreshEvent _toEvent(_) {
+ return new RefreshEvent(this);
+ }
+
+ void _refresh(RefreshEvent e) {
+ if (_disabled) return;
+ _onRefresh.add(e);
+ }
+
+ void refresh() {
+ if (_disabled) return;
+ _refresh(new RefreshEvent(this));
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/nav/refresh_wrapper.dart b/runtime/observatory/lib/src/elements/nav/refresh_wrapper.dart
new file mode 100644
index 0000000..dcd1696
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/nav/refresh_wrapper.dart
@@ -0,0 +1,78 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+import 'dart:async';
+
+import 'package:observatory/app.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/shims/binding.dart';
+import 'package:observatory/src/elements/nav/refresh.dart';
+
+class NavRefreshElementWrapper extends HtmlElement {
+ static final binder = new Binder<NavRefreshElementWrapper>(
+ const [const Binding('callback'), const Binding('label')]);
+
+ static const tag = const Tag<NavRefreshElementWrapper>('nav-refresh');
+
+ Function _callback;
+ String _label;
+ Function get callback => _callback;
+ String get label => _label;
+ set callback(Function value) {
+ _callback = value; render();
+ }
+ set label(String value) {
+ _label = value; render();
+ }
+
+ NavRefreshElementWrapper.created() : super.created() {
+ binder.registerCallback(this);
+ _label = getAttribute('label') ?? 'Refresh';
+ createShadowRoot();
+ render();
+ }
+
+ @override
+ void attached() {
+ super.attached();
+ render();
+ }
+
+ void render() {
+ shadowRoot.children = [];
+ if (_callback == null || _label == null) return;
+
+ shadowRoot.children = [
+ new StyleElement()
+ ..text = '''nav-refresh-wrapped > li > button {
+ color: #000;
+ margin: 3px;
+ padding: 8px;
+ border-width: 2px;
+ line-height: 13px;
+ font: 400 13px 'Montserrat', sans-serif;
+ }
+ nav-refresh-wrapped > li > button[disabled] {
+ color: #aaa;
+ cursor: wait;
+ }
+ nav-refresh-wrapped > li {
+ float: right;
+ margin: 0;
+ }''',
+ new NavRefreshElement(label: _label,
+ queue: ObservatoryApplication.app.queue)
+ ..onRefresh.listen((event) async{
+ event.element.disabled = true;
+ try {
+ var future = callback();
+ if (future is Future) await future;
+ } finally {
+ event.element.disabled = false;
+ }
+ })
+ ];
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/nav/top_menu.dart b/runtime/observatory/lib/src/elements/nav/top_menu.dart
new file mode 100644
index 0000000..a289277
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/nav/top_menu.dart
@@ -0,0 +1,60 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+import 'dart:async';
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/helpers/uris.dart';
+import 'package:observatory/src/elements/nav/menu.dart';
+import 'package:observatory/src/elements/nav/menu_item.dart';
+
+class NavTopMenuElement extends HtmlElement implements Renderable {
+ static const tag = const Tag<NavTopMenuElement>('nav-top-menu',
+ dependencies: const [NavMenuElement.tag,
+ NavMenuItemElement.tag]);
+
+ RenderingScheduler _r;
+
+ Stream<RenderedEvent<NavTopMenuElement>> get onRendered => _r.onRendered;
+
+ bool _last;
+ bool get last => _last;
+ set last(bool value) => _last = _r.checkAndReact(_last, value);
+
+ factory NavTopMenuElement({bool last: false, RenderingQueue queue}) {
+ assert(last != null);
+ NavTopMenuElement e = document.createElement(tag.name);
+ e._r = new RenderingScheduler(e, queue: queue);
+ e._last = last;
+ return e;
+ }
+
+ NavTopMenuElement.created() : super.created() { createShadowRoot(); }
+
+ @override
+ void attached() {
+ super.attached();
+ _r.enable();
+ }
+
+ @override
+ void detached() {
+ super.detached();
+ _r.disable(notify: true);
+ shadowRoot.children = [];
+ }
+
+ void render() {
+ shadowRoot.children = [
+ new NavMenuElement('Observatory', link: Uris.vm(), last: last,
+ queue: _r.queue)
+ ..children = [
+ new NavMenuItemElement('Connect to a VM', link: Uris.vmConnect(),
+ queue: _r.queue),
+ new ContentElement()
+ ]
+ ];
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/nav/top_menu_wrapper.dart b/runtime/observatory/lib/src/elements/nav/top_menu_wrapper.dart
new file mode 100644
index 0000000..fbfebff
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/nav/top_menu_wrapper.dart
@@ -0,0 +1,51 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+
+import 'package:observatory/app.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/shims/binding.dart';
+import 'package:observatory/src/elements/nav/top_menu.dart';
+
+class NavTopMenuElementWrapper extends HtmlElement {
+ static final binder = new Binder<NavTopMenuElementWrapper>(
+ const [const Binding('last')]);
+
+ static const tag = const Tag<NavTopMenuElementWrapper>('top-nav-menu');
+
+ bool _last = false;
+ bool get last => _last;
+ set last(bool value) {
+ _last = value; render();
+ }
+
+ NavTopMenuElementWrapper.created() : super.created() {
+ binder.registerCallback(this);
+ _last = _getBoolAttribute('last');
+ createShadowRoot();
+ render();
+ }
+
+ @override
+ void attached() {
+ super.attached();
+ render();
+ }
+
+ void render() {
+ shadowRoot.children = [];
+ if (_last == null) return;
+
+ shadowRoot.children = [
+ new NavTopMenuElement(last: last, queue: ObservatoryApplication.app.queue)
+ ..children = [new ContentElement()]
+ ];
+ }
+
+ bool _getBoolAttribute(String name) {
+ final String value = getAttribute(name);
+ return !(value == null || value == 'false');
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/nav/vm_menu.dart b/runtime/observatory/lib/src/elements/nav/vm_menu.dart
new file mode 100644
index 0000000..a46d4ca
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/nav/vm_menu.dart
@@ -0,0 +1,84 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+import 'dart:async';
+import 'package:observatory/models.dart' as M
+ show VM, IsolateRef, Target, VMUpdateEvent;
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/helpers/uris.dart';
+import 'package:observatory/src/elements/nav/menu.dart';
+import 'package:observatory/src/elements/nav/menu_item.dart';
+
+class NavVMMenuElement extends HtmlElement implements Renderable {
+ static const tag = const Tag<NavVMMenuElement>('nav-vm-menu',
+ dependencies: const [NavMenuElement.tag,
+ NavMenuItemElement.tag]);
+
+ RenderingScheduler _r;
+
+ Stream<RenderedEvent<NavVMMenuElement>> get onRendered => _r.onRendered;
+
+ Stream<M.VMUpdateEvent> _updates;
+ StreamSubscription _updatesSubscription;
+
+ bool _last;
+ M.VM _vm;
+ M.Target _target;
+ bool get last => _last;
+ M.VM get vm => _vm;
+ M.Target get target => _target;
+ set last(bool value) => _last = _r.checkAndReact(_last, value);
+
+ factory NavVMMenuElement(M.VM vm, Stream<M.VMUpdateEvent> updates,
+ {bool last: false, M.Target target, RenderingQueue queue}) {
+ assert(vm != null);
+ assert(updates != null);
+ assert(last != null);
+ NavVMMenuElement e = document.createElement(tag.name);
+ e._r = new RenderingScheduler(e, queue: queue);
+ e._vm = vm;
+ e._updates = updates;
+ e._last = last;
+ e._target = target;
+ return e;
+ }
+
+ NavVMMenuElement.created() : super.created() { createShadowRoot(); }
+
+ @override
+ void attached() {
+ super.attached();
+ _r.enable();
+ _updatesSubscription = _updates
+ .listen((M.VMUpdateEvent e) { _vm = e.vm; _r.dirty(); });
+ }
+
+ @override
+ void detached() {
+ super.detached();
+ _r.disable(notify: true);
+ shadowRoot.children = [];
+ assert(_updatesSubscription != null);
+ _updatesSubscription.cancel();
+ _updatesSubscription = null;
+ }
+
+ void render() {
+ final String name = (target == null) ? vm.name
+ : '${vm.name}@${target.name}';
+ /// TODO(cbernaschina) use the isolate repository.
+ shadowRoot.children = [
+ new NavMenuElement(name, link: Uris.vm(), last: last, queue: _r.queue)
+ ..children = (
+ _vm.isolates.map((M.IsolateRef isolate) {
+ return new NavMenuItemElement(isolate.name, queue: _r.queue,
+ link: Uris.inspect(isolate));
+ }).toList()
+ ..add(new ContentElement())
+ )
+ ];
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/nav/vm_menu_wrapper.dart b/runtime/observatory/lib/src/elements/nav/vm_menu_wrapper.dart
new file mode 100644
index 0000000..ef71b2d
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/nav/vm_menu_wrapper.dart
@@ -0,0 +1,89 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+import 'dart:async';
+
+import 'package:observatory/app.dart';
+import 'package:observatory/mocks.dart';
+import 'package:observatory/models.dart' as M;
+import 'package:observatory/service.dart';
+import 'package:observatory/service_common.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/shims/binding.dart';
+import 'package:observatory/src/elements/nav/vm_menu.dart';
+
+class NavVMMenuElementWrapper extends HtmlElement {
+ static final binder = new Binder<NavVMMenuElementWrapper>(
+ const [const Binding('last'), const Binding('vm')]);
+
+ static const tag = const Tag<NavVMMenuElementWrapper>('vm-nav-menu');
+
+ StreamSubscription _subscription;
+ StreamController<M.VMUpdateEvent> _updatesController =
+ new StreamController<M.VMUpdateEvent>.broadcast();
+
+ bool _last = false;
+ VM _vm;
+ bool get last => _last;
+ VM get vm => _vm;
+ set last(bool value) {
+ _last = value; render();
+ }
+ set vm(VM value) {
+ _vm = value; _detached(); _attached();
+ }
+
+ NavVMMenuElementWrapper.created() : super.created() {
+ binder.registerCallback(this);
+ _last = _getBoolAttribute('last');
+ createShadowRoot();
+ render();
+ }
+
+ @override
+ void attached() {
+ super.attached();
+ _attached();
+ }
+
+ @override
+ void detached() {
+ super.detached();
+ _detached();
+ }
+
+ void _attached() {
+ if (_vm != null) {
+ _subscription = _vm.changes.listen((_) {
+ _updatesController.add(new VMUpdateEventMock(vm: _vm));
+ });
+ }
+ render();
+ }
+
+ void _detached() {
+ if (_subscription != null) {
+ _subscription.cancel();
+ _subscription = null;
+ }
+ }
+
+ void render() {
+ shadowRoot.children = [];
+ if (_vm == null || _last == null) return;
+
+ shadowRoot.children = [
+ new NavVMMenuElement(vm, _updatesController.stream, last: last,
+ target: (vm as CommonWebSocketVM)?.target,
+ queue: ObservatoryApplication.app.queue)
+ ..children = [new ContentElement()]
+ ];
+ }
+
+ bool _getBoolAttribute(String name) {
+ final String value = getAttribute(name);
+ return !(value == null || value == 'false');
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/nav_bar.dart b/runtime/observatory/lib/src/elements/nav_bar.dart
deleted file mode 100644
index 3999db87..0000000
--- a/runtime/observatory/lib/src/elements/nav_bar.dart
+++ /dev/null
@@ -1,164 +0,0 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library nav_bar_element;
-
-import 'dart:async';
-import 'dart:html' hide Notification;
-import 'observatory_element.dart';
-import 'package:observatory/service.dart';
-import 'package:observatory/app.dart' show Notification;
-import 'package:polymer/polymer.dart';
-
-
-@CustomTag('nav-bar')
-class NavBarElement extends ObservatoryElement {
- @published bool notifyOnPause = true;
- @published bool pad = true;
-
- // Desired nav var height in pixels.
- static const height = 40;
-
- NavBarElement.created() : super.created();
-}
-
-@CustomTag('nav-menu')
-class NavMenuElement extends ObservatoryElement {
- @published String link = '#';
- @published String anchor = '---';
- @published bool last = false;
-
- NavMenuElement.created() : super.created();
-}
-
-@CustomTag('nav-menu-item')
-class NavMenuItemElement extends ObservatoryElement {
- @published String link = '#';
- @published String anchor = '---';
-
- NavMenuItemElement.created() : super.created();
-}
-
-typedef Future RefreshCallback();
-
-@CustomTag('nav-refresh')
-class NavRefreshElement extends ObservatoryElement {
- @published RefreshCallback callback;
- @published bool active = false;
- @published String label = 'Refresh';
-
- NavRefreshElement.created() : super.created();
-
- void buttonClick(Event e, var detail, Node target) {
- if (active) {
- return;
- }
- active = true;
- if (callback != null) {
- callback()
- .catchError(app.handleException)
- .whenComplete(refreshDone);
- }
- }
-
- void refreshDone() {
- active = false;
- }
-}
-
-@CustomTag('top-nav-menu')
-class TopNavMenuElement extends ObservatoryElement {
- @published bool last = false;
-
- TopNavMenuElement.created() : super.created();
-}
-
-@CustomTag('vm-nav-menu')
-class VMNavMenuElement extends ObservatoryElement {
- @published bool last = false;
- @published VM vm;
-
- String nameAndAddress(name, target) {
- if (name != null && target != null) {
- return '${name}@${target.networkAddress}';
- } else {
- return '<initializing>';
- }
- }
-
- VMNavMenuElement.created() : super.created();
-}
-
-@CustomTag('isolate-nav-menu')
-class IsolateNavMenuElement extends ObservatoryElement {
- @published bool last = false;
- @published Isolate isolate;
-
- IsolateNavMenuElement.created() : super.created();
-}
-
-@CustomTag('library-nav-menu')
-class LibraryNavMenuElement extends ObservatoryElement {
- @published Library library;
- @published bool last = false;
-
- LibraryNavMenuElement.created() : super.created();
-}
-
-@CustomTag('class-nav-menu')
-class ClassNavMenuElement extends ObservatoryElement {
- @published Class cls;
- @published bool last = false;
-
- ClassNavMenuElement.created() : super.created();
-}
-
-@CustomTag('nav-notify')
-class NavNotifyElement extends ObservatoryElement {
- @published ObservableList<Notification> notifications;
- @published bool notifyOnPause = true;
-
- NavNotifyElement.created() : super.created();
-}
-
-@CustomTag('nav-notify-event')
-class NavNotifyEventElement extends ObservatoryElement {
- @published ObservableList<Notification> notifications;
- @published Notification notification;
- @published ServiceEvent event;
- @published bool notifyOnPause = true;
-
- void closeItem(MouseEvent e, var detail, Element target) {
- notifications.remove(notification);
- }
-
- NavNotifyEventElement.created() : super.created();
-}
-
-@CustomTag('nav-notify-exception')
-class NavNotifyExceptionElement extends ObservatoryElement {
- @published ObservableList<Notification> notifications;
- @published Notification notification;
- @published var exception;
- @published var stacktrace;
-
- exceptionChanged() {
- notifyPropertyChange(#isNetworkError, true, false);
- notifyPropertyChange(#isUnexpectedError, true, false);
- }
-
- @observable get isNetworkError {
- return (exception is NetworkRpcException);
- }
-
- @observable get isUnexpectedError {
- return (exception is! NetworkRpcException);
- }
-
- void closeItem(MouseEvent e, var detail, Element target) {
- notifications.remove(notification);
- }
-
- NavNotifyExceptionElement.created() : super.created();
-}
diff --git a/runtime/observatory/lib/src/elements/nav_bar.html b/runtime/observatory/lib/src/elements/nav_bar.html
deleted file mode 100644
index c97b1d1..0000000
--- a/runtime/observatory/lib/src/elements/nav_bar.html
+++ /dev/null
@@ -1,486 +0,0 @@
-<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="action_link.html">
-<link rel="import" href="observatory_element.html">
-
-<polymer-element name="nav-bar" extends="observatory-element">
- <template>
- <link rel="stylesheet" href="css/shared.css">
- <style>
- nav {
- position: fixed;
- width: 100%;
- z-index: 1000;
- }
- nav ul {
- display: inline-table;
- position: relative;
- list-style: none;
- padding-left: 0;
- margin-left: 0;
- width: 100%;
- z-index: 1000;
- font: 400 16px 'Montserrat', sans-serif;
- color: white;
- background-color: #0489c3;
- }
- nav ul:after {
- content: ""; clear: both; display: block;
- }
- .vertical-spacer {
- height: 40px;
- background-color: #0489c3;
- }
- </style>
- <nav>
- <ul>
- <nav-notify notifications="{{ app.notifications }}"
- notifyOnPause="{{ notifyOnPause }}"></nav-notify>
- <content></content>
- </ul>
- </nav>
- <div class="vertical-spacer">
- </div>
- <template if="{{ pad }}">
- <br>
- </template>
- </template>
-</polymer-element>
-
-<polymer-element name="nav-menu" extends="observatory-element">
- <template>
- <style>
- .menu, .spacer {
- float: left;
- }
- .menu a, .spacer {
- display: block;
- padding: 12px 8px;
- color: White;
- text-decoration: none;
- }
- .menu:hover {
- background: #455;
- }
- .menu ul {
- display: none;
- position: absolute;
- top: 98%;
- list-style: none;
- margin: 0;
- padding: 0;
- width: auto;
- z-index: 1000;
- font: 400 16px 'Montserrat', sans-serif;
- color: white;
- background: #567;
- }
- .menu ul:after {
- content: ""; clear: both; display: block;
- }
- .menu:hover > ul {
- display: block;
- }
- </style>
-
- <li class="menu">
- <a on-click="{{ goto }}" _href="{{ gotoLink(link) }}">{{ anchor }}</a>
- <ul><content></content></ul>
- </li>
- <template if="{{ !last }}">
- <li class="spacer">></li>
- </template>
-
- </template>
-</polymer-element>
-
-<polymer-element name="nav-menu-item" extends="observatory-element">
- <template>
- <style>
- li {
- float: none;
- border-top: 1px solid #677;
- border-bottom: 1px solid #556; position: relative;
- }
- li:hover {
- background: #455;
- }
- li ul {
- display: none;
- position: absolute;
- top:0;
- left: 100%;
- list-style: none;
- padding: 0;
- margin-left: 0;
- width: auto;
- z-index: 1000;
- font: 400 16px 'Montserrat', sans-serif;
- color: white;
- background: #567;
- }
- li ul:after {
- content: ""; clear: both; display: block;
- }
- li:hover > ul {
- display: block;
- }
- li a {
- display: block;
- padding: 12px 12px;
- color: white;
- text-decoration: none;
- }
- </style>
- <li><a on-click="{{ goto }}" _href="{{ gotoLink(link) }}">{{ anchor }}</a>
- <ul><content></content></ul>
- </li>
- </template>
-</polymer-element>
-
-<polymer-element name="nav-refresh" extends="observatory-element">
- <template>
- <style>
- .active {
- color: #aaa;
- cursor: wait;
- }
- .idle {
- color: #000;
- }
- li {
- float: right;
- margin: 0;
- }
- li button {
- margin: 3px;
- padding: 8px;
- }
- </style>
- <li>
- <template if="{{ active }}">
- <button class="active" on-click="{{ buttonClick }}">{{ label }}</button>
- </template>
- <template if="{{ !active }}">
- <button class="idle" on-click="{{ buttonClick }}">{{ label }}</button>
- </template>
- </li>
- </template>
-</polymer-element>
-
-<polymer-element name="top-nav-menu">
- <template>
- <nav-menu link="/vm" anchor="Observatory" last="{{ last }}">
- <nav-menu-item link="/vm-connect" anchor="Connect to a VM"></nav-menu-item>
- <content></content>
- </nav-menu>
- </template>
-</polymer-element>
-
-<polymer-element name="vm-nav-menu">
- <template>
- <nav-menu link="/vm" anchor="{{ nameAndAddress(vm.name, vm.target) }}" last="{{ last }}">
- <template repeat="{{ isolate in vm.isolates }}">
- <nav-menu-item link="{{ makeLink('/inspect', isolate) }}"
- anchor="{{ isolate.name }}"></nav-menu-item>
- </template>
- <content></content>
- </nav-menu>
- </template>
-</polymer-element>
-
-<polymer-element name="isolate-nav-menu" extends="observatory-element">
- <template>
- <nav-menu link="{{ makeLink('/inspect', isolate) }}" anchor="{{ isolate.name }}" last="{{ last }}">
- <nav-menu-item link="{{ makeLink('/debugger', isolate) }}"
- anchor="debugger"></nav-menu-item>
- <nav-menu-item link="{{ makeLink('/class-tree', isolate) }}"
- anchor="class hierarchy"></nav-menu-item>
- <nav-menu-item link="{{ makeLink('/profiler', isolate) }}"
- anchor="cpu profile"></nav-menu-item>
- <nav-menu-item link="{{ makeLink('/profiler-table', isolate) }}"
- anchor="cpu profile (table)"></nav-menu-item>
- <nav-menu-item link="{{ makeLink('/allocation-profiler', isolate) }}"
- anchor="allocation profile"></nav-menu-item>
- <nav-menu-item link="{{ makeLink('/heap-map', isolate) }}"
- anchor="heap map"></nav-menu-item>
- <nav-menu-item link="{{ makeLink('/metrics', isolate) }}"
- anchor="metrics"></nav-menu-item>
- <nav-menu-item link="{{ makeLink('/heap-snapshot', isolate) }}"
- anchor="heap snapshot"></nav-menu-item>
- <nav-menu-item link="{{ makeLink('/persistent-handles', isolate) }}"
- anchor="persistent handles"></nav-menu-item>
- <nav-menu-item link="{{ makeLink('/ports', isolate) }}"
- anchor="ports"></nav-menu-item>
- <nav-menu-item link="{{ makeLink('/logging', isolate) }}"
- anchor="logging"></nav-menu-item>
- <content></content>
- </nav-menu>
- </template>
-</polymer-element>
-
-<polymer-element name="library-nav-menu" extends="observatory-element">
- <template>
- <nav-menu link="{{ makeLink('/inspect', library) }}"
- anchor="{{ library.name }}" last="{{ last }}">
- <content></content>
- </nav-menu>
- </template>
-</polymer-element>
-
-<polymer-element name="class-nav-menu" extends="observatory-element">
- <template>
- <nav-menu link="{{ makeLink('/inspect', cls) }}"
- anchor="{{ cls.name }}" last="{{ last }}">
- <content></content>
- </nav-menu>
- </template>
-</polymer-element>
-
-<polymer-element name="nav-notify" extends="observatory-element">
- <template>
- <style>
- .menu {
- float: right;
- }
- .menu .list {
- display: block;
- position: absolute;
- top: 98%;
- right: 0;
- margin: 0;
- padding: 0;
- width: auto;
- z-index: 1000;
- font: 400 12px 'Montserrat', sans-serif;
- color: white;
- background: none;
- }
- </style>
-
- <div class="menu">
- <div class="list">
- <template repeat="{{ notification in notifications }}">
- <template if="{{ notification.event != null }}">
- <nav-notify-event notifications="{{ notifications }}"
- notification="{{ notification }}"
- event="{{ notification.event }}"
- notifyOnPause="{{ notifyOnPause }}">
- </nav-notify-event>
- </template>
- <template if="{{ notification.exception != null }}">
- <nav-notify-exception notifications="{{ notifications }}"
- notification="{{ notification }}"
- exception="{{ notification.exception }}"
- stacktrace="{{ notification.stacktrace }}">
- </nav-notify-exception>
- </template>
- </template>
- </div>
- </div>
- </template>
-</polymer-element>
-
-<polymer-element name="nav-notify-event" extends="observatory-element">
- <template>
- <style>
- .item {
- position: relative;
- padding: 16px;
- margin-top: 10px;
- margin-right: 10px;
- padding-right: 25px;
- width: 250px;
- color: #ddd;
- background: rgba(0,0,0,.6);
- border: solid 2px white;
- box-shadow: 0 0 5px black;
- border-radius: 5px;
- animation: fadein 1s;
- }
-
- .wide-item {
- width: 50vw;
- }
-
- @keyframes fadein {
- from { opacity: 0; }
- to { opacity: 1; }
- }
-
- a.link {
- color: white;
- text-decoration: none;
- }
- a.link:hover {
- text-decoration: underline;
- }
-
- a.boxclose {
- position: absolute;
- display: block;
- top: 4px;
- right: 4px;
- height: 18px;
- width: 18px;
- line-height: 16px;
- border-radius: 9px;
- color: white;
- font-size: 18px;
- cursor: pointer;
- text-align: center;
- }
- a.boxclose:hover {
- background: rgba(255,255,255,0.5);
- }
- .error {
- white-space: pre;
- }
- </style>
- <template if="{{ event != null }}">
- <template if="{{ notifyOnPause && event.isPauseEvent }}">
- <div class="item">
- Isolate
- <a class="link" on-click="{{ goto }}"
- _href="{{ gotoLink('/inspect', event.isolate) }}">{{ event.isolate.name }}</a>
- is paused
- <template if="{{ event.kind == 'PauseStart' }}">
- at isolate start
- </template>
- <template if="{{ event.kind == 'PauseExit' }}">
- at isolate exit
- </template>
- <template if="{{ event.breakpoint != null }}">
- at breakpoint {{ event.breakpoint.number }}
- </template>
- <template if="{{ event.kind == 'PauseException' }}">
- due to exception
- </template>
-
- <br><br>
- [<a class="link" on-click="{{ goto }}"
- _href="{{ gotoLink('/debugger', event.isolate) }}">debug</a>]
-
- <a class="boxclose" on-click="{{ closeItem }}">×</a>
- </div>
- </template>
- <template if="{{ event.kind == 'ConnectionClosed' }}">
- <div class="item">
- Disconnected from VM: {{ event.reason }}
- <br><br>
- [<a class="link" on-click="{{ goto }}"
- _href="{{ gotoLink('/vm-connect') }}">Connect to a VM</a>]
- <a class="boxclose" on-click="{{ closeItem }}">×</a>
- </div>
- </template>
- <template if="{{ event.kind == 'Inspect' }}">
- <div class="item">
- Inspect <any-service-ref ref="{{ event.inspectee }}"></any-service-ref>
- <br><br>
- <a class="boxclose" on-click="{{ closeItem }}">×</a>
- </div>
- </template>
- <template if="{{ event.kind == 'IsolateReload' }}">
- <div class="wide-item item">
- Isolate reload
- <template if="{{ event.reloadError != null }}">
- failed:
- <br>
- <br>
- <div class="indent error">{{ event.reloadError.message.toString() }}</div><br>
- </template>
- <template if="{{ event.reloadError == null }}">
- succeeded
- </template>
- <a class="boxclose" on-click="{{ closeItem }}">×</a>
- </div>
- </template>
- </template>
- </template>
-</polymer-element>
-
-
-<polymer-element name="nav-notify-exception" extends="observatory-element">
- <template>
- <style>
- .item {
- position: relative;
- padding: 16px;
- margin-top: 10px;
- margin-right: 10px;
- padding-right: 25px;
- width: 500px;
- color: #ddd;
- background: rgba(0,0,0,.6);
- border: solid 2px white;
- box-shadow: 0 0 5px black;
- border-radius: 5px;
- animation: fadein 1s;
- }
-
- @keyframes fadein {
- from { opacity: 0; }
- to { opacity: 1; }
- }
-
- a.link {
- color: white;
- text-decoration: none;
- }
- a.link:hover {
- text-decoration: underline;
- }
- .indent {
- margin-left:20px;
- }
-
- a.boxclose {
- position: absolute;
- display: block;
- top: 4px;
- right: 4px;
- height: 18px;
- width: 18px;
- line-height: 16px;
- border-radius: 9px;
- color: white;
- font-size: 18px;
- cursor: pointer;
- text-align: center;
- }
- a.boxclose:hover {
- background: rgba(255,255,255,0.5);
- }
- .stacktrace {
- white-space: pre
- }
- </style>
- <template if="{{ isUnexpectedError }}">
- <!-- TODO(turnidge): Add a file-a-bug link to this notification -->
- <div class="item">
- Unexpected exception:<br><br>
- <div class="indent">{{ exception.toString() }}</div><br>
- <template if="{{ stacktrace != null }}">
- Stacktrace:<br><br>
- <div class="indent stacktrace">{{ stacktrace.toString() }}</div>
- <br>
- </template>
- [<a class="link" on-click="{{ goto }}"
- _href="{{ gotoLink('vm-connect') }}">Connect to a different VM</a>]
- <a class="boxclose" on-click="{{ closeItem }}">×</a>
- </div>
- </template>
- <template if="{{ isNetworkError }}">
- <div class="item">
- The request cannot be completed because the VM is currently
- disconnected.
- <br><br>
- [<a class="link" on-click="{{ goto }}"
- _href="{{ gotoLink('vm-connect') }}">Connect to a different VM</a>]
- <a class="boxclose" on-click="{{ closeItem }}">×</a>
- </div>
- </template>
- </template>
-</polymer-element>
-
-
-<script type="application/dart" src="nav_bar.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/object_common.html b/runtime/observatory/lib/src/elements/object_common.html
index 14311e0..c0167ea 100644
--- a/runtime/observatory/lib/src/elements/object_common.html
+++ b/runtime/observatory/lib/src/elements/object_common.html
@@ -5,11 +5,9 @@
<link rel="import" href="function_ref.html">
<link rel="import" href="inbound_reference.html">
<link rel="import" href="instance_ref.html">
-<link rel="import" href="observatory_element.html">
-<link rel="import" href="nav_bar.html">
<link rel="import" href="eval_link.html">
-<polymer-element name="object-common" extends="observatory-element">
+<polymer-element name="object-common">
<template>
<link rel="stylesheet" href="css/shared.css">
<div class="memberList">
diff --git a/runtime/observatory/lib/src/elements/object_view.html b/runtime/observatory/lib/src/elements/object_view.html
index eff9e49..99917f2 100644
--- a/runtime/observatory/lib/src/elements/object_view.html
+++ b/runtime/observatory/lib/src/elements/object_view.html
@@ -5,12 +5,10 @@
<link rel="import" href="function_ref.html">
<link rel="import" href="inbound_reference.html">
<link rel="import" href="instance_ref.html">
-<link rel="import" href="observatory_element.html">
<link rel="import" href="object_common.html">
-<link rel="import" href="nav_bar.html">
<link rel="import" href="eval_link.html">
-<polymer-element name="object-view" extends="observatory-element">
+<polymer-element name="object-view">
<template>
<link rel="stylesheet" href="css/shared.css">
<nav-bar>
@@ -19,6 +17,7 @@
<isolate-nav-menu isolate="{{ object.isolate }}"></isolate-nav-menu>
<nav-menu link="." anchor="object" last="{{ true }}"></nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content">
diff --git a/runtime/observatory/lib/src/elements/objectpool_view.html b/runtime/observatory/lib/src/elements/objectpool_view.html
index 4177eea..1aff2dd 100644
--- a/runtime/observatory/lib/src/elements/objectpool_view.html
+++ b/runtime/observatory/lib/src/elements/objectpool_view.html
@@ -5,12 +5,10 @@
<link rel="import" href="function_ref.html">
<link rel="import" href="inbound_reference.html">
<link rel="import" href="instance_ref.html">
-<link rel="import" href="observatory_element.html">
<link rel="import" href="object_common.html">
-<link rel="import" href="nav_bar.html">
<link rel="import" href="eval_link.html">
-<polymer-element name="objectpool-view" extends="observatory-element">
+<polymer-element name="objectpool-view">
<template>
<link rel="stylesheet" href="css/shared.css">
<nav-bar>
@@ -19,6 +17,7 @@
<isolate-nav-menu isolate="{{ pool.isolate }}"></isolate-nav-menu>
<nav-menu link="." anchor="object" last="{{ true }}"></nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content">
@@ -48,7 +47,7 @@
</div>
</div>
-
+
<hr>
<view-footer></view-footer>
</template>
diff --git a/runtime/observatory/lib/src/elements/objectstore_view.html b/runtime/observatory/lib/src/elements/objectstore_view.html
index a8d4d02..01f467b 100644
--- a/runtime/observatory/lib/src/elements/objectstore_view.html
+++ b/runtime/observatory/lib/src/elements/objectstore_view.html
@@ -1,17 +1,13 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
<link rel="import" href="class_ref.html">
-<link rel="import" href="curly_block.html">
<link rel="import" href="eval_box.html">
<link rel="import" href="field_ref.html">
<link rel="import" href="function_ref.html">
<link rel="import" href="instance_ref.html">
-<link rel="import" href="observatory_element.html">
<link rel="import" href="library_ref.html">
-<link rel="import" href="nav_bar.html">
<link rel="import" href="script_ref.html">
-<link rel="import" href="view_footer.html">
-<polymer-element name="objectstore-view" extends="observatory-element">
+<polymer-element name="objectstore-view">
<template>
<link rel="stylesheet" href="css/shared.css">
@@ -20,6 +16,7 @@
<vm-nav-menu vm="{{ objectStore.isolate.vm }}"></vm-nav-menu>
<isolate-nav-menu isolate="{{ objectStore.isolate }}" last="{{ true }}"></isolate-nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content-centered-big">
diff --git a/runtime/observatory/lib/src/elements/observatory_application.html b/runtime/observatory/lib/src/elements/observatory_application.html
index 73a2615..d91819f 100644
--- a/runtime/observatory/lib/src/elements/observatory_application.html
+++ b/runtime/observatory/lib/src/elements/observatory_application.html
@@ -1,7 +1,7 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="observatory_element.html">
+
<link rel="import" href="service_view.html">
-<polymer-element name="observatory-application" extends="observatory-element">
+<polymer-element name="observatory-application">
<!-- This element explicitly manages its child elements -->
</polymer-element>
diff --git a/runtime/observatory/lib/src/elements/observatory_element.dart b/runtime/observatory/lib/src/elements/observatory_element.dart
index 164f079..a661ccf 100644
--- a/runtime/observatory/lib/src/elements/observatory_element.dart
+++ b/runtime/observatory/lib/src/elements/observatory_element.dart
@@ -11,7 +11,6 @@
import 'package:polymer/polymer.dart';
/// Base class for all Observatory custom elements.
-@CustomTag('observatory-element')
class ObservatoryElement extends PolymerElement {
ObservatoryElement.created() : super.created();
diff --git a/runtime/observatory/lib/src/elements/observatory_element.html b/runtime/observatory/lib/src/elements/observatory_element.html
deleted file mode 100644
index dce89dc..0000000
--- a/runtime/observatory/lib/src/elements/observatory_element.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<link rel="import" href="../../../../packages/polymer/polymer.html">
-
-<polymer-element name="observatory-element">
-</polymer-element>
-
-<script type="application/dart" src="observatory_element.dart"></script>
\ No newline at end of file
diff --git a/runtime/observatory/lib/src/elements/persistent_handles.html b/runtime/observatory/lib/src/elements/persistent_handles.html
index 9005494..af92aa7 100644
--- a/runtime/observatory/lib/src/elements/persistent_handles.html
+++ b/runtime/observatory/lib/src/elements/persistent_handles.html
@@ -1,8 +1,6 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="nav_bar.html">
-<link rel="import" href="observatory_element.html">
-<polymer-element name="persistent-handles-page" extends="observatory-element">
+<polymer-element name="persistent-handles-page">
<template>
<link rel="stylesheet" href="css/shared.css">
<style>
@@ -56,6 +54,7 @@
<isolate-nav-menu isolate="{{ isolate }}"></isolate-nav-menu>
<nav-menu link="{{ makeLink('/persistent-handles', isolate) }}" anchor="persistent handles" last="{{ true }}"></nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content-centered-big">
<template if="{{ persistentHandles.isEmpty }}">
diff --git a/runtime/observatory/lib/src/elements/ports.html b/runtime/observatory/lib/src/elements/ports.html
index d5b3152..af2adfb 100644
--- a/runtime/observatory/lib/src/elements/ports.html
+++ b/runtime/observatory/lib/src/elements/ports.html
@@ -1,8 +1,6 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="nav_bar.html">
-<link rel="import" href="observatory_element.html">
-<polymer-element name="ports-page" extends="observatory-element">
+<polymer-element name="ports-page">
<template>
<link rel="stylesheet" href="css/shared.css">
<style>
@@ -22,6 +20,7 @@
<isolate-nav-menu isolate="{{ isolate }}"></isolate-nav-menu>
<nav-menu link="{{ makeLink('/ports', isolate) }}" anchor="ports" last="{{ true }}"></nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content">
<h1>Ports ({{ports.length}})</h1>
diff --git a/runtime/observatory/lib/src/elements/script_inset.dart b/runtime/observatory/lib/src/elements/script_inset.dart
index 5776bc4..d4f2899 100644
--- a/runtime/observatory/lib/src/elements/script_inset.dart
+++ b/runtime/observatory/lib/src/elements/script_inset.dart
@@ -8,7 +8,6 @@
import 'dart:html';
import 'dart:math';
import 'observatory_element.dart';
-import 'nav_bar.dart';
import 'service_ref.dart';
import 'package:observatory/service.dart';
import 'package:observatory/utils.dart';
@@ -984,7 +983,8 @@
return 5;
}
const padding = 5;
- const navbarHeight = NavBarElement.height;
+ // TODO (cbernaschina) check if this is needed.
+ const navbarHeight = 40;
var rect = getBoundingClientRect();
var buttonHeight = element.clientHeight;
return min(max(0, navbarHeight - rect.top) + padding,
diff --git a/runtime/observatory/lib/src/elements/script_inset.html b/runtime/observatory/lib/src/elements/script_inset.html
index dd21155..c8ea9df 100644
--- a/runtime/observatory/lib/src/elements/script_inset.html
+++ b/runtime/observatory/lib/src/elements/script_inset.html
@@ -1,5 +1,5 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="observatory_element.html">
+
<polymer-element name="icon-refresh" noscript>
<template>
@@ -27,7 +27,7 @@
</template>
</polymer-element>
-<polymer-element name="script-inset" extends="observatory-element">
+<polymer-element name="script-inset">
<template>
<style>
a {
diff --git a/runtime/observatory/lib/src/elements/script_ref.html b/runtime/observatory/lib/src/elements/script_ref.html
index ccbb177..7a9f0f1 100644
--- a/runtime/observatory/lib/src/elements/script_ref.html
+++ b/runtime/observatory/lib/src/elements/script_ref.html
@@ -1,8 +1,8 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="observatory_element.html">
+
<link rel="import" href="service_ref.html">
-<polymer-element name="script-ref" extends="service-ref">
+<polymer-element name="script-ref">
<template>
<link rel="stylesheet" href="css/shared.css">
<a on-click="{{ goto }}" title="{{ hoverText }}" _href="{{ url }}">{{ name }}</a>
diff --git a/runtime/observatory/lib/src/elements/script_view.html b/runtime/observatory/lib/src/elements/script_view.html
index e5aec18..b732128 100644
--- a/runtime/observatory/lib/src/elements/script_view.html
+++ b/runtime/observatory/lib/src/elements/script_view.html
@@ -1,10 +1,7 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="nav_bar.html">
-<link rel="import" href="observatory_element.html">
<link rel="import" href="script_inset.html">
-<link rel="import" href="view_footer.html">
-<polymer-element name="script-view" extends="observatory-element">
+<polymer-element name="script-view">
<template>
<link rel="stylesheet" href="css/shared.css">
<nav-bar>
@@ -14,6 +11,7 @@
<library-nav-menu library="{{ script.library }}"></library-nav-menu>
<nav-menu link="{{ makeLink('/inspect', script) }}" anchor="{{ script.name }}" last="{{ true }}"></nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content-centered-big">
diff --git a/runtime/observatory/lib/src/elements/service_ref.dart b/runtime/observatory/lib/src/elements/service_ref.dart
index e9aad6d..d368713 100644
--- a/runtime/observatory/lib/src/elements/service_ref.dart
+++ b/runtime/observatory/lib/src/elements/service_ref.dart
@@ -14,7 +14,6 @@
import 'library_ref.dart';
import 'observatory_element.dart';
-@CustomTag('service-ref')
class ServiceRefElement extends ObservatoryElement {
@published ServiceObject ref;
@published bool internal = false;
diff --git a/runtime/observatory/lib/src/elements/service_ref.html b/runtime/observatory/lib/src/elements/service_ref.html
index 17ce4c5..c6e8b8b 100644
--- a/runtime/observatory/lib/src/elements/service_ref.html
+++ b/runtime/observatory/lib/src/elements/service_ref.html
@@ -1,13 +1,9 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="observatory_element.html">
-<polymer-element name="service-ref" extends="observatory-element">
+<polymer-element name="any-service-ref">
</polymer-element>
-<polymer-element name="any-service-ref" extends="observatory-element">
-</polymer-element>
-
-<polymer-element name="object-ref" extends="service-ref">
+<polymer-element name="object-ref">
<template><link rel="stylesheet" href="css/shared.css">
<template if="{{ ref.isObjectPool }}">
diff --git a/runtime/observatory/lib/src/elements/service_view.html b/runtime/observatory/lib/src/elements/service_view.html
index 723248f..3ddbbe4 100644
--- a/runtime/observatory/lib/src/elements/service_view.html
+++ b/runtime/observatory/lib/src/elements/service_view.html
@@ -11,16 +11,15 @@
<link rel="import" href="instance_view.html">
<link rel="import" href="library_view.html">
<link rel="import" href="heap_snapshot.html">
-<link rel="import" href="observatory_element.html">
+
<link rel="import" href="script_view.html">
<link rel="import" href="vm_view.html">
-<link rel="import" href="view_footer.html">
-<polymer-element name="service-view" extends="observatory-element">
+<polymer-element name="service-view">
<!-- This element explicitly manages the child elements to avoid setting
an observable property on the old element to an invalid type. -->
</polymer-element>
-<polymer-element name="trace-view" extends="observatory-element">
+<polymer-element name="trace-view">
<template>
<link rel="stylesheet" href="css/shared.css">
@@ -48,7 +47,7 @@
</template>
</polymer-element>
-<polymer-element name="map-viewer" extends="observatory-element">
+<polymer-element name="map-viewer">
<template>
<link rel="stylesheet" href="css/shared.css">
@@ -80,7 +79,7 @@
</template>
</polymer-element>
-<polymer-element name="list-viewer" extends="observatory-element">
+<polymer-element name="list-viewer">
<template>
<link rel="stylesheet" href="css/shared.css">
diff --git a/runtime/observatory/lib/src/elements/shims/binding.dart b/runtime/observatory/lib/src/elements/shims/binding.dart
new file mode 100644
index 0000000..5e37609
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/shims/binding.dart
@@ -0,0 +1,61 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:core';
+import 'dart:html';
+import 'dart:js';
+import 'dart:mirrors';
+import 'package:js/js.dart';
+import 'package:js_util/js_util.dart';
+import 'package:polymer/polymer.dart';
+
+class Binding {
+ final String attribute;
+ final String property;
+ const Binding (attribute, [String property])
+ : attribute = attribute,
+ property = property == null ? attribute : property;
+}
+
+///This is a temporary bridge between Polymer Bindings and the wrapper entities.
+class Binder<T extends HtmlElement> {
+ final List<Binding> attributes;
+ final callback;
+
+ Binder(List<Binding> attributes)
+ : attributes = attributes,
+ callback = _createCallback(T, attributes);
+
+ registerCallback(T element) {
+ assert(element != null);
+ setValue(element, 'bind', callback);
+ }
+
+ static _createCallback(Type T, List<Binding> attributes){
+ final target = reflectClass(T);
+ final setters = <String, Symbol>{};
+ for (Binding binding in attributes){
+ var member = target.instanceMembers[new Symbol(binding.property + '=')];
+ if (!member.isSetter)
+ throw new ArgumentError(
+ '${binding.property} is not a Setter for class $T');
+ setters[binding.attribute] = new Symbol(binding.property);
+ }
+ return allowInteropCaptureThis((_this, name, value, [other]) {
+ final setter = setters[name];
+ if (setter == null) return;
+ Bindable bindable;
+ if (identical(1, 1.0)) { // dart2js
+ bindable = getValue(getValue(value, '__dartBindable'), 'o') as Bindable;
+ } else { // vm
+ bindable = getValue(value, '__dartBindable');
+ }
+ var obj = reflect(_this);
+ obj.setField(setter, bindable.value);
+ bindable.open((value) {
+ obj.setField(setter, value);
+ });
+ });
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/sliding_checkbox.dart b/runtime/observatory/lib/src/elements/sliding_checkbox.dart
deleted file mode 100644
index 760fd11..0000000
--- a/runtime/observatory/lib/src/elements/sliding_checkbox.dart
+++ /dev/null
@@ -1,21 +0,0 @@
-// 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 sliding_checkbox_element;
-
-import 'dart:html';
-import 'package:polymer/polymer.dart';
-
-@CustomTag('sliding-checkbox')
-class SlidingCheckboxElement extends PolymerElement {
- SlidingCheckboxElement.created() : super.created();
- @published bool checked;
- @published String checkedText;
- @published String uncheckedText;
-
- void change(Event e, var details, Node target) {
- CheckboxInputElement input = shadowRoot.querySelector('#slide-switch');
- checked = input.checked;
- }
-}
diff --git a/runtime/observatory/lib/src/elements/sliding_checkbox.html b/runtime/observatory/lib/src/elements/sliding_checkbox.html
deleted file mode 100644
index cdb4f78..0000000
--- a/runtime/observatory/lib/src/elements/sliding_checkbox.html
+++ /dev/null
@@ -1,90 +0,0 @@
-<link rel="import" href="../../../../packages/polymer/polymer.html">
-
-<polymer-element name="sliding-checkbox">
- <template>
- <style>
- .switch {
- position: relative;
- width: 121px;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- }
- .hide {
- display: none;
- }
- .label {
- display: block;
- overflow: hidden;
- cursor: pointer;
- border: 2px solid #999999;
- border-radius: 15px;
- }
- .content {
- width: 200%;
- margin-left: -100%;
- -moz-transition: margin 0.3s ease-in 0s;
- -webkit-transition: margin 0.3s ease-in 0s;
- -o-transition: margin 0.3s ease-in 0s;
- transition: margin 0.3s ease-in 0s;
- }
- .content:before, .content:after {
- float: left;
- width: 50%;
- height: 30px;
- padding: 0;
- line-height: 30px;
- color: white;
- font: 400 14px 'Montserrat', sans-serif;
- -moz-box-sizing: border-box;
- -webkit-box-sizing: border-box;
- box-sizing: border-box;
- }
- .content:before {
- content: {{ checkedText }};
- padding-left: 10px;
- background-color: #0489C3;
- }
- .content:after {
- content: {{ uncheckedText }};
- padding-right: 10px;
- background-color: #EEEEEE;
- color: #999999;
- text-align: right;
- }
- .dot {
- width: 14px;
- margin: 8px;
- background: #FFFFFF;
- border: 2px solid #999999;
- border-radius: 15px;
- position: absolute;
- top: 0;
- bottom: 0;
- right: 87px;
- -moz-transition: all 0.3s ease-in 0s;
- -webkit-transition: all 0.3s ease-in 0s;
- -o-transition: all 0.3s ease-in 0s;
- transition: all 0.3s ease-in 0s;
- }
- :checked + .label .content {
- margin-left: 0;
- }
- :checked + .label .dot {
- right: 0px;
- }
- </style>
- <div class="switch">
- <input type="checkbox"
- class="hide"
- id="slide-switch"
- on-change="{{ change }}">
- <label class="label" for="slide-switch">
- <div class="content"></div>
- <div class="dot"></div>
- </label>
- </div>
- </template>
-</polymer-element>
-
-<script type="application/dart" src="sliding_checkbox.dart"></script>
\ No newline at end of file
diff --git a/runtime/observatory/lib/src/elements/timeline_page.html b/runtime/observatory/lib/src/elements/timeline_page.html
index 433c242..df9e0b4 100644
--- a/runtime/observatory/lib/src/elements/timeline_page.html
+++ b/runtime/observatory/lib/src/elements/timeline_page.html
@@ -1,8 +1,6 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="nav_bar.html">
-<link rel="import" href="observatory_element.html">
-<polymer-element name="timeline-page" extends="observatory-element">
+<polymer-element name="timeline-page">
<template>
<link rel="stylesheet" href="css/shared.css">
<nav-bar>
@@ -13,6 +11,7 @@
<nav-refresh callback="{{ clear }}" label="Clear"></nav-refresh>
<nav-refresh callback="{{ saveTimeline }}" label="Save"></nav-refresh>
<nav-refresh callback="{{ loadTimeline }}" label="Load"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div id="control" class="content-centered-big">
<h2>Timeline settings</h2>
diff --git a/runtime/observatory/lib/src/elements/view_footer.dart b/runtime/observatory/lib/src/elements/view_footer.dart
index a182511..7493a7a 100644
--- a/runtime/observatory/lib/src/elements/view_footer.dart
+++ b/runtime/observatory/lib/src/elements/view_footer.dart
@@ -4,10 +4,50 @@
library view_footer_element;
-import 'package:polymer/polymer.dart';
-import 'observatory_element.dart';
+import 'dart:html';
+import 'dart:async';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
-@CustomTag('view-footer')
-class ViewFooterElement extends ObservatoryElement {
- ViewFooterElement.created() : super.created();
+class ViewFooterElement extends HtmlElement implements Renderable {
+ static const tag = const Tag<ViewFooterElement>('view-footer');
+
+ RenderingScheduler _r;
+
+ Stream<RenderedEvent<ViewFooterElement>> get onRendered => _r.onRendered;
+
+ factory ViewFooterElement({RenderingQueue queue}) {
+ ViewFooterElement e = document.createElement(tag.name);
+ e._r = new RenderingScheduler(e, queue: queue);
+ return e;
+ }
+
+ ViewFooterElement.created() : super.created() {
+ // TODO(cbernaschina) remove this when no more needed.
+ _r = new RenderingScheduler(this);
+ }
+
+ @override
+ void attached() {
+ super.attached();
+ _r.enable();
+ }
+
+ @override
+ void detached() {
+ super.detached();
+ _r.disable(notify: true);
+ children = [];
+ }
+
+ void render() {
+ children = [
+ new AnchorElement()
+ ..href = 'https://www.dartlang.org/tools/observatory'
+ ..text = 'View documentation',
+ new AnchorElement()
+ ..href = 'https://github.com/dart-lang/sdk/issues/new?title=Observatory:&body=Observatory%20Feedback'
+ ..text = 'File a bug report'
+ ];
+ }
}
diff --git a/runtime/observatory/lib/src/elements/view_footer.html b/runtime/observatory/lib/src/elements/view_footer.html
deleted file mode 100644
index 59862b5..0000000
--- a/runtime/observatory/lib/src/elements/view_footer.html
+++ /dev/null
@@ -1,23 +0,0 @@
-<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="observatory_element.html">
-
-<polymer-element name="view-footer" extends="observatory-element">
- <template><link rel="stylesheet" href="css/shared.css">
- <br><br><br><br>
- <br><br><br><br>
- <div align="right" style="padding: 1em">
- <p>
- <a href="https://www.dartlang.org/tools/observatory/" style="font-size:90%">
- View documentation
- </a>
- </p>
- <p>
- <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>
- </div>
- </template>
-</polymer-element>
-
-<script type="application/dart" src="view_footer.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/vm_connect.dart b/runtime/observatory/lib/src/elements/vm_connect.dart
index 5d42edc..37cc2a2 100644
--- a/runtime/observatory/lib/src/elements/vm_connect.dart
+++ b/runtime/observatory/lib/src/elements/vm_connect.dart
@@ -8,51 +8,10 @@
import 'dart:html';
import 'observatory_element.dart';
-import 'package:observatory/app.dart';
import 'package:observatory/elements.dart';
import 'package:observatory/service_html.dart';
import 'package:polymer/polymer.dart';
-void _connectToVM(ObservatoryApplication app, WebSocketVMTarget target) {
- app.vm = new WebSocketVM(target);
-}
-
-@CustomTag('vm-connect-target')
-class VMConnectTargetElement extends ObservatoryElement {
- @published WebSocketVMTarget target;
-
- VMConnectTargetElement.created() : super.created();
-
- bool get isCurrentTarget {
- if (app.vm == null) {
- return false;
- }
- return (app.vm as WebSocketVM).target == target;
- }
-
- void connectToVm(MouseEvent event, var detail, Element node) {
- if (event.button > 0 || event.metaKey || event.ctrlKey ||
- event.shiftKey || event.altKey) {
- // Not a left-click or a left-click with a modifier key:
- // Let browser handle.
- return;
- }
- event.preventDefault();
- WebSocketVM currentVM = app.vm;
- if ((currentVM == null) ||
- currentVM.isDisconnected ||
- (currentVM.target != target)) {
- _connectToVM(app, target);
- }
- var href = node.attributes['href'];
- app.locationManager.go(href);
- }
-
- void deleteVm(MouseEvent event, var detail, Element node) {
- app.targets.remove(target);
- }
-}
-
@CustomTag('vm-connect')
class VMConnectElement extends ObservatoryElement {
@published String standaloneVmAddress = '';
@@ -61,7 +20,7 @@
}
void _connect(WebSocketVMTarget target) {
- _connectToVM(app, target);
+ app.vm = new WebSocketVM(target);
app.locationManager.goForwardingParameters('/vm');
}
diff --git a/runtime/observatory/lib/src/elements/vm_connect.html b/runtime/observatory/lib/src/elements/vm_connect.html
index 0bae096..53be73d 100644
--- a/runtime/observatory/lib/src/elements/vm_connect.html
+++ b/runtime/observatory/lib/src/elements/vm_connect.html
@@ -1,34 +1,6 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="nav_bar.html">
-<link rel="import" href="observatory_element.html">
-<link rel="import" href="view_footer.html">
-<polymer-element name="vm-connect-target" extends="observatory-element">
- <template>
- <style>
- .delete-button {
- padding: 4px;
- background: transparent;
- border: none !important;
- }
- .delete-button:hover {
- background: #ff0000;
- }
- </style>
- <link rel="stylesheet" href="css/shared.css">
- <span>
- <template if="{{ isCurrentTarget }}">
- <a on-click="{{ connectToVm }}" _href="{{ gotoLinkForwardingParameters('/vm') }}">{{ target.name }} (Connected)</a>
- </template>
- <template if="{{ !isCurrentTarget }}">
- <a on-click="{{ connectToVm }}" _href="{{ gotoLinkForwardingParameters('/vm') }}">{{ target.name }}</a>
- </template>
- <button class="delete-button" on-click="{{ deleteVm }}">✖ Remove</button>
- </span>
- </template>
-</polymer-element>
-
-<polymer-element name="vm-connect" extends="observatory-element">
+<polymer-element name="vm-connect">
<template>
<link rel="stylesheet" href="css/shared.css">
<style>
@@ -40,6 +12,7 @@
<nav-bar>
<top-nav-menu last="{{ true }}"></top-nav-menu>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content-centered">
diff --git a/runtime/observatory/lib/src/elements/vm_connect_target.dart b/runtime/observatory/lib/src/elements/vm_connect_target.dart
new file mode 100644
index 0000000..befe6dd
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/vm_connect_target.dart
@@ -0,0 +1,101 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+import 'dart:html';
+import 'package:observatory/models.dart' as M show Target;
+import 'package:observatory/src/elements/helpers/rendering_scheduler.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/helpers/uris.dart';
+
+class TargetEvent {
+ final M.Target target;
+
+ TargetEvent(this.target);
+}
+
+class VMConnectTargetElement extends HtmlElement implements Renderable{
+
+ static const tag =
+ const Tag<VMConnectTargetElement>('vm-connect-target-wrapped');
+
+ RenderingScheduler<VMConnectTargetElement> _r;
+
+ Stream<RenderedEvent<VMConnectTargetElement>> get onRendered => _r.onRendered;
+
+ final StreamController<TargetEvent> _onConnect =
+ new StreamController<TargetEvent>.broadcast();
+ Stream<TargetEvent> get onConnect => _onConnect.stream;
+ final StreamController<TargetEvent> _onDelete =
+ new StreamController<TargetEvent>.broadcast();
+ Stream<TargetEvent> get onDelete => _onDelete.stream;
+
+ M.Target _target;
+ bool _current;
+
+ M.Target get target => _target;
+ bool get current => _current;
+
+ factory VMConnectTargetElement(M.Target target, {bool current: false,
+ RenderingQueue queue}) {
+ assert(target != null);
+ assert(current != null);
+ VMConnectTargetElement e = document.createElement(tag.name);
+ e._r = new RenderingScheduler(e, queue: queue);
+ e._target = target;
+ e._current = current;
+ return e;
+ }
+
+ VMConnectTargetElement.created() : super.created();
+
+ @override
+ void attached() {
+ super.attached();
+ _r.enable();
+ }
+
+ @override
+ void detached() {
+ super.detached();
+ children = [];
+ _r.disable(notify: true);
+ }
+
+ void connect() {
+ _connect(new TargetEvent(target));
+ }
+
+ void delete() {
+ _delete(new TargetEvent(target));
+ }
+
+ void render() {
+ children = [
+ new AnchorElement(href: Uris.vm())
+ ..text = current ? '${target.name} (Connected)' : '${target.name}'
+ ..onClick.where(_filter).map(_toEvent).listen(_connect),
+ new ButtonElement()
+ ..text = '✖ Remove' ..classes = ['delete-button']
+ ..onClick.map(_toEvent).listen(_delete)
+ ];
+ }
+
+ void _connect(TargetEvent e) {
+ _onConnect.add(e);
+ }
+
+ void _delete(TargetEvent e) {
+ _onDelete.add(e);
+ }
+
+ TargetEvent _toEvent(_) {
+ return new TargetEvent(target);
+ }
+
+ static bool _filter(MouseEvent event) {
+ return !(event.button > 0 || event.metaKey || event.ctrlKey ||
+ event.shiftKey || event.altKey);
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/vm_connect_target_wrapper.dart b/runtime/observatory/lib/src/elements/vm_connect_target_wrapper.dart
new file mode 100644
index 0000000..1034061
--- /dev/null
+++ b/runtime/observatory/lib/src/elements/vm_connect_target_wrapper.dart
@@ -0,0 +1,77 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:html';
+import 'package:observatory/app.dart';
+import 'package:observatory/service_html.dart';
+import 'package:observatory/src/elements/helpers/tag.dart';
+import 'package:observatory/src/elements/shims/binding.dart';
+import 'package:observatory/src/elements/vm_connect_target.dart';
+
+class VMConnectTargetElementWrapper extends HtmlElement {
+ static final binder = new Binder<VMConnectTargetElementWrapper>(
+ const [const Binding('target')]);
+
+ static const tag =
+ const Tag<VMConnectTargetElementWrapper>('vm-connect-target');
+
+ WebSocketVMTarget _target;
+ WebSocketVMTarget get target => _target;
+ void set target(WebSocketVMTarget target) { _target = target; render(); }
+
+ VMConnectTargetElementWrapper.created() : super.created() {
+ binder.registerCallback(this);
+ createShadowRoot();
+ render();
+ }
+
+ @override
+ void attached() {
+ super.attached();
+ render();
+ }
+
+ void render() {
+ if (target == null) return;
+
+ shadowRoot.children = [
+ new StyleElement()
+ ..text = '''
+ vm-connect-target-wrapped > button.delete-button {
+ margin-left: 0.28em;
+ padding: 4px;
+ background: transparent;
+ border: none !important;
+ }
+
+ vm-connect-target-wrapped > button.delete-button:hover {
+ background: #ff0000;
+ }''',
+ new VMConnectTargetElement(target, current: current,
+ queue: application.queue)
+ ..onConnect.listen(connectToVm)
+ ..onDelete.listen(deleteVm)
+ ];
+ }
+
+ static ObservatoryApplication get application => ObservatoryApplication.app;
+
+ bool get current {
+ if (application.vm == null) { return false; }
+ return (application.vm as WebSocketVM).target == target;
+ }
+
+ static void connectToVm(TargetEvent event) {
+ WebSocketVM currentVM = application.vm;
+ if ((currentVM == null) ||
+ currentVM.isDisconnected ||
+ (currentVM.target != event.target)) {
+ application.vm = new WebSocketVM(event.target);
+ }
+ }
+
+ static void deleteVm(TargetEvent event) {
+ application.targets.remove(event.target);
+ }
+}
diff --git a/runtime/observatory/lib/src/elements/vm_ref.dart b/runtime/observatory/lib/src/elements/vm_ref.dart
deleted file mode 100644
index 56fab8a..0000000
--- a/runtime/observatory/lib/src/elements/vm_ref.dart
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-library vm_ref_element;
-
-import 'package:polymer/polymer.dart';
-import 'service_ref.dart';
-
-@CustomTag('vm-ref')
-class VMRefElement extends ServiceRefElement {
- VMRefElement.created() : super.created();
-}
diff --git a/runtime/observatory/lib/src/elements/vm_ref.html b/runtime/observatory/lib/src/elements/vm_ref.html
deleted file mode 100644
index e7cb8e4..0000000
--- a/runtime/observatory/lib/src/elements/vm_ref.html
+++ /dev/null
@@ -1,10 +0,0 @@
-<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="service_ref.html">
-
-<polymer-element name="vm-ref" extends="service-ref">
- <template><link rel="stylesheet" href="css/shared.css">
- <a on-click="{{ goto }}" _href="{{ url }}">{{ ref.name }}</a>
- </template>
-</polymer-element>
-
-<script type="application/dart" src="vm_ref.dart"></script>
diff --git a/runtime/observatory/lib/src/elements/vm_view.html b/runtime/observatory/lib/src/elements/vm_view.html
index 2934009..a078f04 100644
--- a/runtime/observatory/lib/src/elements/vm_view.html
+++ b/runtime/observatory/lib/src/elements/vm_view.html
@@ -1,15 +1,11 @@
<link rel="import" href="../../../../packages/polymer/polymer.html">
-<link rel="import" href="curly_block.html">
<link rel="import" href="eval_box.html">
<link rel="import" href="function_ref.html">
<link rel="import" href="isolate_summary.html">
<link rel="import" href="library_ref.html">
-<link rel="import" href="nav_bar.html">
-<link rel="import" href="observatory_element.html">
<link rel="import" href="script_ref.html">
-<link rel="import" href="view_footer.html">
-<polymer-element name="vm-view" extends="observatory-element">
+<polymer-element name="vm-view">
<template>
<link rel="stylesheet" href="css/shared.css">
@@ -17,6 +13,7 @@
<top-nav-menu last="{{ false }}"></top-nav-menu>
<vm-nav-menu vm="{{ vm }}" last="{{ true }}"></vm-nav-menu>
<nav-refresh callback="{{ refresh }}"></nav-refresh>
+ <nav-notify notifications="{{ app.notifications }}"></nav-notify>
</nav-bar>
<div class="content-centered">
diff --git a/runtime/observatory/lib/src/mocks/exceptions/connection_exception.dart b/runtime/observatory/lib/src/mocks/exceptions/connection_exception.dart
new file mode 100644
index 0000000..127cb20
--- /dev/null
+++ b/runtime/observatory/lib/src/mocks/exceptions/connection_exception.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of mocks;
+
+class ConnectionExceptionMock implements M.ConnectionException {
+ final String message;
+ const ConnectionExceptionMock({this.message});
+}
diff --git a/runtime/observatory/lib/src/mocks/objects/class.dart b/runtime/observatory/lib/src/mocks/objects/class.dart
new file mode 100644
index 0000000..33eb764
--- /dev/null
+++ b/runtime/observatory/lib/src/mocks/objects/class.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of mocks;
+
+class ClassRefMock implements M.ClassRef {
+ final String id;
+ final String name;
+ const ClassRefMock({this.id, this.name});
+}
+
+class ClassMock implements M.ClassRef {
+ final String id;
+ final String name;
+ final bool isAbstract;
+ final bool isConst;
+ final M.ClassRef superclass;
+ final Iterable<M.ClassRef> subclasses;
+ const ClassMock({this.id, this.name, this.isAbstract, this.isConst,
+ this.superclass, this.subclasses: const []});
+}
diff --git a/runtime/observatory/lib/src/mocks/objects/error.dart b/runtime/observatory/lib/src/mocks/objects/error.dart
new file mode 100644
index 0000000..8b47830
--- /dev/null
+++ b/runtime/observatory/lib/src/mocks/objects/error.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of mocks;
+
+class ErrorRefMock implements M.ErrorRef {
+ final String id;
+ final M.ErrorKind kind;
+ final String message;
+ const ErrorRefMock({this.id, this.kind, this.message});
+}
+
+class ErrorMock implements M.Error {
+ final String id;
+ final M.ErrorKind kind;
+ final String message;
+ final int size;
+ const ErrorMock({this.id, this.kind, this.message, this.size});
+}
diff --git a/runtime/observatory/lib/src/mocks/objects/event.dart b/runtime/observatory/lib/src/mocks/objects/event.dart
new file mode 100644
index 0000000..6a646f3
--- /dev/null
+++ b/runtime/observatory/lib/src/mocks/objects/event.dart
@@ -0,0 +1,142 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of mocks;
+
+class VMUpdateEventMock implements M.VMUpdateEvent {
+ final M.VMRef vm;
+ final DateTime timestamp;
+ const VMUpdateEventMock({this.timestamp, this.vm});
+}
+class IsolateStartEventMock implements M.IsolateStartEvent {
+ final DateTime timestamp;
+ final M.IsolateRef isolate;
+ const IsolateStartEventMock({this.timestamp, this.isolate});
+}
+class IsolateRunnableEventMock implements M.IsolateRunnableEvent {
+ final DateTime timestamp;
+ final M.IsolateRef isolate;
+ const IsolateRunnableEventMock({this.timestamp, this.isolate});
+}
+class IsolateExitEventMock implements M.IsolateExitEvent {
+ final DateTime timestamp;
+ final M.IsolateRef isolate;
+ const IsolateExitEventMock({this.timestamp, this.isolate});
+}
+class IsolateUpdateEventMock implements M.IsolateUpdateEvent {
+ final DateTime timestamp;
+ final M.IsolateRef isolate;
+ const IsolateUpdateEventMock({this.timestamp, this.isolate});
+}
+class IsolateRealodEventMock implements M.IsolateReloadEvent {
+ final DateTime timestamp;
+ final M.IsolateRef isolate;
+ final M.Error error;
+ const IsolateRealodEventMock({this.timestamp, this.isolate, this.error});
+}
+class ServiceExtensionAddedEventMock implements M.ServiceExtensionAddedEvent {
+ final DateTime timestamp;
+ final M.IsolateRef isolate;
+ final String extensionRPC;
+ const ServiceExtensionAddedEventMock({this.extensionRPC, this.isolate,
+ this.timestamp});
+}
+class PauseStartEventMock implements M.PauseStartEvent {
+ final DateTime timestamp;
+ final M.IsolateRef isolate;
+ const PauseStartEventMock({this.isolate, this.timestamp});
+}
+class PauseExitEventMock implements M.PauseExitEvent {
+ final DateTime timestamp;
+ final M.IsolateRef isolate;
+ const PauseExitEventMock({this.isolate, this.timestamp});
+}
+class PauseBreakpointEventMock implements M.PauseBreakpointEvent {
+ final DateTime timestamp;
+ final M.IsolateRef isolate;
+ final M.Breakpoint breakpoint;
+ final List<M.Breakpoint> pauseBreakpoints;
+ final M.Frame topFrame;
+ final bool atAsyncSuspension;
+ const PauseBreakpointEventMock({this.timestamp, this.isolate, this.breakpoint,
+ this.pauseBreakpoints, this.topFrame, this.atAsyncSuspension});
+}
+class PauseInterruptedEventMock implements M.PauseInterruptedEvent {
+ final DateTime timestamp;
+ final M.IsolateRef isolate;
+ final M.Frame topFrame;
+ final bool atAsyncSuspension;
+ const PauseInterruptedEventMock({this.timestamp, this.isolate, this.topFrame,
+ this.atAsyncSuspension});
+}
+class PauseExceptionEventMock implements M.PauseExceptionEvent {
+ final DateTime timestamp;
+ final M.IsolateRef isolate;
+ final M.Frame topFrame;
+ final M.InstanceRef exception;
+ const PauseExceptionEventMock({this.timestamp, this.isolate, this.topFrame,
+ this.exception});
+}
+class ResumeEventMock implements M.ResumeEvent {
+ final DateTime timestamp;
+ final M.IsolateRef isolate;
+ const ResumeEventMock({this.timestamp, this.isolate});
+}
+class BreakpointAddedEventMock implements M.BreakpointAddedEvent {
+ final DateTime timestamp;
+ final M.IsolateRef isolate;
+ final M.Breakpoint breakpoint;
+ const BreakpointAddedEventMock({this.timestamp, this.isolate,
+ this.breakpoint});
+}
+class BreakpointResolvedEventMock implements M.BreakpointResolvedEvent {
+ final DateTime timestamp;
+ final M.IsolateRef isolate;
+ final M.Breakpoint breakpoint;
+ const BreakpointResolvedEventMock({this.timestamp, this.isolate,
+ this.breakpoint});
+}
+class BreakpointRemovedEventMock implements M.BreakpointRemovedEvent {
+ final DateTime timestamp;
+ final M.IsolateRef isolate;
+ final M.Breakpoint breakpoint;
+ const BreakpointRemovedEventMock({this.timestamp, this.isolate,
+ this.breakpoint});
+}
+class InspectEventMock implements M.InspectEvent {
+ final DateTime timestamp;
+ final M.IsolateRef isolate;
+ final M.InstanceRef inspectee;
+ const InspectEventMock({this.timestamp, this.isolate, this.inspectee});
+}
+class NoneEventMock implements M.NoneEvent {
+ final DateTime timestamp;
+ final M.IsolateRef isolate;
+ const NoneEventMock({this.timestamp, this.isolate});
+}
+class GCEventMock implements M.GCEvent {
+ final DateTime timestamp;
+ final M.IsolateRef isolate;
+ const GCEventMock({this.timestamp, this.isolate});
+}
+class ExtensionEventMock implements M.ExtensionEvent {
+ final DateTime timestamp;
+ final M.IsolateRef isolate;
+ final String extensionKind;
+ final M.ExtensionData extensionData;
+ const ExtensionEventMock({this.timestamp, this.isolate, this.extensionKind,
+ this.extensionData});
+}
+class TimelineEventsEventMock implements M.TimelineEventsEvent {
+ final DateTime timestamp;
+ final M.IsolateRef isolate;
+ final List<M.TimelineEvent> timelineEvents;
+ const TimelineEventsEventMock({this.timestamp, this.isolate,
+ this.timelineEvents});
+}
+class ConnectionClockedEventMock implements M.ConnectionClosedEvent {
+ final DateTime timestamp;
+ final String reason;
+ const ConnectionClockedEventMock({this.timestamp, this.reason});
+}
diff --git a/runtime/observatory/lib/src/mocks/objects/isolate.dart b/runtime/observatory/lib/src/mocks/objects/isolate.dart
new file mode 100644
index 0000000..9f5ba80
--- /dev/null
+++ b/runtime/observatory/lib/src/mocks/objects/isolate.dart
@@ -0,0 +1,25 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of mocks;
+
+class IsolateRefMock implements M.IsolateRef {
+ final String id;
+ final int number;
+ final String name;
+
+ const IsolateRefMock({this.id, this.number, this.name});
+}
+
+class IsolateMock implements M.Isolate {
+ final String id;
+ final int number;
+ final String name;
+ final DateTime startTime;
+ final bool runnable;
+
+ const IsolateMock({this.id, this.number, this.name, this.startTime,
+ this.runnable});
+ // TODO(cbernaschina) add other properties.
+}
diff --git a/runtime/observatory/lib/src/mocks/objects/library.dart b/runtime/observatory/lib/src/mocks/objects/library.dart
new file mode 100644
index 0000000..2932efa
--- /dev/null
+++ b/runtime/observatory/lib/src/mocks/objects/library.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of mocks;
+
+class LibraryRefMock implements M.LibraryRef {
+ final String id;
+ final String name;
+ final String uri;
+ const LibraryRefMock({this.id, this.name, this.uri});
+}
+
+class LibraryMock implements M.Library {
+ final String id;
+ final String name;
+ final String uri;
+ final bool debuggable;
+ final Iterable<M.ScriptRef> scripts;
+ final Iterable<M.ClassRef> classes;
+ const LibraryMock({this.id, this.name, this.uri, this.debuggable,
+ this.scripts: const [], this.classes: const []});
+}
diff --git a/runtime/observatory/lib/src/mocks/objects/notification.dart b/runtime/observatory/lib/src/mocks/objects/notification.dart
new file mode 100644
index 0000000..68bfd75
--- /dev/null
+++ b/runtime/observatory/lib/src/mocks/objects/notification.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of mocks;
+
+class ExceptionNotificationMock implements M.ExceptionNotification {
+ final Exception exception;
+ final StackTrace stacktrace;
+ const ExceptionNotificationMock({this.exception, this.stacktrace});
+}
+
+class EventNotificationMock implements M.EventNotification {
+ final M.Event event;
+ const EventNotificationMock({this.event});
+}
diff --git a/runtime/observatory/lib/src/mocks/objects/script.dart b/runtime/observatory/lib/src/mocks/objects/script.dart
new file mode 100644
index 0000000..bb264dc
--- /dev/null
+++ b/runtime/observatory/lib/src/mocks/objects/script.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of mocks;
+
+class ScriptRefMock implements M.ScriptRef {
+ final String id;
+ final String uri;
+ const ScriptRefMock({this.id, this.uri});
+}
+
+typedef int TokenToInt(int token);
+
+class ScriptMock implements M.Script {
+ final String id;
+ final int size;
+ final String uri;
+ final String source;
+
+ final TokenToInt _tokenToLine;
+ final TokenToInt _tokenToCol;
+
+ int tokenToLine(int token) => _tokenToLine(token);
+ int tokenToCol(int token) => _tokenToCol(token);
+
+ const ScriptMock({this.id, this.size, this.uri, this.source,
+ TokenToInt tokenToLine, TokenToInt tokenToCol})
+ : _tokenToLine = tokenToLine,
+ _tokenToCol = tokenToCol;
+}
diff --git a/runtime/observatory/lib/src/mocks/objects/source_location.dart b/runtime/observatory/lib/src/mocks/objects/source_location.dart
new file mode 100644
index 0000000..481b44b
--- /dev/null
+++ b/runtime/observatory/lib/src/mocks/objects/source_location.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of mocks;
+
+class SourceLocationMock implements M.SourceLocation {
+ final M.ScriptRef script;
+ final int tokenPos;
+ final int endTokenPos;
+ const SourceLocationMock({this.script, this.tokenPos, this.endTokenPos});
+}
diff --git a/runtime/observatory/lib/src/mocks/objects/target.dart b/runtime/observatory/lib/src/mocks/objects/target.dart
new file mode 100644
index 0000000..c5ae189
--- /dev/null
+++ b/runtime/observatory/lib/src/mocks/objects/target.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of mocks;
+
+class TargetMock implements M.Target {
+ final String name;
+ const TargetMock({this.name});
+}
diff --git a/runtime/observatory/lib/src/mocks/objects/vm.dart b/runtime/observatory/lib/src/mocks/objects/vm.dart
new file mode 100644
index 0000000..a58272e
--- /dev/null
+++ b/runtime/observatory/lib/src/mocks/objects/vm.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of mocks;
+
+class VMRefMock implements M.VMRef {
+ final String name;
+ const VMRefMock({this.name});
+}
+
+class VMMock implements M.VM {
+ final String name;
+ final int architectureBits;
+ final String targetCPU;
+ final String hostCPU;
+ final String version;
+ final int pid;
+ final DateTime startTime;
+ final Iterable<M.IsolateRef> isolates;
+ const VMMock({this.name, this.architectureBits, this.targetCPU, this.hostCPU,
+ this.version, this.pid, this.startTime, this.isolates : const []});
+}
diff --git a/runtime/observatory/lib/src/mocks/repositories/notification.dart b/runtime/observatory/lib/src/mocks/repositories/notification.dart
new file mode 100644
index 0000000..cf7f2b9
--- /dev/null
+++ b/runtime/observatory/lib/src/mocks/repositories/notification.dart
@@ -0,0 +1,58 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of mocks;
+
+class NotificationChangeEventMock implements M.NotificationChangeEvent {
+ final NotificationRepositoryMock repository;
+ const NotificationChangeEventMock({this.repository});
+}
+
+typedef void NotificationRepositoryMockCallback(M.Notification notification);
+
+class NotificationRepositoryMock implements M.NotificationRepository {
+ final StreamController<M.NotificationChangeEvent> _onChange =
+ new StreamController<M.NotificationChangeEvent>.broadcast();
+ Stream<M.NotificationChangeEvent> get onChange => _onChange.stream;
+
+ bool get hasListeners => _onChange.hasListener;
+
+ final Iterable<M.Notification> _list;
+ final NotificationRepositoryMockCallback _add;
+ final NotificationRepositoryMockCallback _delete;
+
+ bool addInvoked = false;
+ bool listInvoked = false;
+ bool deleteInvoked = false;
+ bool deleteAllInvoked = false;
+
+
+ void add(M.Notification notification) {
+ addInvoked = true;
+ if (_add != null) _add(notification);
+ }
+
+ Iterable<M.Notification> list() {
+ listInvoked = true;
+ return _list;
+ }
+
+ void delete(M.Notification notification) {
+ deleteInvoked = true;
+ if (_add != null) _delete(notification);
+ }
+
+ void deleteAll() { deleteAllInvoked = true; }
+
+ void triggerChangeEvent() {
+ _onChange.add(new NotificationChangeEventMock(repository: this));
+ }
+
+ NotificationRepositoryMock({Iterable<M.Notification> list : const [],
+ NotificationRepositoryMockCallback add,
+ NotificationRepositoryMockCallback delete})
+ : _list = list,
+ _add = add,
+ _delete = delete;
+}
diff --git a/runtime/observatory/lib/src/models/exceptions.dart b/runtime/observatory/lib/src/models/exceptions.dart
new file mode 100644
index 0000000..871c095
--- /dev/null
+++ b/runtime/observatory/lib/src/models/exceptions.dart
@@ -0,0 +1,49 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of models;
+
+abstract class BasicException implements Exception {
+ String get message;
+}
+
+abstract class ConnectionException implements BasicException {}
+
+abstract class ResponseException implements BasicException {}
+
+abstract class RequestException implements BasicException {}
+
+abstract class ParseErrorException implements RequestException {}
+
+abstract class InvalidRequestException implements RequestException {}
+
+abstract class MethodNotFoundException implements RequestException {}
+
+abstract class InvalidParamsException implements RequestException {}
+
+abstract class InternalErrorException implements RequestException {}
+
+abstract class FeatureDisabledException implements RequestException {}
+
+abstract class CannotAddBreakpointException implements RequestException {}
+
+abstract class StreamAlreadySubscribedException implements RequestException {}
+
+abstract class StreamNotSubscribedException implements RequestException {}
+
+abstract class IsolateMustBeRunnableException implements RequestException {}
+
+abstract class IsolateMustBePausedException implements RequestException {}
+
+abstract class IsolateIsReloadingException implements RequestException {}
+
+abstract class FileSystemAlreadyExistsException implements RequestException {}
+
+abstract class FileSystemDoesNotExistException implements RequestException {}
+
+abstract class FileDoesNotExistException implements RequestException {}
+
+abstract class IsolateReloadFailedException implements RequestException {}
+
+abstract class UnknownException implements RequestException {}
diff --git a/runtime/observatory/lib/src/models/objects/breakpoint.dart b/runtime/observatory/lib/src/models/objects/breakpoint.dart
new file mode 100644
index 0000000..e5e9324
--- /dev/null
+++ b/runtime/observatory/lib/src/models/objects/breakpoint.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of models;
+
+abstract class Breakpoint extends Object {
+ /// A number identifying this breakpoint to the user.
+ int get number;
+
+ /// Has this breakpoint been assigned to a specific program location?
+ bool get resolved;
+}
diff --git a/runtime/observatory/lib/src/models/objects/class.dart b/runtime/observatory/lib/src/models/objects/class.dart
new file mode 100644
index 0000000..a2a9007
--- /dev/null
+++ b/runtime/observatory/lib/src/models/objects/class.dart
@@ -0,0 +1,57 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of models;
+
+abstract class ClassRef extends ObjectRef {
+ /// The name of this class.
+ String get name;
+}
+
+abstract class Class extends ObjectRef implements ClassRef {
+ /// The error which occurred during class finalization, if it exists.
+ /// [optional]
+ ErrorRef get error;
+
+ /// Is this an abstract class?
+ bool get isAbstract;
+
+ /// Is this a const class?
+ bool get isConst;
+
+ /// The library which contains this class.
+ LibraryRef get library;
+
+ /// The location of this class in the source code.[optional]
+ SourceLocation get location;
+
+ /// The superclass of this class, if any. [optional]
+ ClassRef get superclass;
+
+ /// The supertype for this class, if any.
+ ///
+ /// The value will be of the kind: Type. [optional]
+ InstanceRef get superType;
+
+ /// A list of interface types for this class.
+ ///
+ /// The values will be of the kind: Type.
+ Iterable<InstanceRef> get interfaces;
+
+ /// The mixin type for this class, if any.
+ ///
+ /// The value will be of the kind: Type. [optional]
+ Iterable<InstanceRef> get mixin;
+
+ /// A list of fields in this class. Does not include fields from
+ /// superclasses.
+ //List<FieldRef> get fields;
+
+ /// A list of functions in this class. Does not include functions
+ /// from superclasses.
+ //List<FunctionRef> get functions;
+
+ // A list of subclasses of this class.
+ Iterable<ClassRef> get subclasses;
+}
diff --git a/runtime/observatory/lib/src/models/objects/error.dart b/runtime/observatory/lib/src/models/objects/error.dart
new file mode 100644
index 0000000..b5d1bbd
--- /dev/null
+++ b/runtime/observatory/lib/src/models/objects/error.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of models;
+
+enum ErrorKind {
+ /// The isolate has encountered an unhandled Dart exception.
+ UnhandledException,
+ /// The isolate has encountered a Dart language error in the program.
+ LanguageError,
+ /// The isolate has encounted an internal error. These errors should be
+ /// reported as bugs.
+ InternalError,
+ /// The isolate has been terminated by an external source.
+ TerminationError
+}
+
+abstract class ErrorRef extends ObjectRef {
+ String get id;
+ ErrorKind get kind;
+ String get message;
+}
+
+abstract class Error extends Object implements ErrorRef {
+
+}
diff --git a/runtime/observatory/lib/src/models/objects/event.dart b/runtime/observatory/lib/src/models/objects/event.dart
new file mode 100644
index 0000000..aff1946
--- /dev/null
+++ b/runtime/observatory/lib/src/models/objects/event.dart
@@ -0,0 +1,75 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of models;
+
+abstract class Event {
+ DateTime get timestamp;
+ static bool isPauseEvent(Event event) {
+ return event is PauseStartEvent || event is PauseExitEvent ||
+ event is PauseBreakpointEvent || event is PauseInterruptedEvent ||
+ event is PauseExceptionEvent || event is NoneEvent;
+ }
+}
+abstract class VMEvent extends Event {
+ VMRef get vm;
+}
+abstract class VMUpdateEvent extends VMEvent {}
+abstract class IsolateEvent extends Event {
+ IsolateRef get isolate;
+}
+abstract class IsolateStartEvent extends IsolateEvent {}
+abstract class IsolateRunnableEvent extends IsolateEvent {}
+abstract class IsolateExitEvent extends IsolateEvent {}
+abstract class IsolateUpdateEvent extends IsolateEvent {}
+abstract class IsolateReloadEvent extends IsolateEvent {
+ ErrorRef get error;
+}
+abstract class ServiceExtensionAddedEvent extends IsolateEvent {
+ String get extensionRPC;
+}
+abstract class DebugEvent extends IsolateEvent {}
+abstract class PauseStartEvent extends DebugEvent {}
+abstract class PauseExitEvent extends DebugEvent {}
+abstract class PauseBreakpointEvent extends DebugEvent {
+ /// [optional]
+ Breakpoint get breakpoint;
+ Iterable<Breakpoint> get pauseBreakpoints;
+ Frame get topFrame;
+ bool get atAsyncSuspension;
+}
+abstract class PauseInterruptedEvent extends DebugEvent {
+ Frame get topFrame;
+ bool get atAsyncSuspension;
+}
+abstract class PauseExceptionEvent extends DebugEvent {
+ Frame get topFrame;
+ InstanceRef get exception;
+}
+abstract class ResumeEvent extends DebugEvent {}
+abstract class BreakpointAddedEvent extends DebugEvent {
+ Breakpoint get breakpoint;
+}
+abstract class BreakpointResolvedEvent extends DebugEvent {
+ Breakpoint get breakpoint;
+}
+abstract class BreakpointRemovedEvent extends DebugEvent {
+ Breakpoint get breakpoint;
+}
+abstract class InspectEvent extends DebugEvent {
+ InstanceRef get inspectee;
+}
+abstract class NoneEvent extends DebugEvent {}
+abstract class GCEvent extends IsolateEvent {}
+abstract class ExtensionEvent extends Event {
+ IsolateRef get isolate;
+ String get extensionKind;
+ ExtensionData get extensionData;
+}
+abstract class TimelineEventsEvent extends IsolateEvent {
+ Iterable<TimelineEvent> get timelineEvents;
+}
+abstract class ConnectionClosedEvent extends Event {
+ String get reason;
+}
diff --git a/runtime/observatory/lib/src/models/objects/extension_data.dart b/runtime/observatory/lib/src/models/objects/extension_data.dart
new file mode 100644
index 0000000..5000a9b
--- /dev/null
+++ b/runtime/observatory/lib/src/models/objects/extension_data.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of models;
+
+abstract class ExtensionData implements Map<String, dynamic> {}
diff --git a/runtime/observatory/lib/src/models/objects/frame.dart b/runtime/observatory/lib/src/models/objects/frame.dart
new file mode 100644
index 0000000..d8e87cd
--- /dev/null
+++ b/runtime/observatory/lib/src/models/objects/frame.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of models;
+
+abstract class Frame {}
diff --git a/runtime/observatory/lib/src/models/objects/instance.dart b/runtime/observatory/lib/src/models/objects/instance.dart
new file mode 100644
index 0000000..b337f79
--- /dev/null
+++ b/runtime/observatory/lib/src/models/objects/instance.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of models;
+
+abstract class InstanceRef extends ObjectRef {}
diff --git a/runtime/observatory/lib/src/models/objects/isolate.dart b/runtime/observatory/lib/src/models/objects/isolate.dart
new file mode 100644
index 0000000..007a6f4
--- /dev/null
+++ b/runtime/observatory/lib/src/models/objects/isolate.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of models;
+
+abstract class IsolateRef {
+ String get id;
+ int get number;
+ String get name;
+}
+
+abstract class Isolate extends IsolateRef {
+ DateTime get startTime;
+ bool get runnable;
+}
diff --git a/runtime/observatory/lib/src/models/objects/library.dart b/runtime/observatory/lib/src/models/objects/library.dart
new file mode 100644
index 0000000..6543ef9
--- /dev/null
+++ b/runtime/observatory/lib/src/models/objects/library.dart
@@ -0,0 +1,33 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of models;
+
+abstract class LibraryRef extends ObjectRef {
+ /// The name of this library.
+ String get name;
+
+ /// The uri of this library.
+ String get uri;
+}
+
+abstract class Library extends Object implements LibraryRef {
+ /// Is this library debuggable? Default true.
+ bool get debuggable;
+
+ /// A list of the imports for this library.
+ //LibraryDependency[] dependencies;
+
+ // A list of the scripts which constitute this library.
+ Iterable<ScriptRef> get scripts;
+
+ // A list of the top-level variables in this library.
+ //List<FieldRef> get variables;
+
+ // A list of the top-level functions in this library.
+ //List<FunctionRef> get functions;
+
+ // A list of all classes in this library.
+ Iterable<ClassRef> get classes;
+}
diff --git a/runtime/observatory/lib/src/models/objects/notification.dart b/runtime/observatory/lib/src/models/objects/notification.dart
new file mode 100644
index 0000000..9a9f8af
--- /dev/null
+++ b/runtime/observatory/lib/src/models/objects/notification.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of models;
+
+abstract class Notification {}
+
+abstract class ExceptionNotification implements Notification{
+ Exception get exception;
+ /// [optional]
+ StackTrace get stacktrace;
+}
+
+abstract class EventNotification implements Notification{
+ Event get event;
+}
diff --git a/runtime/observatory/lib/src/models/objects/object.dart b/runtime/observatory/lib/src/models/objects/object.dart
new file mode 100644
index 0000000..76b2393
--- /dev/null
+++ b/runtime/observatory/lib/src/models/objects/object.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of models;
+
+abstract class ObjectRef {
+ /// A unique identifier for an Object.
+ String get id;
+}
+
+abstract class Object implements ObjectRef {}
diff --git a/runtime/observatory/lib/src/models/objects/script.dart b/runtime/observatory/lib/src/models/objects/script.dart
new file mode 100644
index 0000000..274fb08
--- /dev/null
+++ b/runtime/observatory/lib/src/models/objects/script.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of models;
+
+abstract class ScriptRef extends ObjectRef {
+ /// The uri from which this script was loaded.
+ String get uri;
+}
+
+abstract class Script extends Object implements ScriptRef {
+ /// The library which owns this script.
+ // LibraryRef get library;
+
+ /// The source code for this script. For certain built-in scripts,
+ /// this may be reconstructed without source comments.
+ String get source;
+
+ int tokenToLine(int token);
+ int tokenToCol(int token);
+}
diff --git a/runtime/observatory/lib/src/models/objects/source_location.dart b/runtime/observatory/lib/src/models/objects/source_location.dart
new file mode 100644
index 0000000..5d35d57
--- /dev/null
+++ b/runtime/observatory/lib/src/models/objects/source_location.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of models;
+
+abstract class SourceLocation {
+ /// The script containing the source location.
+ ScriptRef get script;
+ /// The first token of the location.
+ int get tokenPos;
+ /// The last token of the location if this is a range. [optional]
+ int get endTokenPos;
+}
diff --git a/runtime/observatory/lib/src/models/objects/target.dart b/runtime/observatory/lib/src/models/objects/target.dart
new file mode 100644
index 0000000..f2a1658
--- /dev/null
+++ b/runtime/observatory/lib/src/models/objects/target.dart
@@ -0,0 +1,9 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of models;
+
+abstract class Target {
+ String get name;
+}
diff --git a/runtime/observatory/lib/src/models/objects/timeline_event.dart b/runtime/observatory/lib/src/models/objects/timeline_event.dart
new file mode 100644
index 0000000..6cac6d1
--- /dev/null
+++ b/runtime/observatory/lib/src/models/objects/timeline_event.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of models;
+
+abstract class TimelineEvent implements Map<String, dynamic> {}
diff --git a/runtime/observatory/lib/src/models/objects/vm.dart b/runtime/observatory/lib/src/models/objects/vm.dart
new file mode 100644
index 0000000..051a9fa
--- /dev/null
+++ b/runtime/observatory/lib/src/models/objects/vm.dart
@@ -0,0 +1,34 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of models;
+
+abstract class VMRef {
+ String get name;
+}
+
+abstract class VM implements VMRef {
+ /// Word length on target architecture (e.g. 32, 64).
+ int get architectureBits;
+
+ /// The CPU we are generating code for.
+ String get targetCPU;
+
+ /// The CPU we are actually running on.
+ String get hostCPU;
+
+ /// The Dart VM version string.
+ String get version;
+
+ /// The process id for the VM.
+ int get pid;
+
+ /// The time that the VM started in milliseconds since the epoch.
+ ///
+ /// Suitable to pass to DateTime.fromMillisecondsSinceEpoch.
+ DateTime get startTime;
+
+ // A list of isolates running in the VM.
+ Iterable<IsolateRef> get isolates;
+}
diff --git a/runtime/observatory/lib/src/models/repositories/notification.dart b/runtime/observatory/lib/src/models/repositories/notification.dart
new file mode 100644
index 0000000..9ab3543
--- /dev/null
+++ b/runtime/observatory/lib/src/models/repositories/notification.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of models;
+
+abstract class NotificationChangeEvent {
+ NotificationRepository get repository;
+}
+
+abstract class NotificationRepository {
+ Stream<NotificationChangeEvent> get onChange;
+ Iterable<Notification> list();
+ void delete(Notification);
+ void deleteAll();
+}
diff --git a/runtime/observatory/lib/src/repositories/notification.dart b/runtime/observatory/lib/src/repositories/notification.dart
new file mode 100644
index 0000000..348dbca
--- /dev/null
+++ b/runtime/observatory/lib/src/repositories/notification.dart
@@ -0,0 +1,72 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file
+
+part of repositories;
+
+class NotificationChangeEvent implements M.NotificationChangeEvent {
+ final NotificationRepository repository;
+ NotificationChangeEvent(this.repository);
+}
+
+class NotificationRepository implements M.NotificationRepository {
+ final List<M.Notification> _list = new List<M.Notification>();
+
+ final StreamController<M.NotificationChangeEvent> _onChange =
+ new StreamController<M.NotificationChangeEvent>.broadcast();
+ Stream<M.NotificationChangeEvent> get onChange => _onChange.stream;
+
+ void add(M.Notification notification) {
+ assert(notification != null);
+ _list.add(notification);
+ _notify();
+ }
+
+ Iterable<M.Notification> list() => _list;
+
+ void delete(M.Notification notification) {
+ if (_list.remove(notification))
+ _notify();
+ }
+
+ void deleteAll() {
+ if (_list.isNotEmpty) {
+ _list.clear();
+ _notify();
+ }
+ }
+
+ NotificationRepository();
+
+ void _notify() {
+ _onChange.add(new NotificationChangeEvent(this));
+ }
+
+ void deleteWhere(bool test(M.Notification element)) {
+ int length = _list.length;
+ _list.removeWhere(test);
+ if (_list.length != length) _notify();
+ }
+
+ void deletePauseEvents({M.Isolate isolate}) {
+ if (isolate == null) {
+ deleteWhere((notification) {
+ return notification is M.EventNotification &&
+ M.Event.isPauseEvent(notification.event);
+ });
+ } else {
+ deleteWhere((notification) {
+ return notification is M.EventNotification &&
+ M.Event.isPauseEvent(notification.event) &&
+ notification.event.isolate == isolate;
+ });
+ }
+ }
+
+ void deleteDisconnectEvents() {
+ deleteWhere((notification) {
+ return notification is M.EventNotification &&
+ notification.event is M.ConnectionClosedEvent;
+ });
+ }
+}
diff --git a/runtime/observatory/lib/src/service/object.dart b/runtime/observatory/lib/src/service/object.dart
index 18d29bf..85574fe 100644
--- a/runtime/observatory/lib/src/service/object.dart
+++ b/runtime/observatory/lib/src/service/object.dart
@@ -22,14 +22,14 @@
/// An RpcException represents an exceptional event that happened
/// while invoking an rpc.
-abstract class RpcException implements Exception {
+abstract class RpcException implements Exception, M.BasicException {
RpcException(this.message);
String message;
}
/// A ServerRpcException represents an error returned by the VM.
-class ServerRpcException extends RpcException {
+class ServerRpcException extends RpcException implements M.RequestException {
/// A list of well-known server error codes.
static const kParseError = -32700;
static const kInvalidRequest = -32600;
@@ -70,7 +70,8 @@
/// A NetworkRpcException is used to indicate that an rpc has
/// been canceled due to network error.
-class NetworkRpcException extends RpcException {
+class NetworkRpcException extends RpcException
+ implements M.ConnectionException {
NetworkRpcException(String message) : super(message);
String toString() => 'NetworkRpcException(${message})';
@@ -424,7 +425,8 @@
}
/// A [SourceLocation] represents a location or range in the source code.
-class SourceLocation extends ServiceObject implements Location {
+class SourceLocation extends ServiceObject implements Location,
+ M.SourceLocation {
Script script;
int tokenPos;
int endTokenPos;
@@ -603,7 +605,7 @@
}
/// State for a VM being inspected.
-abstract class VM extends ServiceObjectOwner {
+abstract class VM extends ServiceObjectOwner implements M.VM {
@reflectable VM get vm => this;
@reflectable Isolate get isolate => null;
@@ -622,6 +624,7 @@
final ObservableList<Isolate> isolates = new ObservableList<Isolate>();
@observable String version = 'unknown';
+ @observable String hostCPU;
@observable String targetCPU;
@observable int architectureBits;
@observable bool assertsEnabled = false;
@@ -896,6 +899,7 @@
_loaded = true;
version = map['version'];
+ hostCPU = map['hostCPU'];
targetCPU = map['targetCPU'];
architectureBits = map['architectureBits'];
int startTimeMillis = map['startTime'];
@@ -1117,7 +1121,7 @@
}
/// State for a running isolate.
-class Isolate extends ServiceObjectOwner {
+class Isolate extends ServiceObjectOwner implements M.Isolate {
static const kLoggingStream = '_Logging';
static const kExtensionStream = 'Extension';
@@ -1451,7 +1455,11 @@
updateHeapsFromMap(map['_heaps']);
_updateBreakpoints(map['breakpoints']);
- exceptionsPauseInfo = map['_debuggerSettings']['_exceptions'];
+ if (map['_debuggerSettings'] != null) {
+ exceptionsPauseInfo = map['_debuggerSettings']['_exceptions'];
+ } else {
+ exceptionsPauseInfo = "none";
+ }
var newPauseEvent = map['pauseEvent'];
assert((pauseEvent == null) ||
@@ -1886,6 +1894,7 @@
static const kIsolateExit = 'IsolateExit';
static const kIsolateUpdate = 'IsolateUpdate';
static const kIsolateReload = 'IsolateReload';
+ static const kIsolateSpawn = 'IsolateSpawn';
static const kServiceExtensionAdded = 'ServiceExtensionAdded';
static const kPauseStart = 'PauseStart';
static const kPauseExit = 'PauseExit';
@@ -1929,6 +1938,8 @@
@observable String extensionKind;
@observable Map extensionData;
@observable List timelineEvents;
+ @observable String spawnToken;
+ @observable String spawnError;
int chunkIndex, chunkCount, nodeCount;
@@ -2011,6 +2022,12 @@
if (map['timelineEvents'] != null) {
timelineEvents = map['timelineEvents'];
}
+ if (map['spawnToken'] != null) {
+ spawnToken = map['spawnToken'];
+ }
+ if (map['spawnError'] != null) {
+ spawnError = map['spawnError'];
+ }
}
String toString() {
@@ -2025,7 +2042,7 @@
}
}
-class Breakpoint extends ServiceObject {
+class Breakpoint extends ServiceObject implements M.Breakpoint {
Breakpoint._empty(ServiceObjectOwner owner) : super._empty(owner);
// TODO(turnidge): Add state to track if a breakpoint has been
@@ -2121,7 +2138,7 @@
}
-class Library extends HeapObject {
+class Library extends HeapObject implements M.LibraryRef {
@observable String uri;
@reflectable final dependencies = new ObservableList<LibraryDependency>();
@reflectable final scripts = new ObservableList<Script>();
@@ -2223,7 +2240,7 @@
bool get empty => accumulated.empty && current.empty;
}
-class Class extends HeapObject {
+class Class extends HeapObject implements M.ClassRef {
@observable Library library;
@observable bool isAbstract;
@@ -2918,7 +2935,7 @@
LocalVarLocation(this.line, this.column, this.endColumn);
}
-class Script extends HeapObject {
+class Script extends HeapObject implements M.Script {
final lines = new ObservableList<ScriptLine>();
@observable String uri;
@observable String kind;
@@ -2929,6 +2946,8 @@
@observable int columnOffset;
@observable Library library;
+ String source;
+
bool get immutable => true;
String _shortUri;
@@ -3030,6 +3049,7 @@
lineOffset = map['lineOffset'];
columnOffset = map['columnOffset'];
_parseTokenPosTable(map['tokenPosTable']);
+ source = map['source'];
_processSource(map['source']);
library = map['library'];
}
@@ -3987,7 +4007,7 @@
}
}
-class Frame extends ServiceObject {
+class Frame extends ServiceObject implements M.Frame {
@observable int index;
@observable ServiceFunction function;
@observable SourceLocation location;
diff --git a/runtime/observatory/observatory_sources.gypi b/runtime/observatory/observatory_sources.gypi
index c2084e1..30659e0 100644
--- a/runtime/observatory/observatory_sources.gypi
+++ b/runtime/observatory/observatory_sources.gypi
@@ -11,7 +11,10 @@
'lib/debugger.dart',
'lib/elements.dart',
'lib/elements.html',
+ 'lib/mocks.dart',
+ 'lib/models.dart',
'lib/object_graph.dart',
+ 'lib/repositories.dart',
'lib/service.dart',
'lib/service_common.dart',
'lib/service_html.dart',
@@ -19,6 +22,7 @@
'lib/src/app/analytics.dart',
'lib/src/app/application.dart',
'lib/src/app/location_manager.dart',
+ 'lib/src/app/notification.dart',
'lib/src/app/page.dart',
'lib/src/app/settings.dart',
'lib/src/app/target_manager.dart',
@@ -47,7 +51,7 @@
'lib/src/elements/cpu_profile.html',
'lib/src/elements/css/shared.css',
'lib/src/elements/curly_block.dart',
- 'lib/src/elements/curly_block.html',
+ 'lib/src/elements/curly_block_wrapper.dart',
'lib/src/elements/debugger.dart',
'lib/src/elements/debugger.html',
'lib/src/elements/error_ref.dart',
@@ -76,6 +80,10 @@
'lib/src/elements/heap_profile.html',
'lib/src/elements/heap_snapshot.dart',
'lib/src/elements/heap_snapshot.html',
+ 'lib/src/elements/helpers/rendering_queue.dart',
+ 'lib/src/elements/helpers/rendering_scheduler.dart',
+ 'lib/src/elements/helpers/tag.dart',
+ 'lib/src/elements/helpers/uris.dart',
'lib/src/elements/icdata_view.dart',
'lib/src/elements/icdata_view.html',
'lib/src/elements/img/chromium_icon.png',
@@ -94,7 +102,7 @@
'lib/src/elements/isolate_reconnect.dart',
'lib/src/elements/isolate_reconnect.html',
'lib/src/elements/isolate_ref.dart',
- 'lib/src/elements/isolate_ref.html',
+ 'lib/src/elements/isolate_ref_wrapper.dart',
'lib/src/elements/isolate_summary.dart',
'lib/src/elements/isolate_summary.html',
'lib/src/elements/isolate_view.dart',
@@ -113,8 +121,27 @@
'lib/src/elements/megamorphiccache_view.html',
'lib/src/elements/metrics.dart',
'lib/src/elements/metrics.html',
- 'lib/src/elements/nav_bar.dart',
- 'lib/src/elements/nav_bar.html',
+ 'lib/src/elements/nav/bar.dart',
+ 'lib/src/elements/nav/class_menu.dart',
+ 'lib/src/elements/nav/class_menu_wrapper.dart',
+ 'lib/src/elements/nav/isolate_menu.dart',
+ 'lib/src/elements/nav/isolate_menu_wrapper.dart',
+ 'lib/src/elements/nav/library_menu.dart',
+ 'lib/src/elements/nav/library_menu_wrapper.dart',
+ 'lib/src/elements/nav/menu_item.dart',
+ 'lib/src/elements/nav/menu_item_wrapper.dart',
+ 'lib/src/elements/nav/menu.dart',
+ 'lib/src/elements/nav/menu_wrapper.dart',
+ 'lib/src/elements/nav/notify_event.dart',
+ 'lib/src/elements/nav/notify_exception.dart',
+ 'lib/src/elements/nav/notify.dart',
+ 'lib/src/elements/nav/notify_wrapper.dart',
+ 'lib/src/elements/nav/refresh.dart',
+ 'lib/src/elements/nav/refresh_wrapper.dart',
+ 'lib/src/elements/nav/top_menu.dart',
+ 'lib/src/elements/nav/top_menu_wrapper.dart',
+ 'lib/src/elements/nav/vm_menu.dart',
+ 'lib/src/elements/nav/vm_menu_wrapper.dart',
'lib/src/elements/object_common.dart',
'lib/src/elements/object_common.html',
'lib/src/elements/object_view.dart',
@@ -124,7 +151,6 @@
'lib/src/elements/observatory_application.dart',
'lib/src/elements/observatory_application.html',
'lib/src/elements/observatory_element.dart',
- 'lib/src/elements/observatory_element.html',
'lib/src/elements/persistent_handles.dart',
'lib/src/elements/persistent_handles.html',
'lib/src/elements/ports.dart',
@@ -139,18 +165,47 @@
'lib/src/elements/service_ref.html',
'lib/src/elements/service_view.dart',
'lib/src/elements/service_view.html',
- 'lib/src/elements/sliding_checkbox.dart',
- 'lib/src/elements/sliding_checkbox.html',
+ 'lib/src/elements/shims/binding.dart',
'lib/src/elements/timeline_page.dart',
'lib/src/elements/timeline_page.html',
'lib/src/elements/view_footer.dart',
- 'lib/src/elements/view_footer.html',
+ 'lib/src/elements/vm_connect_target.dart',
+ 'lib/src/elements/vm_connect_target_wrapper.dart',
'lib/src/elements/vm_connect.dart',
'lib/src/elements/vm_connect.html',
- 'lib/src/elements/vm_ref.dart',
- 'lib/src/elements/vm_ref.html',
'lib/src/elements/vm_view.dart',
'lib/src/elements/vm_view.html',
+ 'lib/src/mocks/exceptions/connection_exception.dart',
+ 'lib/src/mocks/objects/error.dart',
+ 'lib/src/mocks/objects/event.dart',
+ 'lib/src/mocks/objects/class.dart',
+ 'lib/src/mocks/objects/isolate.dart',
+ 'lib/src/mocks/objects/library.dart',
+ 'lib/src/mocks/objects/notification.dart',
+ 'lib/src/mocks/objects/script.dart',
+ 'lib/src/mocks/objects/source_location.dart',
+ 'lib/src/mocks/objects/target.dart',
+ 'lib/src/mocks/objects/vm.dart',
+ 'lib/src/mocks/repositories/notification.dart',
+ 'lib/src/models/exceptions.dart',
+ 'lib/src/models/objects/breakpoint.dart',
+ 'lib/src/models/objects/class.dart',
+ 'lib/src/models/objects/error.dart',
+ 'lib/src/models/objects/event.dart',
+ 'lib/src/models/objects/extension_data.dart',
+ 'lib/src/models/objects/frame.dart',
+ 'lib/src/models/objects/instance.dart',
+ 'lib/src/models/objects/isolate.dart',
+ 'lib/src/models/objects/library.dart',
+ 'lib/src/models/objects/notification.dart',
+ 'lib/src/models/objects/object.dart',
+ 'lib/src/models/objects/script.dart',
+ 'lib/src/models/objects/source_location.dart',
+ 'lib/src/models/objects/target.dart',
+ 'lib/src/models/objects/timeline_event.dart',
+ 'lib/src/models/objects/vm.dart',
+ 'lib/src/models/repositories/notification.dart',
+ 'lib/src/repositories/notification.dart',
'lib/src/service/object.dart',
'lib/tracer.dart',
'lib/utils.dart',
diff --git a/runtime/observatory/tests/observatory_ui/curly_block/element_test.dart b/runtime/observatory/tests/observatory_ui/curly_block/element_test.dart
new file mode 100644
index 0000000..fe1ca8f
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/curly_block/element_test.dart
@@ -0,0 +1,179 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+import 'dart:html';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/src/elements/curly_block.dart';
+
+main() {
+ CurlyBlockElement.tag.ensureRegistration();
+
+ group('instantiation', () {
+ test('default', () {
+ final CurlyBlockElement e = new CurlyBlockElement();
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.expanded, isFalse);
+ expect(e.disabled, isFalse);
+ });
+ test('not expanded', () {
+ final CurlyBlockElement e = new CurlyBlockElement(expanded: false);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.expanded, isFalse);
+ expect(e.disabled, isFalse);
+ });
+ test('not expanded / not disabled', () {
+ final CurlyBlockElement e = new CurlyBlockElement(expanded: false,
+ disabled: false);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.expanded, isFalse);
+ expect(e.disabled, isFalse);
+ });
+ test('not expanded / disabled', () {
+ final CurlyBlockElement e = new CurlyBlockElement(expanded: false,
+ disabled: true);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.expanded, isFalse);
+ expect(e.disabled, isTrue);
+ });
+ test('expanded', () {
+ final CurlyBlockElement e = new CurlyBlockElement(expanded: true);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.expanded, isTrue);
+ expect(e.disabled, isFalse);
+ });
+ test('expanded / not disabled', () {
+ final CurlyBlockElement e = new CurlyBlockElement(expanded: true,
+ disabled: false);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.expanded, isTrue);
+ expect(e.disabled, isFalse);
+ });
+ test('expanded / disabled', () {
+ final CurlyBlockElement e = new CurlyBlockElement(expanded: true,
+ disabled: true);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.expanded, isTrue);
+ expect(e.disabled, isTrue);
+ });
+ test('not disabled', () {
+ final CurlyBlockElement e = new CurlyBlockElement(disabled: false);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.expanded, isFalse);
+ expect(e.disabled, isFalse);
+ });
+ test('disabled', () {
+ final CurlyBlockElement e = new CurlyBlockElement(disabled: true);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.expanded, isFalse);
+ expect(e.disabled, isTrue);
+ });
+ });
+ test('elements created', () async {
+ final CurlyBlockElement e = new CurlyBlockElement();
+ expect(e.shadowRoot, isNotNull, reason: 'shadowRoot is created');
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.shadowRoot.children.length, isNonZero,
+ reason: 'shadowRoot has elements');
+ e.remove();
+ await e.onRendered.first;
+ expect(e.shadowRoot.children.length, isZero, reason: 'shadowRoot is empty');
+ });
+ group('content', () {
+ CurlyBlockElement e;
+ setUp(() async {
+ e = new CurlyBlockElement();
+ document.body.append(e);
+ await e.onRendered.first;
+ });
+ tearDown(() {
+ e.remove();
+ });
+ test('toggles visibility', () async {
+ expect(e.shadowRoot.querySelector('content'), isNull);
+ e.toggle();
+ await e.onRendered.first;
+ expect(e.shadowRoot.querySelector('content'), isNotNull);
+ e.toggle();
+ await e.onRendered.first;
+ expect(e.shadowRoot.querySelector('content'), isNull);
+ e.remove();
+ });
+ test('toggles visibility (manually)', () async {
+ expect(e.shadowRoot.querySelector('content'), isNull);
+ e.expanded = true;
+ await e.onRendered.first;
+ expect(e.shadowRoot.querySelector('content'), isNotNull);
+ e.expanded = false;
+ await e.onRendered.first;
+ expect(e.shadowRoot.querySelector('content'), isNull);
+ e.remove();
+ });
+ test('does not toggle if disabled', () async {
+ e.disabled = true;
+ await e.onRendered.first;
+ expect(e.expanded, isFalse);
+ expect(e.shadowRoot.querySelector('content'), isNull);
+ e.toggle();
+ await e.onRendered.first;
+ expect(e.expanded, isFalse);
+ expect(e.shadowRoot.querySelector('content'), isNull);
+ e.disabled = false;
+ e.toggle();
+ await e.onRendered.first;
+ expect(e.expanded, isTrue);
+ expect(e.shadowRoot.querySelector('content'), isNotNull);
+ e.disabled = true;
+ e.toggle();
+ await e.onRendered.first;
+ expect(e.expanded, isTrue);
+ expect(e.shadowRoot.querySelector('content'), isNotNull);
+ e.remove();
+ });
+ test('toggles visibility (manually) if disabled', () async {
+ e.disabled = true;
+ await e.onRendered.first;
+ expect(e.shadowRoot.querySelector('content'), isNull);
+ e.expanded = true;
+ await e.onRendered.first;
+ expect(e.shadowRoot.querySelector('content'), isNotNull);
+ e.expanded = false;
+ await e.onRendered.first;
+ expect(e.shadowRoot.querySelector('content'), isNull);
+ e.remove();
+ });
+ });
+ group('event', () {
+ CurlyBlockElement e;
+ setUp(() async {
+ e = new CurlyBlockElement();
+ document.body.append(e);
+ await e.onRendered.first;
+ });
+ tearDown(() async {
+ e.remove();
+ await e.onRendered.first;
+ });
+ test('fires on toggle', () async {
+ e.onToggle.listen(expectAsync((CurlyBlockToggleEvent event){
+ expect(event, isNotNull);
+ expect(event.control, equals(e));
+ }, count: 1));
+ e.toggle();
+ await e.onRendered.first;
+ });
+ test('fires on manual toggle', () async {
+ e.onToggle.listen(expectAsync((CurlyBlockToggleEvent event){
+ expect(event, isNotNull);
+ expect(event.control, equals(e));
+ }, count: 1));
+ e.expanded = !e.expanded;
+ await e.onRendered.first;
+ });
+ test('does not fire if setting same expanded value', () async {
+ e.onToggle.listen(expectAsync((_){}, count: 0));
+ e.expanded = e.expanded;
+ await e.onRendered.first;
+ });
+ });
+}
diff --git a/runtime/observatory/tests/observatory_ui/curly_block/element_test.html b/runtime/observatory/tests/observatory_ui/curly_block/element_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/curly_block/element_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="dart.unittest" content="full-stack-traces">
+ <style>
+ .unittest-table { font-family:monospace; border:1px; }
+ .unittest-pass { background: #6b3;}
+ .unittest-fail { background: #d55;}
+ .unittest-error { background: #a11;}
+ </style>
+ <script src="/packages/web_components/webcomponents.js"></script>
+ <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+ <script type="text/javascript"
+ src="/root_dart/tools/testing/dart/test_controller.js"></script>
+ %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/observatory_ui/nav/bar/element_test.dart b/runtime/observatory/tests/observatory_ui/nav/bar/element_test.dart
new file mode 100644
index 0000000..fe54785
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/nav/bar/element_test.dart
@@ -0,0 +1,26 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+import 'dart:html';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/src/elements/nav/bar.dart';
+
+main() {
+ NavBarElement.tag.ensureRegistration();
+
+ test('instantiation', () {
+ final NavBarElement e = new NavBarElement();
+ expect(e, isNotNull, reason: 'element correctly created');
+ });
+ test('elements created', () async {
+ final NavBarElement e = new NavBarElement();
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.shadowRoot.children.length, isNonZero, reason: 'has elements');
+ expect(e.shadowRoot.querySelector('content'), isNotNull,
+ reason: 'has content elements');
+ e.remove();
+ await e.onRendered.first;
+ expect(e.shadowRoot.children.length, isZero, reason: 'is empty');
+ });
+}
diff --git a/runtime/observatory/tests/observatory_ui/nav/bar/element_test.html b/runtime/observatory/tests/observatory_ui/nav/bar/element_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/nav/bar/element_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="dart.unittest" content="full-stack-traces">
+ <style>
+ .unittest-table { font-family:monospace; border:1px; }
+ .unittest-pass { background: #6b3;}
+ .unittest-fail { background: #d55;}
+ .unittest-error { background: #a11;}
+ </style>
+ <script src="/packages/web_components/webcomponents.js"></script>
+ <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+ <script type="text/javascript"
+ src="/root_dart/tools/testing/dart/test_controller.js"></script>
+ %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/observatory_ui/nav/class-menu/element_test.dart b/runtime/observatory/tests/observatory_ui/nav/class-menu/element_test.dart
new file mode 100644
index 0000000..df83ea4
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/nav/class-menu/element_test.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+import 'dart:html';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/mocks.dart';
+import 'package:observatory/src/elements/nav/class_menu.dart';
+
+main(){
+ NavClassMenuElement.tag.ensureRegistration();
+
+ final IsolateRefMock i_ref = const IsolateRefMock(id: 'i-id', name: 'i-name');
+ final ClassRefMock c_ref = const ClassRefMock(id: 'c-id', name: 'c-name');
+ test('instantiation', () {
+ final NavClassMenuElement e = new NavClassMenuElement(i_ref, c_ref);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.isolate, equals(i_ref));
+ expect(e.cls, equals(c_ref));
+ });
+ test('elements created after attachment', () async {
+ final NavClassMenuElement e = new NavClassMenuElement(i_ref, c_ref);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.shadowRoot.children.length, isNonZero, reason: 'has elements');
+ e.remove();
+ await e.onRendered.first;
+ expect(e.shadowRoot.children.length, isZero, reason: 'is empty');
+ });
+}
diff --git a/runtime/observatory/tests/observatory_ui/nav/class-menu/element_test.html b/runtime/observatory/tests/observatory_ui/nav/class-menu/element_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/nav/class-menu/element_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="dart.unittest" content="full-stack-traces">
+ <style>
+ .unittest-table { font-family:monospace; border:1px; }
+ .unittest-pass { background: #6b3;}
+ .unittest-fail { background: #d55;}
+ .unittest-error { background: #a11;}
+ </style>
+ <script src="/packages/web_components/webcomponents.js"></script>
+ <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+ <script type="text/javascript"
+ src="/root_dart/tools/testing/dart/test_controller.js"></script>
+ %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/observatory_ui/nav/isolate-menu/element_test.dart b/runtime/observatory/tests/observatory_ui/nav/isolate-menu/element_test.dart
new file mode 100644
index 0000000..27bf79c
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/nav/isolate-menu/element_test.dart
@@ -0,0 +1,75 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+import 'dart:html';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/models.dart';
+import 'package:observatory/mocks.dart';
+import 'package:observatory/src/elements/nav/menu.dart';
+import 'package:observatory/src/elements/nav/isolate_menu.dart';
+
+main(){
+ NavIsolateMenuElement.tag.ensureRegistration();
+
+ final String tag = NavMenuElement.tag.name;
+
+ StreamController<IsolateUpdateEvent> updatesController;
+ final IsolateRefMock ref = const IsolateRefMock(id: 'i-id', name: 'old-name');
+ final IsolateMock obj = const IsolateMock(id: 'i-id', name: 'new-name');
+ setUp(() {
+ updatesController = new StreamController<IsolateUpdateEvent>();
+ });
+ group('instantiation', () {
+ test('IsolateRef', () {
+ final NavIsolateMenuElement e = new NavIsolateMenuElement(ref,
+ updatesController.stream);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.isolate, equals(ref));
+ });
+ test('Isolate', () {
+ final NavIsolateMenuElement e = new NavIsolateMenuElement(obj,
+ updatesController.stream);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.isolate, equals(obj));
+ });
+ });
+ test('elements created after attachment', () async {
+ final NavIsolateMenuElement e = new NavIsolateMenuElement(ref,
+ updatesController.stream);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.shadowRoot.children.length, isNonZero, reason: 'has elements');
+ e.remove();
+ await e.onRendered.first;
+ expect(e.shadowRoot.children.length, isZero, reason: 'is empty');
+ });
+ group('updates', () {
+ test('are correctly listen', () async {
+ final NavIsolateMenuElement e = new NavIsolateMenuElement(ref,
+ updatesController.stream);
+ expect(updatesController.hasListener, isFalse);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(updatesController.hasListener, isTrue);
+ e.remove();
+ await e.onRendered.first;
+ expect(updatesController.hasListener, isFalse);
+ });
+ test('have effects', () async {
+ final NavIsolateMenuElement e = new NavIsolateMenuElement(ref,
+ updatesController.stream);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect((e.shadowRoot.querySelector(tag) as NavMenuElement)
+ .label.contains(ref.name), isTrue);
+ updatesController.add(new IsolateUpdateEventMock(isolate: obj));
+ await e.onRendered.first;
+ expect((e.shadowRoot.querySelector(tag) as NavMenuElement)
+ .label.contains(ref.name), isFalse);
+ expect((e.shadowRoot.querySelector(tag) as NavMenuElement)
+ .label.contains(obj.name), isTrue);
+ e.remove();
+ });
+ });
+}
diff --git a/runtime/observatory/tests/observatory_ui/nav/isolate-menu/element_test.html b/runtime/observatory/tests/observatory_ui/nav/isolate-menu/element_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/nav/isolate-menu/element_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="dart.unittest" content="full-stack-traces">
+ <style>
+ .unittest-table { font-family:monospace; border:1px; }
+ .unittest-pass { background: #6b3;}
+ .unittest-fail { background: #d55;}
+ .unittest-error { background: #a11;}
+ </style>
+ <script src="/packages/web_components/webcomponents.js"></script>
+ <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+ <script type="text/javascript"
+ src="/root_dart/tools/testing/dart/test_controller.js"></script>
+ %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/observatory_ui/nav/library-menu/element_test.dart b/runtime/observatory/tests/observatory_ui/nav/library-menu/element_test.dart
new file mode 100644
index 0000000..f6967c9
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/nav/library-menu/element_test.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+import 'dart:html';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/mocks.dart';
+import 'package:observatory/src/elements/nav/library_menu.dart';
+
+main(){
+ NavLibraryMenuElement.tag.ensureRegistration();
+
+ final IsolateRefMock i_ref = const IsolateRefMock(id: 'i-id', name: 'i-name');
+ final LibraryRefMock l_ref = const LibraryRefMock(id: 'l-id', name: 'l-name');
+ test('instantiation', () {
+ final NavLibraryMenuElement e = new NavLibraryMenuElement(i_ref, l_ref);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.isolate, equals(i_ref));
+ expect(e.library, equals(l_ref));
+ });
+ test('elements created after attachment', () async {
+ final NavLibraryMenuElement e = new NavLibraryMenuElement(i_ref, l_ref);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.shadowRoot.children.length, isNonZero, reason: 'has elements');
+ e.remove();
+ await e.onRendered.first;
+ expect(e.shadowRoot.children.length, isZero, reason: 'is empty');
+ });
+}
diff --git a/runtime/observatory/tests/observatory_ui/nav/library-menu/element_test.html b/runtime/observatory/tests/observatory_ui/nav/library-menu/element_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/nav/library-menu/element_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="dart.unittest" content="full-stack-traces">
+ <style>
+ .unittest-table { font-family:monospace; border:1px; }
+ .unittest-pass { background: #6b3;}
+ .unittest-fail { background: #d55;}
+ .unittest-error { background: #a11;}
+ </style>
+ <script src="/packages/web_components/webcomponents.js"></script>
+ <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+ <script type="text/javascript"
+ src="/root_dart/tools/testing/dart/test_controller.js"></script>
+ %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/observatory_ui/nav/menu-item/element_test.dart b/runtime/observatory/tests/observatory_ui/nav/menu-item/element_test.dart
new file mode 100644
index 0000000..f4ee551
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/nav/menu-item/element_test.dart
@@ -0,0 +1,70 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+import 'dart:html';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/src/elements/nav/menu_item.dart';
+
+main() {
+ NavMenuItemElement.tag.ensureRegistration();
+
+ group('instantiation', () {
+ final label = 'custom-label';
+ final link = 'link-to-target';
+ test('label', () {
+ final NavMenuItemElement e = new NavMenuItemElement(label);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.label, equals(label), reason: 'element correctly created');
+ });
+ test('label', () {
+ final NavMenuItemElement e = new NavMenuItemElement(label, link: link);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.link, equals(link), reason: 'element correctly created');
+ });
+ });
+ group('elements', () {
+ test('created', () async {
+ final label = 'custom-label';
+ final NavMenuItemElement e = new NavMenuItemElement(label);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.shadowRoot.children.length, isNonZero, reason: 'has elements');
+ expect(e.shadowRoot.querySelector('content'), isNotNull,
+ reason: 'has content elements');
+ e.remove();
+ await e.onRendered.first;
+ expect(e.shadowRoot.children.length, isZero, reason: 'is empty');
+ });
+ test('react to label change', () async {
+ final label1 = 'custom-label-1';
+ final label2 = 'custom-label-2';
+ final NavMenuItemElement e = new NavMenuItemElement(label1);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.shadowRoot.innerHtml.contains(label1), isTrue);
+ expect(e.shadowRoot.innerHtml.contains(label2), isFalse);
+ e.label = label2;
+ await e.onRendered.first;
+ expect(e.shadowRoot.innerHtml.contains(label1), isFalse);
+ expect(e.shadowRoot.innerHtml.contains(label2), isTrue);
+ e.remove();
+ await e.onRendered.first;
+ });
+ test('react to link change', () async {
+ final label = 'custom-label';
+ final link1 = 'custom-label-1';
+ final link2 = 'custom-label-2';
+ final NavMenuItemElement e = new NavMenuItemElement(label, link: link1);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.shadowRoot.innerHtml.contains(link1), isTrue);
+ expect(e.shadowRoot.innerHtml.contains(link2), isFalse);
+ e.link = link2;
+ await e.onRendered.first;
+ expect(e.shadowRoot.innerHtml.contains(link1), isFalse);
+ expect(e.shadowRoot.innerHtml.contains(link2), isTrue);
+ e.remove();
+ await e.onRendered.first;
+ });
+ });
+}
diff --git a/runtime/observatory/tests/observatory_ui/nav/menu-item/element_test.html b/runtime/observatory/tests/observatory_ui/nav/menu-item/element_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/nav/menu-item/element_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="dart.unittest" content="full-stack-traces">
+ <style>
+ .unittest-table { font-family:monospace; border:1px; }
+ .unittest-pass { background: #6b3;}
+ .unittest-fail { background: #d55;}
+ .unittest-error { background: #a11;}
+ </style>
+ <script src="/packages/web_components/webcomponents.js"></script>
+ <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+ <script type="text/javascript"
+ src="/root_dart/tools/testing/dart/test_controller.js"></script>
+ %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/observatory_ui/nav/menu/element_test.dart b/runtime/observatory/tests/observatory_ui/nav/menu/element_test.dart
new file mode 100644
index 0000000..0cabc3c
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/nav/menu/element_test.dart
@@ -0,0 +1,73 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+import 'dart:html';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/src/elements/nav/menu.dart';
+
+main() {
+ NavMenuElement.tag.ensureRegistration();
+
+ group('instantiation', () {
+ final label = 'custom-label';
+ test('label', () {
+ final NavMenuElement e = new NavMenuElement(label);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.label, equals(label), reason: 'element correctly created');
+ });
+ test('not last', () {
+ final NavMenuElement e = new NavMenuElement(label, last: false);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.last, isFalse, reason: 'element correctly created');
+ });
+ test('last', () {
+ final NavMenuElement e = new NavMenuElement(label, last: true);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.last, isTrue, reason: 'element correctly created');
+ });
+ });
+ group('elements', () {
+ test('created', () async {
+ final label = 'custom-label';
+ final NavMenuElement e = new NavMenuElement(label);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.shadowRoot.children.length, isNonZero, reason: 'has elements');
+ expect(e.shadowRoot.querySelector('content'), isNotNull,
+ reason: 'has content elements');
+ e.remove();
+ await e.onRendered.first;
+ expect(e.shadowRoot.children.length, isZero, reason: 'is empty');
+ });
+ test('react to label change', () async {
+ final label1 = 'custom-label-1';
+ final label2 = 'custom-label-2';
+ final NavMenuElement e = new NavMenuElement(label1);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.shadowRoot.innerHtml.contains(label1), isTrue);
+ expect(e.shadowRoot.innerHtml.contains(label2), isFalse);
+ e.label = label2;
+ await e.onRendered.first;
+ expect(e.shadowRoot.innerHtml.contains(label1), isFalse);
+ expect(e.shadowRoot.innerHtml.contains(label2), isTrue);
+ e.remove();
+ await e.onRendered.first;
+ });
+ test('react to last change', () async {
+ final label = 'custom-label';
+ final NavMenuElement e = new NavMenuElement(label, last: false);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.shadowRoot.innerHtml.contains('>'), isTrue);
+ e.last = true;
+ await e.onRendered.first;
+ expect(e.shadowRoot.innerHtml.contains('>'), isFalse);
+ e.last = false;
+ await e.onRendered.first;
+ expect(e.shadowRoot.innerHtml.contains('>'), isTrue);
+ e.remove();
+ await e.onRendered.first;
+ });
+ });
+}
diff --git a/runtime/observatory/tests/observatory_ui/nav/menu/element_test.html b/runtime/observatory/tests/observatory_ui/nav/menu/element_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/nav/menu/element_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="dart.unittest" content="full-stack-traces">
+ <style>
+ .unittest-table { font-family:monospace; border:1px; }
+ .unittest-pass { background: #6b3;}
+ .unittest-fail { background: #d55;}
+ .unittest-error { background: #a11;}
+ </style>
+ <script src="/packages/web_components/webcomponents.js"></script>
+ <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+ <script type="text/javascript"
+ src="/root_dart/tools/testing/dart/test_controller.js"></script>
+ %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/observatory_ui/nav/notify/element_test.dart b/runtime/observatory/tests/observatory_ui/nav/notify/element_test.dart
new file mode 100644
index 0000000..64adcfb
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/nav/notify/element_test.dart
@@ -0,0 +1,121 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+import 'dart:html' hide Notification, NotificationEvent;
+import 'package:unittest/unittest.dart';
+import 'package:observatory/mocks.dart';
+import 'package:observatory/models.dart' as M;
+import 'package:observatory/src/elements/nav/notify.dart';
+import 'package:observatory/src/elements/nav/notify_event.dart';
+import 'package:observatory/src/elements/nav/notify_exception.dart';
+
+main() {
+ NavNotifyElement.tag.ensureRegistration();
+
+ final evTag = NavNotifyEventElement.tag.name;
+ final exTag = NavNotifyExceptionElement.tag.name;
+
+ const vm = const VMRefMock();
+ const isolate = const IsolateRefMock(id: 'i-id', name: 'i-name');
+
+ group('instantiation', () {
+ test('default', () {
+ final NavNotifyElement e = new NavNotifyElement(
+ new NotificationRepositoryMock());
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.notifyOnPause, isTrue, reason: 'notifyOnPause is default');
+ });
+ test('notify on pause', () {
+ final NavNotifyElement e = new NavNotifyElement(
+ new NotificationRepositoryMock(), notifyOnPause: true);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.notifyOnPause, isTrue, reason: 'notifyOnPause is the same');
+ });
+ test('do not notify on pause', () {
+ final NavNotifyElement e = new NavNotifyElement(
+ new NotificationRepositoryMock(), notifyOnPause: false);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.notifyOnPause, isFalse, reason: 'notifyOnPause is the same');
+ });
+ });
+ test('is correctly listening', () async {
+ final NotificationRepositoryMock repository =
+ new NotificationRepositoryMock();
+ final NavNotifyElement e = new NavNotifyElement(repository);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(repository.hasListeners, isTrue, reason: 'is listening');
+ e.remove();
+ await e.onRendered.first;
+ expect(repository.hasListeners, isFalse, reason: 'is no more listening');
+ });
+ group('elements', () {
+ test('created after attachment', () async {
+ final NotificationRepositoryMock repository =
+ new NotificationRepositoryMock(list: [
+ new ExceptionNotificationMock(exception: new Exception("ex")),
+ const EventNotificationMock(event: const VMUpdateEventMock(vm: vm)),
+ const EventNotificationMock(event: const VMUpdateEventMock(vm: vm))
+ ]);
+ final NavNotifyElement e = new NavNotifyElement(repository);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(repository.listInvoked, isTrue, reason: 'should invoke list()');
+ expect(e.children.length, isNonZero, reason: 'has elements');
+ expect(e.querySelectorAll(evTag).length, equals(2));
+ expect(e.querySelectorAll(exTag).length, equals(1));
+ e.remove();
+ await e.onRendered.first;
+ expect(e.children.length, isZero, reason: 'is empty');
+ });
+ test('react to notifyOnPause change', () async {
+ final NotificationRepositoryMock repository =
+ new NotificationRepositoryMock(list: [
+ new ExceptionNotificationMock(exception: new Exception("ex")),
+ const EventNotificationMock(event: const VMUpdateEventMock()),
+ const EventNotificationMock(
+ event: const PauseStartEventMock(isolate: isolate))
+ ]);
+ final NavNotifyElement e = new NavNotifyElement(repository,
+ notifyOnPause: true);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.querySelectorAll(evTag).length, equals(2));
+ expect(e.querySelectorAll(exTag).length, equals(1));
+ e.notifyOnPause = false;
+ await e.onRendered.first;
+ expect(e.querySelectorAll(evTag).length, equals(1));
+ expect(e.querySelectorAll(exTag).length, equals(1));
+ e.notifyOnPause = true;
+ await e.onRendered.first;
+ expect(e.querySelectorAll(evTag).length, equals(2));
+ expect(e.querySelectorAll(exTag).length, equals(1));
+ e.remove();
+ await e.onRendered.first;
+ expect(e.children.length, isZero, reason: 'is empty');
+ });
+ test('react to update event', () async {
+ final List<M.Notification> list = [
+ new ExceptionNotificationMock(exception: new Exception("ex")),
+ const EventNotificationMock(event: const VMUpdateEventMock()),
+ ];
+ final NotificationRepositoryMock repository =
+ new NotificationRepositoryMock(list: list);
+ final NavNotifyElement e = new NavNotifyElement(repository,
+ notifyOnPause: true);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.querySelectorAll(evTag).length, equals(1));
+ expect(e.querySelectorAll(exTag).length, equals(1));
+ list.add(const EventNotificationMock(
+ event: const PauseStartEventMock(isolate: isolate)));
+ repository.triggerChangeEvent();
+ await e.onRendered.first;
+ expect(e.querySelectorAll(evTag).length, equals(2));
+ expect(e.querySelectorAll(exTag).length, equals(1));
+ e.remove();
+ await e.onRendered.first;
+ expect(e.children.length, isZero, reason: 'is empty');
+ });
+ });
+}
diff --git a/runtime/observatory/tests/observatory_ui/nav/notify/element_test.html b/runtime/observatory/tests/observatory_ui/nav/notify/element_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/nav/notify/element_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="dart.unittest" content="full-stack-traces">
+ <style>
+ .unittest-table { font-family:monospace; border:1px; }
+ .unittest-pass { background: #6b3;}
+ .unittest-fail { background: #d55;}
+ .unittest-error { background: #a11;}
+ </style>
+ <script src="/packages/web_components/webcomponents.js"></script>
+ <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+ <script type="text/javascript"
+ src="/root_dart/tools/testing/dart/test_controller.js"></script>
+ %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/observatory_ui/nav/notify_event/element_test.dart b/runtime/observatory/tests/observatory_ui/nav/notify_event/element_test.dart
new file mode 100644
index 0000000..5d5de5c
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/nav/notify_event/element_test.dart
@@ -0,0 +1,65 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+import 'dart:html';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/mocks.dart';
+import 'package:observatory/src/elements/nav/notify_event.dart';
+
+main() {
+ NavNotifyEventElement.tag.ensureRegistration();
+
+ final PauseStartEventMock event = new PauseStartEventMock(
+ isolate: new IsolateMock(id: 'isolate-id', name: 'isolate-name'));
+ group('instantiation', () {
+ final NavNotifyEventElement e = new NavNotifyEventElement(event);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.event, equals(event));
+ });
+ group('elements', () {
+ test('created after attachment', () async {
+ final NavNotifyEventElement e = new NavNotifyEventElement(event);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.children.length, isNonZero, reason: 'has elements');
+ e.remove();
+ await e.onRendered.first;
+ expect(e.children.length, isZero, reason: 'is empty');
+ });
+ });
+ group('events are fired', () {
+ NavNotifyEventElement e;
+ StreamSubscription sub;
+ setUp(() async {
+ e = new NavNotifyEventElement(event);
+ document.body.append(e);
+ await e.onRendered.first;
+ });
+ tearDown(() {
+ sub.cancel();
+ e.remove();
+ });
+ test('navigation after connect', () async {
+ sub = window.onPopState.listen(expectAsync((_) {}, count: 1,
+ reason: 'event is fired'));
+ e.querySelector('a').click();
+ });
+ test('onDelete events (DOM)', () async {
+ sub = e.onDelete.listen(expectAsync((EventDeleteEvent ev) {
+ expect(ev, isNotNull, reason: 'event is passed');
+ expect(ev.event, equals(event),
+ reason: 'exception is the same');
+ }, count: 1, reason: 'event is fired'));
+ e.querySelector('button').click();
+ });
+ test('onDelete events (code)', () async {
+ sub = e.onDelete.listen(expectAsync((EventDeleteEvent ev) {
+ expect(ev, isNotNull, reason: 'event is passed');
+ expect(ev.event, equals(event),
+ reason: 'exception is the same');
+ }, count: 1, reason: 'event is fired'));
+ e.delete();
+ });
+ });
+}
diff --git a/runtime/observatory/tests/observatory_ui/nav/notify_event/element_test.html b/runtime/observatory/tests/observatory_ui/nav/notify_event/element_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/nav/notify_event/element_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="dart.unittest" content="full-stack-traces">
+ <style>
+ .unittest-table { font-family:monospace; border:1px; }
+ .unittest-pass { background: #6b3;}
+ .unittest-fail { background: #d55;}
+ .unittest-error { background: #a11;}
+ </style>
+ <script src="/packages/web_components/webcomponents.js"></script>
+ <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+ <script type="text/javascript"
+ src="/root_dart/tools/testing/dart/test_controller.js"></script>
+ %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/observatory_ui/nav/notify_exception/connection_exception_test.dart b/runtime/observatory/tests/observatory_ui/nav/notify_exception/connection_exception_test.dart
new file mode 100644
index 0000000..e6b3bc2
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/nav/notify_exception/connection_exception_test.dart
@@ -0,0 +1,67 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+import 'dart:html';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/models.dart';
+import 'package:observatory/mocks.dart';
+import 'package:observatory/src/elements/nav/notify_exception.dart';
+
+main() {
+ NavNotifyExceptionElement.tag.ensureRegistration();
+
+ final ConnectionException exception =
+ new ConnectionExceptionMock(message: 'message');
+ test('instantiation', () {
+ final NavNotifyExceptionElement e =
+ new NavNotifyExceptionElement(exception);
+ expect(e, isNotNull, reason: 'element correctly created');
+ });
+ test('elements created after attachment', () async {
+ final NavNotifyExceptionElement e =
+ new NavNotifyExceptionElement(exception);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.children.length, isNonZero, reason: 'has elements');
+ e.remove();
+ await e.onRendered.first;
+ expect(e.children.length, isZero, reason: 'is empty');
+ });
+ group('events are fired', () {
+ NavNotifyExceptionElement e;
+ StreamSubscription sub;
+ setUp(() async {
+ e = new NavNotifyExceptionElement(exception);
+ document.body.append(e);
+ await e.onRendered.first;
+ });
+ tearDown(() {
+ sub.cancel();
+ e.remove();
+ });
+ test('navigation after connect', () async {
+ sub = window.onPopState.listen(expectAsync((_) {}, count: 1,
+ reason: 'event is fired'));
+ e.querySelector('a').click();
+ });
+ test('onDelete events (DOM)', () async {
+ sub = e.onDelete.listen(expectAsync((ExceptionDeleteEvent event) {
+ expect(event, isNotNull, reason: 'event is passed');
+ expect(event.exception, equals(exception),
+ reason: 'exception is the same');
+ expect(event.stacktrace, isNull);
+ }, count: 1, reason: 'event is fired'));
+ e.querySelector('button').click();
+ });
+ test('onDelete events (code)', () async {
+ sub = e.onDelete.listen(expectAsync((ExceptionDeleteEvent event) {
+ expect(event, isNotNull, reason: 'event is passed');
+ expect(event.exception, equals(exception),
+ reason: 'exception is the same');
+ expect(event.stacktrace, isNull);
+ }, count: 1, reason: 'event is fired'));
+ e.delete();
+ });
+ });
+}
diff --git a/runtime/observatory/tests/observatory_ui/nav/notify_exception/connection_exception_test.html b/runtime/observatory/tests/observatory_ui/nav/notify_exception/connection_exception_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/nav/notify_exception/connection_exception_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="dart.unittest" content="full-stack-traces">
+ <style>
+ .unittest-table { font-family:monospace; border:1px; }
+ .unittest-pass { background: #6b3;}
+ .unittest-fail { background: #d55;}
+ .unittest-error { background: #a11;}
+ </style>
+ <script src="/packages/web_components/webcomponents.js"></script>
+ <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+ <script type="text/javascript"
+ src="/root_dart/tools/testing/dart/test_controller.js"></script>
+ %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/observatory_ui/nav/notify_exception/exception_test.dart b/runtime/observatory/tests/observatory_ui/nav/notify_exception/exception_test.dart
new file mode 100644
index 0000000..be9fdc5
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/nav/notify_exception/exception_test.dart
@@ -0,0 +1,96 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+import 'dart:html';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/src/elements/nav/notify_exception.dart';
+
+main() {
+ NavNotifyExceptionElement.tag.ensureRegistration();
+
+ final StackTrace stacktrace = new StackTrace.fromString('stacktrace string');
+ group('normal exception', () {
+ final Exception exception = new Exception('exception message');
+ group('instantiation', () {
+ test('no stacktrace', () {
+ final NavNotifyExceptionElement e =
+ new NavNotifyExceptionElement(exception);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.exception, equals(exception));
+ expect(e.stacktrace, isNull);
+ });
+ test('with stacktrace', () {
+ final NavNotifyExceptionElement e =
+ new NavNotifyExceptionElement(exception, stacktrace: stacktrace);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.exception, equals(exception));
+ expect(e.stacktrace, equals(stacktrace));
+ });
+ });
+ group('elements', () {
+ test('created after attachment (no stacktrace)', () async {
+ final NavNotifyExceptionElement e =
+ new NavNotifyExceptionElement(exception);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.children.length, isNonZero, reason: 'has elements');
+ expect(e.innerHtml.contains(exception.toString()), isTrue);
+ expect(e.innerHtml.contains(stacktrace.toString()), isFalse);
+ e.remove();
+ await e.onRendered.first;
+ expect(e.children.length, isZero, reason: 'is empty');
+ });
+ test('created after attachment (with stacktrace)', () async {
+ final NavNotifyExceptionElement e =
+ new NavNotifyExceptionElement(exception, stacktrace: stacktrace);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.children.length, isNonZero, reason: 'has elements');
+ expect(e.innerHtml.contains(exception.toString()), isTrue);
+ expect(e.innerHtml.contains(stacktrace.toString()), isTrue);
+ e.remove();
+ await e.onRendered.first;
+ expect(e.children.length, isZero, reason: 'is empty');
+ });
+ });
+ group('events are fired', () {
+ NavNotifyExceptionElement e;
+ StreamSubscription sub;
+ setUp(() async {
+ e = new NavNotifyExceptionElement(exception, stacktrace: stacktrace);
+ document.body.append(e);
+ await e.onRendered.first;
+ });
+ tearDown(() {
+ sub.cancel();
+ e.remove();
+ });
+ test('navigation after connect', () async {
+ sub = window.onPopState.listen(expectAsync((_) {}, count: 1,
+ reason: 'event is fired'));
+ e.querySelector('a').click();
+ });
+ test('onDelete events (DOM)', () async {
+ sub = e.onDelete.listen(expectAsync((ExceptionDeleteEvent event) {
+ expect(event, isNotNull, reason: 'event is passed');
+ expect(event.exception, equals(exception),
+ reason: 'exception is the same');
+ expect(event.stacktrace, equals(stacktrace),
+ reason: 'stacktrace is the same');
+ }, count: 1, reason: 'event is fired'));
+ e.querySelector('button').click();
+ });
+ test('onDelete events (code)', () async {
+ sub = e.onDelete.listen(expectAsync((ExceptionDeleteEvent event) {
+ expect(event, isNotNull, reason: 'event is passed');
+ expect(event.exception, equals(exception),
+ reason: 'exception is the same');
+ expect(event.stacktrace, equals(stacktrace),
+ reason: 'stacktrace is the same');
+ }, count: 1, reason: 'event is fired'));
+ e.delete();
+ });
+ });
+ });
+}
diff --git a/runtime/observatory/tests/observatory_ui/nav/notify_exception/exception_test.html b/runtime/observatory/tests/observatory_ui/nav/notify_exception/exception_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/nav/notify_exception/exception_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="dart.unittest" content="full-stack-traces">
+ <style>
+ .unittest-table { font-family:monospace; border:1px; }
+ .unittest-pass { background: #6b3;}
+ .unittest-fail { background: #d55;}
+ .unittest-error { background: #a11;}
+ </style>
+ <script src="/packages/web_components/webcomponents.js"></script>
+ <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+ <script type="text/javascript"
+ src="/root_dart/tools/testing/dart/test_controller.js"></script>
+ %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/observatory_ui/nav/refresh/element_test.dart b/runtime/observatory/tests/observatory_ui/nav/refresh/element_test.dart
new file mode 100644
index 0000000..26c3ada
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/nav/refresh/element_test.dart
@@ -0,0 +1,122 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+import 'dart:html';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/src/elements/nav/refresh.dart';
+
+main() {
+ NavRefreshElement.tag.ensureRegistration();
+ group('instantiation', () {
+ test('no parameters', () {
+ final NavRefreshElement e = new NavRefreshElement();
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.label, isNotNull, reason: 'label is set to default');
+ expect(e.disabled, isFalse, reason: 'element correctly created');
+ });
+ test('label', () {
+ final label = 'custom-label';
+ final NavRefreshElement e = new NavRefreshElement(label: label);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.label, isNotNull, reason: 'label is set');
+ expect(e.label, equals(label), reason: 'label is set to value');
+ });
+ test('not disabled', () {
+ final NavRefreshElement e = new NavRefreshElement(disabled: false);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.disabled, isFalse, reason: 'element correctly created');
+ });
+ test('disabled', () {
+ final NavRefreshElement e = new NavRefreshElement(disabled: true);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.disabled, isTrue, reason: 'element correctly created');
+ });
+ });
+ group('elements', () {
+ test('created after attachment', () async {
+ final NavRefreshElement e = new NavRefreshElement();
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.children.length, isNonZero, reason: 'has elements');
+ e.remove();
+ await e.onRendered.first;
+ expect(e.children.length, isZero, reason: 'is empty');
+ });
+ test('contain custom label', () async {
+ final label = 'custom-label';
+ final NavRefreshElement e = new NavRefreshElement(label: label);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.innerHtml.contains(label), isTrue);
+ e.remove();
+ await e.onRendered.first;
+ });
+ test('react to label change', () async {
+ final label1 = 'custom-label-1';
+ final label2 = 'custom-label-2';
+ final NavRefreshElement e = new NavRefreshElement(label: label1);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.innerHtml.contains(label1), isTrue);
+ expect(e.innerHtml.contains(label2), isFalse);
+ e.label = label2;
+ await e.onRendered.first;
+ expect(e.innerHtml.contains(label2), isTrue);
+ expect(e.innerHtml.contains(label1), isFalse);
+ e.remove();
+ await e.onRendered.first;
+ });
+ test('react to disabled change', () async {
+ final NavRefreshElement e = new NavRefreshElement(disabled: false);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.disabled, isFalse);
+ e.disabled = true;
+ await e.onRendered.first;
+ expect(e.disabled, isTrue);
+ e.remove();
+ await e.onRendered.first;
+ });
+ });
+ group('event', () {
+ NavRefreshElement e;
+ StreamSubscription sub;
+ setUp(() async {
+ e = new NavRefreshElement();
+ document.body.append(e);
+ await e.onRendered.first;
+ });
+ tearDown(() async {
+ sub.cancel();
+ e.remove();
+ await e.onRendered.first;
+ });
+ test('fires', () async {
+ sub = e.onRefresh.listen(expectAsync((event) {
+ expect(event, isNotNull, reason: 'event passed');
+ expect(event is RefreshEvent, isTrue, reason: 'is the right event');
+ expect(event.element, equals(e), reason: 'is related to the element');
+ }, count: 1));
+ e.refresh();
+ });
+ test('fires on click', () async {
+ sub = e.onRefresh.listen(expectAsync((event) {
+ expect(event, isNotNull, reason: 'event passed');
+ expect(event is RefreshEvent, isTrue, reason: 'is the right event');
+ expect(event.element, equals(e), reason: 'is related to the element');
+ }, count: 1));
+ e.querySelector('button').click();
+ });
+ test('does not fire if disabled', () async {
+ e.disabled = true;
+ sub = e.onRefresh.listen(expectAsync((_) {}, count: 0));
+ e.refresh();
+ });
+ test('does not fires on click if disabled', () async {
+ e.disabled = true;
+ sub = e.onRefresh.listen(expectAsync((_) {}, count: 0));
+ e.querySelector('button').click();
+ });
+ });
+}
diff --git a/runtime/observatory/tests/observatory_ui/nav/refresh/element_test.html b/runtime/observatory/tests/observatory_ui/nav/refresh/element_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/nav/refresh/element_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="dart.unittest" content="full-stack-traces">
+ <style>
+ .unittest-table { font-family:monospace; border:1px; }
+ .unittest-pass { background: #6b3;}
+ .unittest-fail { background: #d55;}
+ .unittest-error { background: #a11;}
+ </style>
+ <script src="/packages/web_components/webcomponents.js"></script>
+ <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+ <script type="text/javascript"
+ src="/root_dart/tools/testing/dart/test_controller.js"></script>
+ %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/observatory_ui/nav/top-menu/element_test.dart b/runtime/observatory/tests/observatory_ui/nav/top-menu/element_test.dart
new file mode 100644
index 0000000..df9f88c
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/nav/top-menu/element_test.dart
@@ -0,0 +1,57 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+import 'dart:html';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/src/elements/nav/menu.dart';
+import 'package:observatory/src/elements/nav/top_menu.dart';
+
+main() {
+ NavTopMenuElement.tag.ensureRegistration();
+
+ final String tag = NavMenuElement.tag.name;
+
+ group('instantiation', () {
+ test('default', () {
+ final NavTopMenuElement e = new NavTopMenuElement();
+ expect(e, isNotNull, reason: 'element correctly created');
+ });
+ test('not last', () {
+ final NavTopMenuElement e = new NavTopMenuElement(last: false);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.last, isFalse, reason: 'element correctly created');
+ });
+ test('last', () {
+ final NavTopMenuElement e = new NavTopMenuElement(last: true);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.last, isTrue, reason: 'element correctly created');
+ });
+ });
+ group('elements', () {
+ test('created', () async {
+ final NavTopMenuElement e = new NavTopMenuElement();
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.shadowRoot.children.length, isNonZero, reason: 'has elements');
+ expect(e.shadowRoot.querySelector('content'), isNotNull,
+ reason: 'has content elements');
+ e.remove();
+ await e.onRendered.first;
+ expect(e.shadowRoot.children.length, isZero, reason: 'is empty');
+ });
+ test('react to last change', () async {
+ final NavTopMenuElement e = new NavTopMenuElement(last: false);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect((e.shadowRoot.querySelector(tag) as NavMenuElement).last, isFalse);
+ e.last = true;
+ await e.onRendered.first;
+ expect((e.shadowRoot.querySelector(tag) as NavMenuElement).last, isTrue);
+ e.last = false;
+ await e.onRendered.first;
+ expect((e.shadowRoot.querySelector(tag) as NavMenuElement).last, isFalse);
+ e.remove();
+ await e.onRendered.first;
+ });
+ });
+}
diff --git a/runtime/observatory/tests/observatory_ui/nav/top-menu/element_test.html b/runtime/observatory/tests/observatory_ui/nav/top-menu/element_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/nav/top-menu/element_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="dart.unittest" content="full-stack-traces">
+ <style>
+ .unittest-table { font-family:monospace; border:1px; }
+ .unittest-pass { background: #6b3;}
+ .unittest-fail { background: #d55;}
+ .unittest-error { background: #a11;}
+ </style>
+ <script src="/packages/web_components/webcomponents.js"></script>
+ <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+ <script type="text/javascript"
+ src="/root_dart/tools/testing/dart/test_controller.js"></script>
+ %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/observatory_ui/nav/vm_menu/element_test.dart b/runtime/observatory/tests/observatory_ui/nav/vm_menu/element_test.dart
new file mode 100644
index 0000000..b0539ff
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/nav/vm_menu/element_test.dart
@@ -0,0 +1,85 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+import 'dart:html';
+import 'dart:async';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/mocks.dart';
+import 'package:observatory/models.dart' as M;
+import 'package:observatory/src/elements/nav/menu.dart';
+import 'package:observatory/src/elements/nav/menu_item.dart';
+import 'package:observatory/src/elements/nav/vm_menu.dart';
+
+main(){
+ NavVMMenuElement.tag.ensureRegistration();
+
+ final mTag = NavMenuElement.tag.name;
+ final miTag = NavMenuItemElement.tag.name;
+
+ StreamController<M.VMUpdateEvent> updatesController;
+ final TargetMock target = new TargetMock(name: 'target-name');
+ final VMMock vm1 = const VMMock(name: 'vm-name-1',
+ isolates: const [const IsolateRefMock(id: 'i-id-1', name: 'i-name-1')]);
+ final VMMock vm2 = const VMMock(name: 'vm-name-2',
+ isolates: const [const IsolateRefMock(id: 'i-id-1', name: 'i-name-1'),
+ const IsolateRefMock(id: 'i-id-2', name: 'i-name-2')]);
+ setUp(() {
+ updatesController = new StreamController<M.VMUpdateEvent>.broadcast();
+ });
+ group('instantiation', () {
+ test('no target', () {
+ final NavVMMenuElement e = new NavVMMenuElement(vm1,
+ updatesController.stream);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.vm, equals(vm1));
+ expect(e.target, isNull);
+ });
+ test('target', () {
+ final NavVMMenuElement e = new NavVMMenuElement(vm1,
+ updatesController.stream, target: target);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.vm, equals(vm1));
+ expect(e.target, equals(target));
+ });
+ });
+ test('elements created after attachment', () async {
+ final NavVMMenuElement e = new NavVMMenuElement(vm1,
+ updatesController.stream);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.shadowRoot.children.length, isNonZero, reason: 'has elements');
+ e.remove();
+ await e.onRendered.first;
+ expect(e.shadowRoot.children.length, isZero, reason: 'is empty');
+ });
+ group('updates', () {
+ test('are correctly listen', () async {
+ final NavVMMenuElement e = new NavVMMenuElement(vm1,
+ updatesController.stream);
+ expect(updatesController.hasListener, isFalse);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(updatesController.hasListener, isTrue);
+ e.remove();
+ await e.onRendered.first;
+ expect(updatesController.hasListener, isFalse);
+ });
+ test('have effects', () async {
+ final NavVMMenuElement e = new NavVMMenuElement(vm1,
+ updatesController.stream);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect((e.shadowRoot.querySelector(mTag) as NavMenuElement).label,
+ equals(vm1.name));
+ expect(e.shadowRoot.querySelectorAll(miTag).length,
+ equals(vm1.isolates.length));
+ updatesController.add(new VMUpdateEventMock(vm: vm2));
+ await e.onRendered.first;
+ expect((e.shadowRoot.querySelector(mTag) as NavMenuElement).label,
+ equals(vm2.name));
+ expect(e.shadowRoot.querySelectorAll(miTag).length,
+ equals(vm2.isolates.length));
+ e.remove();
+ });
+ });
+}
diff --git a/runtime/observatory/tests/observatory_ui/nav/vm_menu/element_test.html b/runtime/observatory/tests/observatory_ui/nav/vm_menu/element_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/nav/vm_menu/element_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="dart.unittest" content="full-stack-traces">
+ <style>
+ .unittest-table { font-family:monospace; border:1px; }
+ .unittest-pass { background: #6b3;}
+ .unittest-fail { background: #d55;}
+ .unittest-error { background: #a11;}
+ </style>
+ <script src="/packages/web_components/webcomponents.js"></script>
+ <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+ <script type="text/javascript"
+ src="/root_dart/tools/testing/dart/test_controller.js"></script>
+ %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/observatory_ui/observatory_ui.status b/runtime/observatory/tests/observatory_ui/observatory_ui.status
index 4d08c8a..0675fff 100644
--- a/runtime/observatory/tests/observatory_ui/observatory_ui.status
+++ b/runtime/observatory/tests/observatory_ui/observatory_ui.status
@@ -2,5 +2,5 @@
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
-[ $browser == false ]
+[ $browser == false || $runtime == drt ]
*: SkipByDesign
diff --git a/runtime/observatory/tests/observatory_ui/view_footer/element_test.dart b/runtime/observatory/tests/observatory_ui/view_footer/element_test.dart
new file mode 100644
index 0000000..f3ab727
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/view_footer/element_test.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+import 'dart:html';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/src/elements/view_footer.dart';
+
+main() {
+ ViewFooterElement.tag.ensureRegistration();
+
+ test('instantiation', () {
+ final ViewFooterElement e = new ViewFooterElement();
+ expect(e, isNotNull, reason: 'element correctly created');
+ });
+ test('elements created', () async {
+ final ViewFooterElement e = new ViewFooterElement();
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.children.length, isNonZero, reason: 'has elements');
+ e.remove();
+ await e.onRendered.first;
+ expect(e.children.length, isZero, reason: 'is empty');
+ });
+}
diff --git a/runtime/observatory/tests/observatory_ui/view_footer/element_test.html b/runtime/observatory/tests/observatory_ui/view_footer/element_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/view_footer/element_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="dart.unittest" content="full-stack-traces">
+ <style>
+ .unittest-table { font-family:monospace; border:1px; }
+ .unittest-pass { background: #6b3;}
+ .unittest-fail { background: #d55;}
+ .unittest-error { background: #a11;}
+ </style>
+ <script src="/packages/web_components/webcomponents.js"></script>
+ <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+ <script type="text/javascript"
+ src="/root_dart/tools/testing/dart/test_controller.js"></script>
+ %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/observatory_ui/vm_connect_target/element_test.dart b/runtime/observatory/tests/observatory_ui/vm_connect_target/element_test.dart
new file mode 100644
index 0000000..a4340e8
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/vm_connect_target/element_test.dart
@@ -0,0 +1,87 @@
+// 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:html';
+import 'package:unittest/unittest.dart';
+import 'package:observatory/mocks.dart';
+import 'package:observatory/src/elements/vm_connect_target.dart';
+
+main() {
+ VMConnectTargetElement.tag.ensureRegistration();
+
+ TargetMock t;
+ setUp(() {
+ t = new TargetMock(name: "a network address");
+ });
+ group('instantiation', () {
+ test('no other parameters', () {
+ final VMConnectTargetElement e = new VMConnectTargetElement(t);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.target, t, reason: 'target not setted');
+ expect(e.current, isFalse, reason: 'default to not current');
+ });
+ test('isCurrent: false', () {
+ final VMConnectTargetElement e = new VMConnectTargetElement(t,
+ current:false);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.target, t, reason: 'target not setted');
+ expect(e.current, isFalse, reason: 'default to not current');
+ });
+ test('isCurrent: true', () {
+ final VMConnectTargetElement e = new VMConnectTargetElement(t,
+ current:true);
+ expect(e, isNotNull, reason: 'element correctly created');
+ expect(e.target, t, reason: 'target not setted');
+ expect(e.current, isTrue, reason: 'default to not current');
+ });
+ });
+ test('elements created after attachment', () async {
+ final VMConnectTargetElement e = new VMConnectTargetElement(t);
+ document.body.append(e);
+ await e.onRendered.first;
+ expect(e.children.length, isNonZero, reason: 'has elements');
+ e.remove();
+ await e.onRendered.first;
+ expect(e.children.length, isZero, reason: 'is empty');
+ });
+ group('events are fired', () {
+ VMConnectTargetElement e;
+ setUp(() async {
+ e = new VMConnectTargetElement(t);
+ document.body.append(e);
+ await e.onRendered.first;
+ });
+ tearDown(() async {
+ e.remove();
+ await e.onRendered.first;
+ });
+ test('onConnect events (DOM)', () async {
+ e.onConnect.listen(expectAsync((TargetEvent event) {
+ expect(event, isNotNull, reason: 'event is passed');
+ expect(event.target, t, reason: 'target is the same');
+ }, count: 1, reason: 'event is fired'));
+ e.querySelector('a').click();
+ });
+ test('onConnect events (code)', () async {
+ e.onConnect.listen(expectAsync((TargetEvent event) {
+ expect(event, isNotNull, reason: 'event is passed');
+ expect(event.target, t, reason: 'target is the same');
+ }, count: 1, reason: 'event is fired'));
+ e.connect();
+ });
+ test('onRemove events (DOM)', () async {
+ e.onDelete.listen(expectAsync((TargetEvent event) {
+ expect(event, isNotNull, reason: 'event is passed');
+ expect(event.target, t, reason: 'target is the same');
+ }, count: 1, reason: 'event is fired'));
+ e.querySelector('button').click();
+ });
+ test('onRemove events (code)', () async {
+ e.onDelete.listen(expectAsync((TargetEvent event) {
+ expect(event, isNotNull, reason: 'event is passed');
+ expect(event.target, t, reason: 'target is the same');
+ }, count: 1, reason: 'event is fired'));
+ e.delete();
+ });
+ });
+}
diff --git a/runtime/observatory/tests/observatory_ui/vm_connect_target/element_test.html b/runtime/observatory/tests/observatory_ui/vm_connect_target/element_test.html
new file mode 100644
index 0000000..f0e956d
--- /dev/null
+++ b/runtime/observatory/tests/observatory_ui/vm_connect_target/element_test.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="dart.unittest" content="full-stack-traces">
+ <style>
+ .unittest-table { font-family:monospace; border:1px; }
+ .unittest-pass { background: #6b3;}
+ .unittest-fail { background: #d55;}
+ .unittest-error { background: #a11;}
+ </style>
+ <script src="/packages/web_components/webcomponents.js"></script>
+ <script src="/packages/web_components/dart_support.js"></script>
+</head>
+<body>
+ <script type="text/javascript"
+ src="/root_dart/tools/testing/dart/test_controller.js"></script>
+ %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/runtime/observatory/tests/service/dev_fs_spawn_test.dart b/runtime/observatory/tests/service/dev_fs_spawn_test.dart
new file mode 100644
index 0000000..6537d54
--- /dev/null
+++ b/runtime/observatory/tests/service/dev_fs_spawn_test.dart
@@ -0,0 +1,219 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// VMOptions=--error_on_bad_type --error_on_bad_override
+
+import 'dart:async';
+import 'dart:convert';
+import 'package:observatory/service_io.dart';
+import 'package:unittest/unittest.dart';
+import 'service_test_common.dart';
+import 'test_helper.dart';
+
+var tests = [
+ (VM vm) async {
+ // Create a new fs.
+ var fsName = 'scratch';
+ var result = await vm.invokeRpcNoUpgrade('_createDevFS', {
+ 'fsName': fsName,
+ });
+ expect(result['type'], equals('FileSystem'));
+ expect(result['name'], equals('scratch'));
+ expect(result['uri'], new isInstanceOf<String>());
+ var fsUri = result['uri'];
+
+ // Spawn a script with a bad uri and make sure that the error is
+ // delivered asynchronously.
+ Completer completer = new Completer();
+ var sub;
+ sub = await vm.listenEventStream(
+ VM.kIsolateStream,
+ (ServiceEvent event) {
+ if (event.kind == ServiceEvent.kIsolateSpawn) {
+ expect(event.spawnToken, equals('someSpawnToken'));
+ expect(event.spawnError, startsWith(
+ 'IsolateSpawnException: Unable to spawn isolate: '));
+ expect(event.isolate, isNull);
+ completer.complete();
+ sub.cancel();
+ }
+ });
+
+ result = await vm.invokeRpcNoUpgrade('_spawnUri', {
+ 'token': 'someSpawnToken',
+ 'uri': '${fsUri}doesnotexist.dart',
+ });
+ expect(result['type'], equals('Success'));
+ await completer.future;
+
+ // Delete the fs.
+ result = await vm.invokeRpcNoUpgrade('_deleteDevFS', {
+ 'fsName': fsName,
+ });
+ expect(result['type'], equals('Success'));
+ },
+
+ (VM vm) async {
+ // Create a new fs.
+ var fsName = 'scratch';
+ var result = await vm.invokeRpcNoUpgrade('_createDevFS', {
+ 'fsName': fsName,
+ });
+ expect(result['type'], equals('FileSystem'));
+ expect(result['name'], equals('scratch'));
+ expect(result['uri'], new isInstanceOf<String>());
+ var fsUri = result['uri'];
+
+ var filePaths = [
+ 'devfs_file0.dart',
+ 'devfs_file1.dart',
+ 'devfs_file2.dart'
+ ];
+ var scripts = [
+'''
+import 'dart:developer';
+proofOfLife() => 'I live!';
+main() {
+ print('HELLO WORLD 1');
+ debugger();
+}
+''',
+'''
+import 'dart:developer';
+var globalArgs;
+proofOfLife() => 'I live, \${globalArgs}!';
+main(args) {
+ globalArgs = args;
+ print('HELLO WORLD 2');
+ debugger();
+}
+''',
+'''
+import 'dart:developer';
+var globalArgs;
+var globalMsg;
+proofOfLife() => 'I live, \${globalArgs}, \${globalMsg}!';
+main(args, msg) {
+ globalArgs = args;
+ globalMsg = msg;
+ print('HELLO WORLD 3');
+ debugger();
+}
+''',
+ ];
+
+ // Write three scripts to the fs.
+ for (int i = 0; i < 3; i++) {
+ var fileContents = BASE64.encode(UTF8.encode(scripts[i]));
+ result = await vm.invokeRpcNoUpgrade('_writeDevFSFile', {
+ 'fsName': fsName,
+ 'path': filePaths[i],
+ 'fileContents': fileContents
+ });
+ expect(result['type'], equals('Success'));
+ }
+
+ // Spawn the script with no arguments or message and make sure
+ // that we are notified.
+ Completer completer = new Completer();
+ var sub;
+ sub = await vm.listenEventStream(
+ VM.kIsolateStream,
+ (ServiceEvent event) {
+ if (event.kind == ServiceEvent.kIsolateSpawn) {
+ expect(event.spawnToken, equals('mySpawnToken0'));
+ expect(event.isolate, isNotNull);
+ expect(event.isolate.name, equals('devfs_file0.dart\$main'));
+ completer.complete(event.isolate);
+ sub.cancel();
+ }
+ });
+ result = await vm.invokeRpcNoUpgrade('_spawnUri', {
+ 'token': 'mySpawnToken0',
+ 'uri': '${fsUri}${filePaths[0]}',
+ });
+ expect(result['type'], equals('Success'));
+ var spawnedIsolate = await completer.future;
+
+ // Wait for the spawned isolate to hit a breakpoint.
+ await spawnedIsolate.load();
+ await hasStoppedAtBreakpoint(spawnedIsolate);
+
+ // Make sure that we are running code from the spawned isolate.
+ result = await spawnedIsolate.rootLibrary.evaluate('proofOfLife()');
+ expect(result.type, equals('Instance'));
+ expect(result.kind, equals('String'));
+ expect(result.valueAsString, equals('I live!'));
+
+ // Spawn the script with arguments.
+ completer = new Completer();
+ sub = await vm.listenEventStream(
+ VM.kIsolateStream,
+ (ServiceEvent event) {
+ if (event.kind == ServiceEvent.kIsolateSpawn) {
+ expect(event.spawnToken, equals('mySpawnToken1'));
+ expect(event.isolate, isNotNull);
+ expect(event.isolate.name, equals('devfs_file1.dart\$main'));
+ completer.complete(event.isolate);
+ sub.cancel();
+ }
+ });
+ result = await vm.invokeRpcNoUpgrade('_spawnUri', {
+ 'token': 'mySpawnToken1',
+ 'uri': '${fsUri}${filePaths[1]}',
+ 'args': ['one', 'two', 'three']
+ });
+ expect(result['type'], equals('Success'));
+ spawnedIsolate = await completer.future;
+
+ // Wait for the spawned isolate to hit a breakpoint.
+ await spawnedIsolate.load();
+ await hasStoppedAtBreakpoint(spawnedIsolate);
+
+ // Make sure that we are running code from the spawned isolate.
+ result = await spawnedIsolate.rootLibrary.evaluate('proofOfLife()');
+ expect(result.type, equals('Instance'));
+ expect(result.kind, equals('String'));
+ expect(result.valueAsString, equals('I live, [one, two, three]!'));
+
+ // Spawn the script with arguments and message
+ completer = new Completer();
+ sub = await vm.listenEventStream(
+ VM.kIsolateStream,
+ (ServiceEvent event) {
+ if (event.kind == ServiceEvent.kIsolateSpawn) {
+ expect(event.spawnToken, equals('mySpawnToken2'));
+ expect(event.isolate, isNotNull);
+ expect(event.isolate.name, equals('devfs_file2.dart\$main'));
+ completer.complete(event.isolate);
+ sub.cancel();
+ }
+ });
+ result = await vm.invokeRpcNoUpgrade('_spawnUri', {
+ 'token': 'mySpawnToken2',
+ 'uri': '${fsUri}${filePaths[2]}',
+ 'args': ['A', 'B', 'C'],
+ 'message': 'test'
+ });
+ expect(result['type'], equals('Success'));
+ spawnedIsolate = await completer.future;
+
+ // Wait for the spawned isolate to hit a breakpoint.
+ await spawnedIsolate.load();
+ await hasStoppedAtBreakpoint(spawnedIsolate);
+
+ // Make sure that we are running code from the spawned isolate.
+ result = await spawnedIsolate.rootLibrary.evaluate('proofOfLife()');
+ expect(result.type, equals('Instance'));
+ expect(result.kind, equals('String'));
+ expect(result.valueAsString, equals('I live, [A, B, C], test!'));
+
+ // Delete the fs.
+ result = await vm.invokeRpcNoUpgrade('_deleteDevFS', {
+ 'fsName': fsName,
+ });
+ expect(result['type'], equals('Success'));
+ },
+];
+
+main(args) async => runVMTests(args, tests);
diff --git a/runtime/observatory/tests/service/dev_fs_test.dart b/runtime/observatory/tests/service/dev_fs_test.dart
index 08e5a5e..5b2930d 100644
--- a/runtime/observatory/tests/service/dev_fs_test.dart
+++ b/runtime/observatory/tests/service/dev_fs_test.dart
@@ -58,7 +58,7 @@
(VM vm) async {
var fsId = 'banana';
- var filePath = '/foobar.dat';
+ var filePath = '/foo/bar.dat';
var fileContents = BASE64.encode(UTF8.encode('fileContents'));
var result;
diff --git a/runtime/observatory/tests/service/service.status b/runtime/observatory/tests/service/service.status
index b18b6ce..6318dfa 100644
--- a/runtime/observatory/tests/service/service.status
+++ b/runtime/observatory/tests/service/service.status
@@ -56,17 +56,5 @@
*: Skip
[ $hot_reload ]
-add_breakpoint_rpc_test: Pass, Timeout, Fail, Crash
-code_test: Fail, Crash
-debugger_location_test: Timeout, Fail, Crash
-debugging_inlined_finally_test: Pass, Timeout, Fail, Crash
-dominator_tree_test: Timeout, Crash
-eval_test: Timeout, Fail, Crash
-evaluate_in_frame_rpc_test: Timeout, Fail, Crash
-get_cpu_profile_timeline_rpc_test: Pass, Timeout, Crash
-get_heap_map_rpc_test: Pass, Timeout, Fail, Crash
-get_vm_timeline_rpc_test: Timeout, Fail, Crash
-graph_test: Pass, Timeout, Fail, Crash
-smart_next_test: Pass, Timeout, Fail, Crash
-step_over_await_test: Pass, Timeout, Fail, Crash
-vm_timeline_events_test: Timeout, Fail, Crash
+# Skip all service tests because random reloads interfere.
+*: SkipByDesign # The service tests should run without being reloaded.
diff --git a/runtime/observatory/tests/service/test_helper.dart b/runtime/observatory/tests/service/test_helper.dart
index 0e8b6e9..df140c5 100644
--- a/runtime/observatory/tests/service/test_helper.dart
+++ b/runtime/observatory/tests/service/test_helper.dart
@@ -102,10 +102,6 @@
assert(trace_service != null);
assert(trace_compiler != null);
- // TODO(turnidge): I have temporarily turned on service tracing for
- // all tests to help diagnose flaky tests.
- trace_service = true;
-
if (_shouldLaunchSkyShell()) {
return _spawnSkyProcess(pause_on_start,
pause_on_exit,
@@ -255,6 +251,67 @@
}
}
+// A tester runner that doesn't spawn a process but instead connects to
+// an already running flutter application running on a device. Assumes
+// port 8100. This is only useful for debugging.
+class _FlutterDeviceServiceTesterRunner {
+ void run({List<String> mainArgs,
+ List<VMTest> vmTests,
+ List<IsolateTest> isolateTests,
+ bool pause_on_start: false,
+ bool pause_on_exit: false,
+ bool trace_service: false,
+ bool trace_compiler: false,
+ bool verbose_vm: false,
+ bool pause_on_unhandled_exceptions: false}) {
+ var port = 8100;
+ serviceWebsocketAddress = 'ws://localhost:$port/ws';
+ serviceHttpAddress = 'http://localhost:$port';
+ var name = Platform.script.pathSegments.last;
+ runZoned(() async {
+ var vm =
+ new WebSocketVM(new WebSocketVMTarget(serviceWebsocketAddress));
+ print('Loading VM...');
+ await vm.load();
+ print('Done loading VM');
+
+ // Run vm tests.
+ if (vmTests != null) {
+ var testIndex = 1;
+ var totalTests = vmTests.length;
+ for (var test in vmTests) {
+ vm.verbose = verbose_vm;
+ print('Running $name [$testIndex/$totalTests]');
+ testIndex++;
+ await test(vm);
+ }
+ }
+
+ // Run isolate tests.
+ if (isolateTests != null) {
+ var isolate = await vm.isolates.first.load();
+ var testIndex = 1;
+ var totalTests = isolateTests.length;
+ for (var test in isolateTests) {
+ vm.verbose = verbose_vm;
+ print('Running $name [$testIndex/$totalTests]');
+ testIndex++;
+ await test(isolate);
+ }
+ }
+ }, onError: (e, st) {
+ if (!_isWebSocketDisconnect(e)) {
+ print('Unexpected exception in service tests: $e $st');
+ throw e;
+ }
+ });
+ }
+}
+
+void suppressWarning() {
+ new _FlutterDeviceServiceTesterRunner();
+}
+
class _ServiceTesterRunner {
void run({List<String> mainArgs,
List<VMTest> vmTests,
diff --git a/runtime/observatory/web/index.html b/runtime/observatory/web/index.html
index d318cf7..0659525 100644
--- a/runtime/observatory/web/index.html
+++ b/runtime/observatory/web/index.html
@@ -6,6 +6,7 @@
<link rel="import" href="packages/polymer/polymer.html">
<link rel="stylesheet" href="packages/observatory/src/elements/css/shared.css">
<link rel="import" href="packages/observatory/elements.html">
+ <script src="packages/js_util/dist/js_util.js"></script>
<script type="application/dart" src="main.dart"></script>
<script src="packages/browser/dart.js"></script>
</head>
diff --git a/runtime/observatory/web/main.dart b/runtime/observatory/web/main.dart
index 238bf97..41f3dc7 100644
--- a/runtime/observatory/web/main.dart
+++ b/runtime/observatory/web/main.dart
@@ -4,8 +4,9 @@
import 'package:logging/logging.dart';
import 'package:polymer/polymer.dart';
+import 'package:observatory/elements.dart';
-main() {
+main() async {
Logger.root.level = Level.INFO;
Logger.root.onRecord.listen((LogRecord rec) {
if (rec.level == Level.WARNING &&
@@ -17,13 +18,10 @@
}
print('${rec.level.name}: ${rec.time}: ${rec.message}');
});
+ await initElements();
Logger.root.info('Starting Observatory');
- initPolymer().then((zone) {
- Logger.root.info('Polymer initialized');
- // Code here is in the polymer Zone, which ensures that
- // @observable properties work correctly.
- Polymer.onReady.then((_) {
- Logger.root.info('Polymer elements have been upgraded');
- });
- });
+ await initPolymer();
+ Logger.root.info('Polymer initialized');
+ await Polymer.onReady;
+ Logger.root.info('Polymer elements have been upgraded');
}
diff --git a/runtime/platform/assert.cc b/runtime/platform/assert.cc
index c5b91e7..ff71e3f 100644
--- a/runtime/platform/assert.cc
+++ b/runtime/platform/assert.cc
@@ -34,9 +34,8 @@
arguments);
va_end(arguments);
- // Print the buffer on stderr.
- fprintf(stderr, "%s\n", buffer);
- fflush(stderr);
+ // Print the buffer on stderr and/or syslog.
+ OS::PrintErr("%s\n", buffer);
// In case of failed assertions, abort right away. Otherwise, wait
// until the program is exiting before producing a non-zero exit
diff --git a/runtime/platform/globals.h b/runtime/platform/globals.h
index 5e3b011..3a3ed26 100644
--- a/runtime/platform/globals.h
+++ b/runtime/platform/globals.h
@@ -113,6 +113,9 @@
// Windows, both 32- and 64-bit, regardless of the check for _WIN32.
#define TARGET_OS_WINDOWS 1
+#elif defined(__Fuchsia__)
+#define TARGET_OS_FUCHSIA
+
#elif !defined(TARGET_OS_FUCHSIA)
#error Automatic target os detection failed.
#endif
diff --git a/runtime/platform/utils_fuchsia.h b/runtime/platform/utils_fuchsia.h
index 7054225..0129bfe 100644
--- a/runtime/platform/utils_fuchsia.h
+++ b/runtime/platform/utils_fuchsia.h
@@ -10,14 +10,24 @@
namespace dart {
inline int Utils::CountLeadingZeros(uword x) {
- UNIMPLEMENTED();
- return 0;
+#if defined(ARCH_IS_32_BIT)
+ return __builtin_clzl(x);
+#elif defined(ARCH_IS_64_BIT)
+ return __builtin_clzll(x);
+#else
+#error Architecture is not 32-bit or 64-bit.
+#endif
}
inline int Utils::CountTrailingZeros(uword x) {
- UNIMPLEMENTED();
- return 0;
+#if defined(ARCH_IS_32_BIT)
+ return __builtin_ctzl(x);
+#elif defined(ARCH_IS_64_BIT)
+ return __builtin_ctzll(x);
+#else
+#error Architecture is not 32-bit or 64-bit.
+#endif
}
@@ -58,8 +68,8 @@
inline char* Utils::StrError(int err, char* buffer, size_t bufsize) {
- UNIMPLEMENTED();
- return NULL;
+ snprintf(buffer, bufsize, "errno = %d", err);
+ return buffer;
}
} // namespace dart
diff --git a/runtime/tests/vm/dart/double_materialize_test.dart b/runtime/tests/vm/dart/double_materialize_test.dart
new file mode 100644
index 0000000..2cab01c
--- /dev/null
+++ b/runtime/tests/vm/dart/double_materialize_test.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--optimization_counter_threshold=10 --no-use-osr --no-background-compilation
+
+import "package:expect/expect.dart";
+
+double f(double x, double five, dynamic y) {
+ double z = x + five;
+ var a = y + 5;
+ return z + a.toDouble();
+}
+
+void main() {
+ double x = 1.0;
+ for (int i = 0; i < 1000; i++) {
+ x = f(x, 5.0, i);
+ }
+ x = f(x, 5.0, 1.0);
+ Expect.equals(509512.0, x);
+}
+
diff --git a/runtime/tests/vm/dart/double_to_smi_test.dart b/runtime/tests/vm/dart/double_to_smi_test.dart
new file mode 100644
index 0000000..06d6139
--- /dev/null
+++ b/runtime/tests/vm/dart/double_to_smi_test.dart
@@ -0,0 +1,23 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// VMOptions=--optimization_counter_threshold=10 --no-use-osr --no-background-compilation
+
+import "package:expect/expect.dart";
+
+int convert(dynamic d) {
+ return d.toInt();
+}
+
+main() {
+ double x = -100.0;
+ int count = 0;
+ while (x < 100.0) {
+ count = count + convert(x);
+ x = x + 0.5;
+ }
+ Expect.equals(-100, count);
+ count = convert(42);
+ Expect.equals(42, count);
+}
diff --git a/runtime/tests/vm/dart/hello_fuchsia_test.dart b/runtime/tests/vm/dart/hello_fuchsia_test.dart
new file mode 100644
index 0000000..501ffe7
--- /dev/null
+++ b/runtime/tests/vm/dart/hello_fuchsia_test.dart
@@ -0,0 +1,7 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+main() {
+ print("Hello, Fuchsia!");
+}
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 1faa41c..7053458 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -163,9 +163,6 @@
cc/RegExp_OneByteString: Skip
cc/RegExp_TwoByteString: Skip
-# TODO(vegorov) Optimizing compiler is disabled for the SIMDBC
-cc/CompileFunctionOnHelperThread: Skip
-
# TODO(vegorov) Field guards are disabled for SIMDBC
cc/GuardFieldConstructor2Test: Skip
cc/GuardFieldConstructorTest: Skip
@@ -186,33 +183,6 @@
# This test is meaningless for DBC as allocation stubs are not used.
cc/RegenerateAllocStubs: Skip
-# TODO(vegorov) Enable when DBC supports optimizing compiler.
-cc/Debug_InspectStack_Optimized: Skip
-cc/Debug_InspectStackWithClosure_Optimized: Skip
-
-# Isolate reload code assumes that all static calls have ICData attached to
-# them. However this is not the case on DBC.
-cc/IsolateReload_LiveStack: Skip
-cc/IsolateReload_StaticValuePreserved: Skip
-cc/IsolateReload_TopLevelFieldAdded: Skip
-cc/IsolateReload_ConstructorChanged: Skip
-cc/IsolateReload_ImplicitConstructorChanged: Skip
-cc/IsolateReload_MixinChanged: Skip
-cc/IsolateReload_SuperClassChanged: Skip
-cc/IsolateReload_ComplexInheritanceChange: Skip
-cc/IsolateReload_LibraryImportAdded: Skip
-cc/IsolateReload_LibraryHide: Skip
-cc/IsolateReload_LibraryLookup: Skip
-cc/IsolateReload_LibraryShow: Skip
-cc/IsolateReload_LiveStack: Skip
-cc/IsolateReload_StaticValuePreserved: Skip
-cc/IsolateReload_TopLevelFieldAdded: Skip
-cc/IsolateReload_ConstructorChanged: Skip
-cc/IsolateReload_ImplicitConstructorChanged: Skip
-cc/IsolateReload_MixinChanged: Skip
-cc/IsolateReload_SuperClassChanged: Skip
-cc/IsolateReload_ComplexInheritanceChange: Skip
-cc/IsolateReload_LibraryImportAdded: Skip
-cc/IsolateReload_LibraryHide: Skip
-cc/IsolateReload_LibraryLookup: Skip
-cc/IsolateReload_LibraryShow: Skip
+[ $hot_reload ]
+dart/spawn_shutdown_test: Skip # We can shutdown an isolate before it reloads.
+dart/spawn_infinite_loop_test: Skip # We can shutdown an isolate before it reloads.
diff --git a/runtime/tools/create_resources.py b/runtime/tools/create_resources.py
old mode 100644
new mode 100755
index 27c9d78..1e97496
--- a/runtime/tools/create_resources.py
+++ b/runtime/tools/create_resources.py
@@ -1,3 +1,4 @@
+#!/usr/bin/env python
# Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
diff --git a/runtime/tools/gen_library_src_paths.py b/runtime/tools/gen_library_src_paths.py
old mode 100644
new mode 100755
diff --git a/runtime/vm/BUILD.gn b/runtime/vm/BUILD.gn
index f1c2da4..b22a9d5 100644
--- a/runtime/vm/BUILD.gn
+++ b/runtime/vm/BUILD.gn
@@ -3,15 +3,17 @@
# BSD-style license that can be found in the LICENSE file.
config("libdart_vm_config") {
- libs = [
- "dl",
- ]
+ # TODO(zra, jamesr): This check can go away after some problems with the
+ # fuchsia toolchain definition are fixed.
+ if (!defined(is_fuchsia) || !is_fuchsia) {
+ libs = [ "dl" ]
- if (!is_android) {
- libs += [ "pthread" ]
+ if (!is_android) {
+ libs += [ "pthread" ]
- if (is_linux) {
- libs += [ "rt" ]
+ if (is_linux) {
+ libs += [ "rt" ]
+ }
}
}
}
diff --git a/runtime/vm/aot_optimizer.cc b/runtime/vm/aot_optimizer.cc
index cdc4753..3d4b07f 100644
--- a/runtime/vm/aot_optimizer.cc
+++ b/runtime/vm/aot_optimizer.cc
@@ -1674,8 +1674,8 @@
bool AotOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
ASSERT(call->HasICData());
const ICData& ic_data = *call->ic_data();
- if ((ic_data.NumberOfUsedChecks() == 0) || !ic_data.HasOneTarget()) {
- // No type feedback collected or multiple targets found.
+ if (ic_data.NumberOfUsedChecks() != 1) {
+ // No type feedback collected or multiple receivers/targets found.
return false;
}
@@ -1690,14 +1690,13 @@
(recognized_kind == MethodRecognizer::kExternalOneByteStringCodeUnitAt) ||
(recognized_kind == MethodRecognizer::kExternalTwoByteStringCodeUnitAt) ||
(recognized_kind == MethodRecognizer::kGrowableArraySetData) ||
- (recognized_kind == MethodRecognizer::kGrowableArraySetLength)) {
- ASSERT(ic_data.NumberOfChecks() == 1);
+ (recognized_kind == MethodRecognizer::kGrowableArraySetLength) ||
+ (recognized_kind == MethodRecognizer::kSmi_bitAndFromSmi)) {
return FlowGraphInliner::TryReplaceInstanceCallWithInline(
flow_graph_, current_iterator(), call);
}
- if ((recognized_kind == MethodRecognizer::kStringBaseCharAt) &&
- (ic_data.NumberOfChecks() == 1)) {
+ if (recognized_kind == MethodRecognizer::kStringBaseCharAt) {
ASSERT((class_ids[0] == kOneByteStringCid) ||
(class_ids[0] == kTwoByteStringCid) ||
(class_ids[0] == kExternalOneByteStringCid) ||
@@ -1706,7 +1705,7 @@
flow_graph_, current_iterator(), call);
}
- if ((class_ids[0] == kOneByteStringCid) && (ic_data.NumberOfChecks() == 1)) {
+ if (class_ids[0] == kOneByteStringCid) {
if (recognized_kind == MethodRecognizer::kOneByteStringSetAt) {
// This is an internal method, no need to check argument types nor
// range.
@@ -1729,8 +1728,7 @@
}
if (CanUnboxDouble() &&
- (recognized_kind == MethodRecognizer::kIntegerToDouble) &&
- (ic_data.NumberOfChecks() == 1)) {
+ (recognized_kind == MethodRecognizer::kIntegerToDouble)) {
if (class_ids[0] == kSmiCid) {
AddReceiverCheck(call);
ReplaceCall(call,
@@ -1799,21 +1797,20 @@
}
}
- if (IsSupportedByteArrayViewCid(class_ids[0]) &&
- (ic_data.NumberOfChecks() == 1)) {
+ if (IsSupportedByteArrayViewCid(class_ids[0])) {
return FlowGraphInliner::TryReplaceInstanceCallWithInline(
flow_graph_, current_iterator(), call);
}
- if ((class_ids[0] == kFloat32x4Cid) && (ic_data.NumberOfChecks() == 1)) {
+ if (class_ids[0] == kFloat32x4Cid) {
return TryInlineFloat32x4Method(call, recognized_kind);
}
- if ((class_ids[0] == kInt32x4Cid) && (ic_data.NumberOfChecks() == 1)) {
+ if (class_ids[0] == kInt32x4Cid) {
return TryInlineInt32x4Method(call, recognized_kind);
}
- if ((class_ids[0] == kFloat64x2Cid) && (ic_data.NumberOfChecks() == 1)) {
+ if (class_ids[0] == kFloat64x2Cid) {
return TryInlineFloat64x2Method(call, recognized_kind);
}
@@ -2050,6 +2047,10 @@
return true; // May deoptimize since we have not identified all 'true' tests.
}
+// Tells whether the function of the call matches the core private name.
+static bool matches_core(InstanceCallInstr* call, const String& name) {
+ return call->function_name().raw() == Library::PrivateCoreLibName(name).raw();
+}
// TODO(srdjan): Use ICData to check if always true or false.
void AotOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) {
@@ -2060,26 +2061,27 @@
bool negate = false;
if (call->ArgumentCount() == 2) {
type_args = flow_graph()->constant_null();
- if (call->function_name().raw() ==
- Library::PrivateCoreLibName(Symbols::_instanceOfNum()).raw()) {
- type = Type::Number();
- } else if (call->function_name().raw() ==
- Library::PrivateCoreLibName(Symbols::_instanceOfInt()).raw()) {
- type = Type::IntType();
- } else if (call->function_name().raw() ==
- Library::PrivateCoreLibName(Symbols::_instanceOfSmi()).raw()) {
- type = Type::SmiType();
- } else if (call->function_name().raw() ==
- Library::PrivateCoreLibName(Symbols::_instanceOfDouble()).raw()) {
- type = Type::Double();
- } else if (call->function_name().raw() ==
- Library::PrivateCoreLibName(Symbols::_instanceOfString()).raw()) {
- type = Type::StringType();
+ if (matches_core(call, Symbols::_simpleInstanceOf())) {
+ type =
+ AbstractType::Cast(call->ArgumentAt(1)->AsConstant()->value()).raw();
+ negate = false; // Just to be sure.
} else {
- UNIMPLEMENTED();
+ if (matches_core(call, Symbols::_instanceOfNum())) {
+ type = Type::Number();
+ } else if (matches_core(call, Symbols::_instanceOfInt())) {
+ type = Type::IntType();
+ } else if (matches_core(call, Symbols::_instanceOfSmi())) {
+ type = Type::SmiType();
+ } else if (matches_core(call, Symbols::_instanceOfDouble())) {
+ type = Type::Double();
+ } else if (matches_core(call, Symbols::_instanceOfString())) {
+ type = Type::StringType();
+ } else {
+ UNIMPLEMENTED();
+ }
+ negate = Bool::Cast(call->ArgumentAt(1)->OriginalDefinition()
+ ->AsConstant()->value()).value();
}
- negate = Bool::Cast(call->ArgumentAt(1)->OriginalDefinition()
- ->AsConstant()->value()).value();
} else {
type_args = call->ArgumentAt(1);
type = AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value()).raw();
@@ -2746,4 +2748,26 @@
}
+void AotOptimizer::ReplaceArrayBoundChecks() {
+ for (BlockIterator block_it = flow_graph_->reverse_postorder_iterator();
+ !block_it.Done();
+ block_it.Advance()) {
+ ForwardInstructionIterator it(block_it.Current());
+ current_iterator_ = ⁢
+ for (; !it.Done(); it.Advance()) {
+ CheckArrayBoundInstr* check = it.Current()->AsCheckArrayBound();
+ if (check != NULL) {
+ GenericCheckBoundInstr* new_check = new(Z) GenericCheckBoundInstr(
+ new(Z) Value(check->length()->definition()),
+ new(Z) Value(check->index()->definition()),
+ check->deopt_id());
+ flow_graph_->InsertBefore(check, new_check,
+ check->env(), FlowGraph::kEffect);
+ current_iterator()->RemoveCurrentFromGraph();
+ }
+ }
+ }
+}
+
+
} // namespace dart
diff --git a/runtime/vm/aot_optimizer.h b/runtime/vm/aot_optimizer.h
index 1afdadd..6c4586e 100644
--- a/runtime/vm/aot_optimizer.h
+++ b/runtime/vm/aot_optimizer.h
@@ -46,6 +46,8 @@
// Merge instructions (only per basic-block).
void TryOptimizePatterns();
+ void ReplaceArrayBoundChecks();
+
virtual void VisitStaticCall(StaticCallInstr* instr);
virtual void VisitInstanceCall(InstanceCallInstr* instr);
virtual void VisitLoadCodeUnits(LoadCodeUnitsInstr* instr);
diff --git a/runtime/vm/assembler_arm.cc b/runtime/vm/assembler_arm.cc
index 2e39e22..db7881d 100644
--- a/runtime/vm/assembler_arm.cc
+++ b/runtime/vm/assembler_arm.cc
@@ -1921,47 +1921,6 @@
}
-void Assembler::ComputeRange(Register result,
- Register value,
- Register scratch,
- Label* not_mint) {
- const Register hi = TMP;
- const Register lo = scratch;
-
- Label done;
- mov(result, Operand(value, LSR, kBitsPerWord - 1));
- tst(value, Operand(kSmiTagMask));
- b(&done, EQ);
- CompareClassId(value, kMintCid, result);
- b(not_mint, NE);
- ldr(hi, FieldAddress(value, Mint::value_offset() + kWordSize));
- ldr(lo, FieldAddress(value, Mint::value_offset()));
- rsb(result, hi, Operand(ICData::kInt32RangeBit));
- cmp(hi, Operand(lo, ASR, kBitsPerWord - 1));
- b(&done, EQ);
- LoadImmediate(result, ICData::kUint32RangeBit); // Uint32
- tst(hi, Operand(hi));
- LoadImmediate(result, ICData::kInt64RangeBit, NE); // Int64
- Bind(&done);
-}
-
-
-void Assembler::UpdateRangeFeedback(Register value,
- intptr_t index,
- Register ic_data,
- Register scratch1,
- Register scratch2,
- Label* miss) {
- ASSERT(ICData::IsValidRangeFeedbackIndex(index));
- ComputeRange(scratch1, value, scratch2, miss);
- ldr(scratch2, FieldAddress(ic_data, ICData::state_bits_offset()));
- orr(scratch2,
- scratch2,
- Operand(scratch1, LSL, ICData::RangeFeedbackShift(index)));
- str(scratch2, FieldAddress(ic_data, ICData::state_bits_offset()));
-}
-
-
static bool CanEncodeBranchOffset(int32_t offset) {
ASSERT(Utils::IsAligned(offset, 4));
return Utils::IsInt(Utils::CountOneBits(kBranchOffsetMask), offset);
@@ -3278,6 +3237,18 @@
}
+#ifndef PRODUCT
+void Assembler::MaybeTraceAllocation(intptr_t cid,
+ Register temp_reg,
+ Label* trace) {
+ LoadAllocationStatsAddress(temp_reg, cid);
+ const uword state_offset = ClassHeapStats::state_offset();
+ ldr(temp_reg, Address(temp_reg, state_offset));
+ tst(temp_reg, Operand(ClassHeapStats::TraceAllocationMask()));
+ b(trace, NE);
+}
+
+
void Assembler::LoadAllocationStatsAddress(Register dest,
intptr_t cid) {
ASSERT(dest != kNoRegister);
@@ -3292,17 +3263,6 @@
}
-void Assembler::MaybeTraceAllocation(intptr_t cid,
- Register temp_reg,
- Label* trace) {
- LoadAllocationStatsAddress(temp_reg, cid);
- const uword state_offset = ClassHeapStats::state_offset();
- ldr(temp_reg, Address(temp_reg, state_offset));
- tst(temp_reg, Operand(ClassHeapStats::TraceAllocationMask()));
- b(trace, NE);
-}
-
-
void Assembler::IncrementAllocationStats(Register stats_addr_reg,
intptr_t cid,
Heap::Space space) {
@@ -3339,6 +3299,7 @@
add(TMP, TMP, Operand(size_reg));
str(TMP, size_address);
}
+#endif // !PRODUCT
void Assembler::TryAllocate(const Class& cls,
diff --git a/runtime/vm/assembler_arm.h b/runtime/vm/assembler_arm.h
index cac760b..184f28d 100644
--- a/runtime/vm/assembler_arm.h
+++ b/runtime/vm/assembler_arm.h
@@ -794,18 +794,6 @@
void LoadClassIdMayBeSmi(Register result, Register object);
void LoadTaggedClassIdMayBeSmi(Register result, Register object);
- void ComputeRange(Register result,
- Register value,
- Register scratch,
- Label* miss);
-
- void UpdateRangeFeedback(Register value,
- intptr_t idx,
- Register ic_data,
- Register scratch1,
- Register scratch2,
- Label* miss);
-
intptr_t FindImmediate(int32_t imm);
bool CanLoadFromObjectPool(const Object& object) const;
void LoadFromOffset(OperandSize type,
@@ -919,6 +907,11 @@
b(is_smi, CC);
}
+ void BranchIfNotSmi(Register reg, Label* label) {
+ tst(reg, Operand(kSmiTagMask));
+ b(label, NE);
+ }
+
void CheckCodePointer();
// Function frame setup and tear down.
diff --git a/runtime/vm/assembler_arm64.cc b/runtime/vm/assembler_arm64.cc
index 26c0b4a..54dcabb 100644
--- a/runtime/vm/assembler_arm64.cc
+++ b/runtime/vm/assembler_arm64.cc
@@ -1036,51 +1036,6 @@
}
-void Assembler::ComputeRange(Register result,
- Register value,
- Register scratch,
- Label* not_mint) {
- Label done, not_smi;
- tsti(value, Immediate(kSmiTagMask));
- b(¬_smi, NE);
-
- AsrImmediate(scratch, value, 32);
- 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);
- csel(result, result, TMP, LS);
- b(&done);
-
- Bind(¬_smi);
- CompareClassId(value, kMintCid);
- b(not_mint, NE);
-
- LoadImmediate(result, ICData::kInt64RangeBit);
- Bind(&done);
-}
-
-
-void Assembler::UpdateRangeFeedback(Register value,
- intptr_t index,
- Register ic_data,
- Register scratch1,
- Register scratch2,
- Label* miss) {
- ASSERT(ICData::IsValidRangeFeedbackIndex(index));
- ComputeRange(scratch1, value, scratch2, miss);
- ldr(scratch2, FieldAddress(ic_data, ICData::state_bits_offset()), kWord);
- orrw(scratch2,
- scratch2,
- Operand(scratch1, LSL, ICData::RangeFeedbackShift(index)));
- str(scratch2, FieldAddress(ic_data, ICData::state_bits_offset()), kWord);
-}
-
-
// Frame entry and exit.
void Assembler::ReserveAlignedFrameSpace(intptr_t frame_space) {
// Reserve space for arguments and align frame before entering
@@ -1288,6 +1243,23 @@
}
+#ifndef PRODUCT
+void Assembler::MaybeTraceAllocation(intptr_t cid,
+ Register temp_reg,
+ Label* trace) {
+ ASSERT(cid > 0);
+ intptr_t state_offset = ClassTable::StateOffsetFor(cid);
+ LoadIsolate(temp_reg);
+ intptr_t table_offset =
+ Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid);
+ ldr(temp_reg, Address(temp_reg, table_offset));
+ AddImmediate(temp_reg, temp_reg, state_offset);
+ ldr(temp_reg, Address(temp_reg, 0));
+ tsti(temp_reg, Immediate(ClassHeapStats::TraceAllocationMask()));
+ b(trace, NE);
+}
+
+
void Assembler::UpdateAllocationStats(intptr_t cid,
Heap::Space space) {
ASSERT(cid > 0);
@@ -1327,22 +1299,7 @@
add(TMP, TMP, Operand(size_reg));
str(TMP, Address(TMP2, size_field_offset));
}
-
-
-void Assembler::MaybeTraceAllocation(intptr_t cid,
- Register temp_reg,
- Label* trace) {
- ASSERT(cid > 0);
- intptr_t state_offset = ClassTable::StateOffsetFor(cid);
- LoadIsolate(temp_reg);
- intptr_t table_offset =
- Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid);
- ldr(temp_reg, Address(temp_reg, table_offset));
- AddImmediate(temp_reg, temp_reg, state_offset);
- ldr(temp_reg, Address(temp_reg, 0));
- tsti(temp_reg, Immediate(ClassHeapStats::TraceAllocationMask()));
- b(trace, NE);
-}
+#endif // !PRODUCT
void Assembler::TryAllocate(const Class& cls,
diff --git a/runtime/vm/assembler_arm64.h b/runtime/vm/assembler_arm64.h
index 8080ab8..c39e8e3 100644
--- a/runtime/vm/assembler_arm64.h
+++ b/runtime/vm/assembler_arm64.h
@@ -1219,6 +1219,11 @@
LslImmediate(dst, src, kSmiTagSize);
}
+ void BranchIfNotSmi(Register reg, Label* label) {
+ tsti(reg, Immediate(kSmiTagMask));
+ b(label, NE);
+ }
+
void Branch(const StubEntry& stub_entry,
Register pp,
Patchability patchable = kNotPatchable);
@@ -1337,18 +1342,6 @@
void LoadClassIdMayBeSmi(Register result, Register object);
void LoadTaggedClassIdMayBeSmi(Register result, Register object);
- void ComputeRange(Register result,
- Register value,
- Register scratch,
- Label* miss);
-
- void UpdateRangeFeedback(Register value,
- intptr_t idx,
- Register ic_data,
- Register scratch1,
- Register scratch2,
- Label* miss);
-
void SetupDartSP();
void RestoreCSP();
diff --git a/runtime/vm/assembler_arm64_test.cc b/runtime/vm/assembler_arm64_test.cc
index 7c7a620..329466a 100644
--- a/runtime/vm/assembler_arm64_test.cc
+++ b/runtime/vm/assembler_arm64_test.cc
@@ -3634,68 +3634,6 @@
__ ret();
}
-
-ASSEMBLER_TEST_GENERATE(ComputeRange, assembler) {
- __ SetupDartSP();
- EnterTestFrame(assembler);
- Label miss, done;
- __ ComputeRange(R0, R2, R3, &miss);
- __ b(&done);
-
- __ Bind(&miss);
- __ LoadImmediate(R0, -1);
-
- __ Bind(&done);
- LeaveTestFrame(assembler);
- __ RestoreCSP();
- __ ret();
-}
-
-
-ASSEMBLER_TEST_RUN(ComputeRange, test) {
-#define RANGE_OF(arg_type, v) \
- test->InvokeWithCodeAndThread<intptr_t, arg_type>(v)
-
- EXPECT_EQ(ICData::kInt32RangeBit, RANGE_OF(RawSmi*, Smi::New(0)));
- EXPECT_EQ(ICData::kInt32RangeBit, RANGE_OF(RawSmi*, Smi::New(1)));
- EXPECT_EQ(ICData::kInt32RangeBit, RANGE_OF(RawSmi*, Smi::New(kMaxInt32)));
- EXPECT_EQ(ICData::kInt32RangeBit | ICData::kSignedRangeBit,
- RANGE_OF(RawSmi*, Smi::New(-1)));
- EXPECT_EQ(ICData::kInt32RangeBit | ICData::kSignedRangeBit,
- RANGE_OF(RawSmi*, Smi::New(kMinInt32)));
-
- EXPECT_EQ(ICData::kUint32RangeBit,
- RANGE_OF(RawSmi*, Smi::New(static_cast<int64_t>(kMaxInt32) + 1)));
- EXPECT_EQ(ICData::kUint32RangeBit,
- RANGE_OF(RawSmi*, Smi::New(kMaxUint32)));
-
- // On 64-bit platforms we don't track the sign of the smis outside of
- // int32 range because it is not needed to distinguish kInt32Range from
- // kUint32Range.
- EXPECT_EQ(ICData::kSignedRangeBit,
- RANGE_OF(RawSmi*, Smi::New(static_cast<int64_t>(kMinInt32) - 1)));
- EXPECT_EQ(ICData::kSignedRangeBit,
- RANGE_OF(RawSmi*, Smi::New(static_cast<int64_t>(kMaxUint32) + 1)));
- EXPECT_EQ(ICData::kSignedRangeBit,
- RANGE_OF(RawSmi*, Smi::New(Smi::kMaxValue)));
- EXPECT_EQ(ICData::kSignedRangeBit, RANGE_OF(RawSmi*,
- Smi::New(Smi::kMinValue)));
-
- EXPECT_EQ(ICData::kInt64RangeBit,
- RANGE_OF(RawInteger*, Integer::New(Smi::kMaxValue + 1)));
- EXPECT_EQ(ICData::kInt64RangeBit,
- RANGE_OF(RawInteger*, Integer::New(Smi::kMinValue - 1)));
- EXPECT_EQ(ICData::kInt64RangeBit,
- RANGE_OF(RawInteger*, Integer::New(kMaxInt64)));
- EXPECT_EQ(ICData::kInt64RangeBit,
- RANGE_OF(RawInteger*, Integer::New(kMinInt64)));
-
- EXPECT_EQ(-1, RANGE_OF(RawBool*, Bool::True().raw()));
-
-#undef RANGE_OF
-}
-
-
} // namespace dart
#endif // defined(TARGET_ARCH_ARM64)
diff --git a/runtime/vm/assembler_arm_test.cc b/runtime/vm/assembler_arm_test.cc
index 1e6e6ef..7eca350 100644
--- a/runtime/vm/assembler_arm_test.cc
+++ b/runtime/vm/assembler_arm_test.cc
@@ -3961,58 +3961,6 @@
__ Ret();
}
-
-ASSEMBLER_TEST_GENERATE(ComputeRange, assembler) {
- Label miss, done;
- __ mov(R1, Operand(R0));
- __ ComputeRange(R0, R1, R2, &miss);
- __ b(&done);
-
- __ Bind(&miss);
- __ LoadImmediate(R0, -1);
-
- __ Bind(&done);
- __ Ret();
-}
-
-
-ASSEMBLER_TEST_RUN(ComputeRange, test) {
- typedef intptr_t (*ComputeRange)(intptr_t value) DART_UNUSED;
-
-#define RANGE_OF(v) \
- (EXECUTE_TEST_CODE_INTPTR_INTPTR( \
- ComputeRange, test->entry(), reinterpret_cast<intptr_t>(v)))
-
- EXPECT_EQ(0, RANGE_OF(Smi::New(0)));
- EXPECT_EQ(0, RANGE_OF(Smi::New(1)));
- EXPECT_EQ(ICData::kSignedRangeBit, RANGE_OF(Smi::New(-1)));
- EXPECT_EQ(0, RANGE_OF(Smi::New(Smi::kMaxValue)));
- EXPECT_EQ(ICData::kSignedRangeBit, RANGE_OF(Smi::New(Smi::kMinValue)));
-
- EXPECT_EQ(ICData::kInt32RangeBit, RANGE_OF(Integer::New(Smi::kMaxValue + 1)));
- EXPECT_EQ(ICData::kInt32RangeBit | ICData::kSignedRangeBit,
- RANGE_OF(Integer::New(Smi::kMinValue - 1)));
- EXPECT_EQ(ICData::kInt32RangeBit, RANGE_OF(Integer::New(kMaxInt32)));
- EXPECT_EQ(ICData::kInt32RangeBit | ICData::kSignedRangeBit,
- RANGE_OF(Integer::New(kMinInt32)));
-
- EXPECT_EQ(ICData::kUint32RangeBit,
- RANGE_OF(Integer::New(static_cast<int64_t>(kMaxInt32) + 1)));
- EXPECT_EQ(ICData::kUint32RangeBit,
- RANGE_OF(Integer::New(kMaxUint32)));
-
- EXPECT_EQ(ICData::kInt64RangeBit,
- RANGE_OF(Integer::New(static_cast<int64_t>(kMaxUint32) + 1)));
- EXPECT_EQ(ICData::kInt64RangeBit,
- RANGE_OF(Integer::New(static_cast<int64_t>(kMinInt32) - 1)));
- EXPECT_EQ(ICData::kInt64RangeBit, RANGE_OF(Integer::New(kMaxInt64)));
- EXPECT_EQ(ICData::kInt64RangeBit, RANGE_OF(Integer::New(kMinInt64)));
-
- EXPECT_EQ(-1, RANGE_OF(Bool::True().raw()));
-
-#undef RANGE_OF
-}
-
} // namespace dart
#endif // defined TARGET_ARCH_ARM
diff --git a/runtime/vm/assembler_dbc.h b/runtime/vm/assembler_dbc.h
index 590dd5c..7e23863 100644
--- a/runtime/vm/assembler_dbc.h
+++ b/runtime/vm/assembler_dbc.h
@@ -166,6 +166,8 @@
intptr_t AddConstant(const Object& obj);
+ void Nop(intptr_t d) { Nop(0, d); }
+
private:
AssemblerBuffer buffer_; // Contains position independent code.
ObjectPoolWrapper object_pool_wrapper_;
diff --git a/runtime/vm/assembler_dbc_test.cc b/runtime/vm/assembler_dbc_test.cc
index 180437e..254f638 100644
--- a/runtime/vm/assembler_dbc_test.cc
+++ b/runtime/vm/assembler_dbc_test.cc
@@ -28,6 +28,8 @@
(Bool::RawCast(ExecuteTest(code)) == Bool::True().raw())
#define EXECUTE_TEST_CODE_OBJECT(code) \
Object::Handle(ExecuteTest(code))
+#define EXECUTE_TEST_CODE_DOUBLE(code) \
+ bit_cast<double, RawObject*>(ExecuteTest(code))
#define __ assembler->
@@ -1650,6 +1652,91 @@
}
+// - TestCids rA, D
+//
+// The next D instructions must be Nops whose D field encodes a class id. If
+// the class id of FP[rA] matches, jump to PC + N + 1 if the matching Nop's
+// A != 0 or PC + N + 2 if the matching Nop's A = 0. If no match is found,
+// jump to PC + N.
+ASSEMBLER_TEST_GENERATE(TestCidsTrue, assembler) {
+ Label true_branch, no_match_branch;
+ __ Frame(2);
+ __ LoadConstant(0, Object::Handle(String::New("Hi", Heap::kOld)));
+ const intptr_t num_cases = 2;
+ __ TestCids(0, num_cases);
+ __ Nop(0, static_cast<uint16_t>(kSmiCid)); // Smi => false
+ __ Nop(1, static_cast<uint16_t>(kOneByteStringCid)); // String => true
+ __ Jump(&no_match_branch);
+ __ Jump(&true_branch);
+ __ LoadConstant(1, Smi::Handle(Smi::New(0))); // false branch
+ __ Return(1);
+ __ Bind(&true_branch);
+ __ LoadConstant(1, Smi::Handle(Smi::New(1)));
+ __ Return(1);
+ __ Bind(&no_match_branch);
+ __ LoadConstant(1, Smi::Handle(Smi::New(2)));
+ __ Return(1);
+}
+
+
+ASSEMBLER_TEST_RUN(TestCidsTrue, test) {
+ EXPECT_EQ(1, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(TestCidsFalse, assembler) {
+ Label true_branch, no_match_branch;
+ __ Frame(2);
+ __ LoadConstant(0, Object::Handle(Smi::New(42)));
+ const intptr_t num_cases = 2;
+ __ TestCids(0, num_cases);
+ __ Nop(0, static_cast<uint16_t>(kSmiCid)); // Smi => false
+ __ Nop(1, static_cast<uint16_t>(kOneByteStringCid)); // String => true
+ __ Jump(&no_match_branch);
+ __ Jump(&true_branch);
+ __ LoadConstant(1, Smi::Handle(Smi::New(0))); // false branch
+ __ Return(1);
+ __ Bind(&true_branch);
+ __ LoadConstant(1, Smi::Handle(Smi::New(1)));
+ __ Return(1);
+ __ Bind(&no_match_branch);
+ __ LoadConstant(1, Smi::Handle(Smi::New(2)));
+ __ Return(1);
+}
+
+
+ASSEMBLER_TEST_RUN(TestCidsFalse, test) {
+ EXPECT_EQ(0, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(TestCidsNoMatch, assembler) {
+ Label true_branch, no_match_branch;
+ __ Frame(2);
+ __ LoadConstant(0, Object::Handle(Array::New(1, Heap::kOld)));
+ const intptr_t num_cases = 2;
+ __ TestCids(0, num_cases);
+ __ Nop(0, static_cast<uint16_t>(kSmiCid)); // Smi => false
+ __ Nop(1, static_cast<uint16_t>(kOneByteStringCid)); // String => true
+ __ Jump(&no_match_branch);
+ __ Jump(&true_branch);
+ __ LoadConstant(1, Smi::Handle(Smi::New(0))); // false branch
+ __ Return(1);
+ __ Bind(&true_branch);
+ __ LoadConstant(1, Smi::Handle(Smi::New(1)));
+ __ Return(1);
+ __ Bind(&no_match_branch);
+ __ LoadConstant(1, Smi::Handle(Smi::New(2)));
+ __ Return(1);
+}
+
+
+ASSEMBLER_TEST_RUN(TestCidsNoMatch, test) {
+ EXPECT_EQ(2, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+
// - CheckSmi rA
//
// If FP[rA] is a Smi, then skip the next instruction.
@@ -1688,9 +1775,10 @@
// If the object at FP[rA]'s class id matches hthe class id in PP[D], then
// skip the following instruction.
ASSEMBLER_TEST_GENERATE(CheckClassIdSmiPass, assembler) {
- __ Frame(1);
+ __ Frame(2);
__ LoadConstant(0, Smi::Handle(Smi::New(42)));
- __ CheckClassId(0, kSmiCid);
+ __ LoadClassId(1, 0);
+ __ CheckClassId(1, kSmiCid);
__ LoadConstant(0, Smi::Handle(Smi::New(-1)));
__ Return(0);
}
@@ -1702,9 +1790,10 @@
ASSEMBLER_TEST_GENERATE(CheckClassIdNonSmiPass, assembler) {
- __ Frame(1);
+ __ Frame(2);
__ LoadConstant(0, Bool::True());
- __ CheckClassId(0, kBoolCid);
+ __ LoadClassId(1, 0);
+ __ CheckClassId(1, kBoolCid);
__ LoadConstant(0, Bool::False());
__ Return(0);
}
@@ -1716,9 +1805,10 @@
ASSEMBLER_TEST_GENERATE(CheckClassIdFail, assembler) {
- __ Frame(1);
+ __ Frame(2);
__ LoadConstant(0, Smi::Handle(Smi::New(-1)));
- __ CheckClassId(0, kBoolCid);
+ __ LoadClassId(1, 0);
+ __ CheckClassId(1, kBoolCid);
__ LoadConstant(0, Smi::Handle(Smi::New(42)));
__ Return(0);
}
@@ -1792,6 +1882,948 @@
EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
}
+// - If<Cond> rA, rD
+//
+// Cond is Le, Lt, Ge, Gt, unsigned variants ULe, ULt, UGe, UGt, and
+// unboxed double variants DEq, DNe, DLe, DLt, DGe, DGt.
+// Skips the next instruction unless FP[rA] <Cond> FP[rD]. Assumes that
+// FP[rA] and FP[rD] are Smis or unboxed doubles as inidcated by <Cond>.
+ASSEMBLER_TEST_GENERATE(IfLeTrue, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ LoadConstant(1, Smi::Handle(Smi::New(-5)));
+ __ LoadConstant(2, Smi::Handle(Smi::New(100)));
+ __ IfLe(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfLeTrue, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(IfLeFalse, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ LoadConstant(1, Smi::Handle(Smi::New(100)));
+ __ LoadConstant(2, Smi::Handle(Smi::New(-5)));
+ __ IfLe(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfLeFalse, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(IfLtTrue, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ LoadConstant(1, Smi::Handle(Smi::New(-5)));
+ __ LoadConstant(2, Smi::Handle(Smi::New(100)));
+ __ IfLt(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfLtTrue, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(IfLtFalse, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ LoadConstant(1, Smi::Handle(Smi::New(100)));
+ __ LoadConstant(2, Smi::Handle(Smi::New(-5)));
+ __ IfLt(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfLtFalse, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(IfGeTrue, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ LoadConstant(1, Smi::Handle(Smi::New(100)));
+ __ LoadConstant(2, Smi::Handle(Smi::New(-5)));
+ __ IfGe(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfGeTrue, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(IfGeFalse, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ LoadConstant(1, Smi::Handle(Smi::New(-5)));
+ __ LoadConstant(2, Smi::Handle(Smi::New(100)));
+ __ IfGe(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfGeFalse, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(IfGtTrue, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ LoadConstant(1, Smi::Handle(Smi::New(100)));
+ __ LoadConstant(2, Smi::Handle(Smi::New(-5)));
+ __ IfGt(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfGtTrue, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(IfGtFalse, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ LoadConstant(1, Smi::Handle(Smi::New(-5)));
+ __ LoadConstant(2, Smi::Handle(Smi::New(100)));
+ __ IfGt(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfGtFalse, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+#if defined(ARCH_IS_64_BIT)
+ASSEMBLER_TEST_GENERATE(IfDNeTrue, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ LoadConstant(1, Double::Handle(Double::New(-5.0, Heap::kOld)));
+ __ LoadConstant(2, Double::Handle(Double::New(100.0, Heap::kOld)));
+ __ UnboxDouble(1, 1);
+ __ UnboxDouble(2, 2);
+ __ IfDNe(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfDNeTrue, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(IfDNeFalse, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ LoadConstant(1, Double::Handle(Double::New(-5.0, Heap::kOld)));
+ __ LoadConstant(2, Double::Handle(Double::New(-5.0, Heap::kOld)));
+ __ UnboxDouble(1, 1);
+ __ UnboxDouble(2, 2);
+ __ IfDNe(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfDNeFalse, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(IfDNeNan, assembler) {
+ const double not_a_number = bit_cast<double, intptr_t>(0x7FF8000000000000LL);
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ LoadConstant(1, Double::Handle(Double::New(not_a_number, Heap::kOld)));
+ __ LoadConstant(2, Double::Handle(Double::New(not_a_number, Heap::kOld)));
+ __ UnboxDouble(1, 1);
+ __ UnboxDouble(2, 2);
+ __ IfDNe(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfDNeNan, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(IfDEqTrue, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ LoadConstant(1, Double::Handle(Double::New(-5.0, Heap::kOld)));
+ __ LoadConstant(2, Double::Handle(Double::New(-5.0, Heap::kOld)));
+ __ UnboxDouble(1, 1);
+ __ UnboxDouble(2, 2);
+ __ IfDEq(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfDEqTrue, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(IfDEqFalse, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ LoadConstant(1, Double::Handle(Double::New(-5.0, Heap::kOld)));
+ __ LoadConstant(2, Double::Handle(Double::New(100.0, Heap::kOld)));
+ __ UnboxDouble(1, 1);
+ __ UnboxDouble(2, 2);
+ __ IfDEq(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfDEqFalse, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(IfDEqNan, assembler) {
+ const double not_a_number = bit_cast<double, intptr_t>(0x7FF8000000000000LL);
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ LoadConstant(1, Double::Handle(Double::New(not_a_number, Heap::kOld)));
+ __ LoadConstant(2, Double::Handle(Double::New(not_a_number, Heap::kOld)));
+ __ UnboxDouble(1, 1);
+ __ UnboxDouble(2, 2);
+ __ IfDEq(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfDEqNan, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(IfDLeTrue, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ LoadConstant(1, Double::Handle(Double::New(-5.0, Heap::kOld)));
+ __ LoadConstant(2, Double::Handle(Double::New(100.0, Heap::kOld)));
+ __ UnboxDouble(1, 1);
+ __ UnboxDouble(2, 2);
+ __ IfDLe(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfDLeTrue, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(IfDLeFalse, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ LoadConstant(1, Double::Handle(Double::New(100.0, Heap::kOld)));
+ __ LoadConstant(2, Double::Handle(Double::New(-5.0, Heap::kOld)));
+ __ UnboxDouble(1, 1);
+ __ UnboxDouble(2, 2);
+ __ IfDLe(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfDLeFalse, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(IfDLeNan, assembler) {
+ const double not_a_number = bit_cast<double, intptr_t>(0x7FF8000000000000LL);
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ LoadConstant(1, Double::Handle(Double::New(not_a_number, Heap::kOld)));
+ __ LoadConstant(2, Double::Handle(Double::New(100.0, Heap::kOld)));
+ __ UnboxDouble(1, 1);
+ __ UnboxDouble(2, 2);
+ __ IfDLe(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfDLeNan, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(IfDLtTrue, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ LoadConstant(1, Double::Handle(Double::New(-5.0, Heap::kOld)));
+ __ LoadConstant(2, Double::Handle(Double::New(100.0, Heap::kOld)));
+ __ UnboxDouble(1, 1);
+ __ UnboxDouble(2, 2);
+ __ IfDLt(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfDLtTrue, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(IfDLtFalse, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ LoadConstant(1, Double::Handle(Double::New(100.0, Heap::kOld)));
+ __ LoadConstant(2, Double::Handle(Double::New(-5.0, Heap::kOld)));
+ __ UnboxDouble(1, 1);
+ __ UnboxDouble(2, 2);
+ __ IfDLt(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfDLtFalse, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(IfDLtNan, assembler) {
+ const double not_a_number = bit_cast<double, intptr_t>(0x7FF8000000000000LL);
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ LoadConstant(1, Double::Handle(Double::New(not_a_number, Heap::kOld)));
+ __ LoadConstant(2, Double::Handle(Double::New(100.0, Heap::kOld)));
+ __ UnboxDouble(1, 1);
+ __ UnboxDouble(2, 2);
+ __ IfDLt(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfDLtNan, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(IfDGeTrue, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ LoadConstant(1, Double::Handle(Double::New(100.0, Heap::kOld)));
+ __ LoadConstant(2, Double::Handle(Double::New(-5.0, Heap::kOld)));
+ __ UnboxDouble(1, 1);
+ __ UnboxDouble(2, 2);
+ __ IfDGe(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfDGeTrue, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(IfDGeFalse, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ LoadConstant(1, Double::Handle(Double::New(-5.0, Heap::kOld)));
+ __ LoadConstant(2, Double::Handle(Double::New(100.0, Heap::kOld)));
+ __ UnboxDouble(1, 1);
+ __ UnboxDouble(2, 2);
+ __ IfDGe(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfDGeFalse, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(IfDGeNan, assembler) {
+ const double not_a_number = bit_cast<double, intptr_t>(0x7FF8000000000000LL);
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ LoadConstant(1, Double::Handle(Double::New(not_a_number, Heap::kOld)));
+ __ LoadConstant(2, Double::Handle(Double::New(100.0, Heap::kOld)));
+ __ UnboxDouble(1, 1);
+ __ UnboxDouble(2, 2);
+ __ IfDGe(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfDGeNan, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(IfDGtTrue, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ LoadConstant(1, Double::Handle(Double::New(100.0, Heap::kOld)));
+ __ LoadConstant(2, Double::Handle(Double::New(-5.0, Heap::kOld)));
+ __ UnboxDouble(1, 1);
+ __ UnboxDouble(2, 2);
+ __ IfDGt(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfDGtTrue, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(IfDGtFalse, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ LoadConstant(1, Double::Handle(Double::New(-5.0, Heap::kOld)));
+ __ LoadConstant(2, Double::Handle(Double::New(100.0, Heap::kOld)));
+ __ UnboxDouble(1, 1);
+ __ UnboxDouble(2, 2);
+ __ IfDGt(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfDGtFalse, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(IfDGtNan, assembler) {
+ const double not_a_number = bit_cast<double, intptr_t>(0x7FF8000000000000LL);
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ LoadConstant(1, Double::Handle(Double::New(not_a_number, Heap::kOld)));
+ __ LoadConstant(2, Double::Handle(Double::New(100.0, Heap::kOld)));
+ __ UnboxDouble(1, 1);
+ __ UnboxDouble(2, 2);
+ __ IfDGt(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfDGtNan, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+#endif // defined(ARCH_IS_64_BIT)
+
+
+ASSEMBLER_TEST_GENERATE(IfULeTrue, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ LoadConstant(1, Smi::Handle(Smi::New(5)));
+ __ LoadConstant(2, Smi::Handle(Smi::New(100)));
+ __ IfULe(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfULeTrue, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(IfULeFalse, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ LoadConstant(1, Smi::Handle(Smi::New(100)));
+ __ LoadConstant(2, Smi::Handle(Smi::New(5)));
+ __ IfULe(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfULeFalse, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(IfULeNegTrue, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ LoadConstant(1, Smi::Handle(Smi::New(5)));
+ __ LoadConstant(2, Smi::Handle(Smi::New(-5)));
+ __ IfULe(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfULeNegTrue, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(IfULtTrue, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ LoadConstant(1, Smi::Handle(Smi::New(5)));
+ __ LoadConstant(2, Smi::Handle(Smi::New(100)));
+ __ IfULt(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfULtTrue, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(IfULtFalse, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ LoadConstant(1, Smi::Handle(Smi::New(100)));
+ __ LoadConstant(2, Smi::Handle(Smi::New(5)));
+ __ IfULt(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfULtFalse, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(IfUGeTrue, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ LoadConstant(1, Smi::Handle(Smi::New(100)));
+ __ LoadConstant(2, Smi::Handle(Smi::New(5)));
+ __ IfUGe(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfUGeTrue, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(IfUGeFalse, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ LoadConstant(1, Smi::Handle(Smi::New(5)));
+ __ LoadConstant(2, Smi::Handle(Smi::New(100)));
+ __ IfUGe(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfUGeFalse, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(IfUGtTrue, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ LoadConstant(1, Smi::Handle(Smi::New(100)));
+ __ LoadConstant(2, Smi::Handle(Smi::New(5)));
+ __ IfUGt(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfUGtTrue, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(IfUGtFalse, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ LoadConstant(1, Smi::Handle(Smi::New(5)));
+ __ LoadConstant(2, Smi::Handle(Smi::New(100)));
+ __ IfUGt(1, 2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(-1)));
+ __ Return(0);
+}
+
+
+ASSEMBLER_TEST_RUN(IfUGtFalse, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+// - Min, Max rA, rB, rC
+//
+// FP[rA] <- {min, max}(FP[rB], FP[rC]). Assumes that FP[rB], and FP[rC] are
+// Smis.
+ASSEMBLER_TEST_GENERATE(Min, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ LoadConstant(1, Smi::Handle(Smi::New(500)));
+ __ Min(2, 0, 1);
+ __ Return(2);
+}
+
+
+ASSEMBLER_TEST_RUN(Min, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(Max, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ LoadConstant(1, Smi::Handle(Smi::New(5)));
+ __ Max(2, 0, 1);
+ __ Return(2);
+}
+
+
+ASSEMBLER_TEST_RUN(Max, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+#if defined(ARCH_IS_64_BIT)
+// - UnboxDouble rA, rD
+//
+// Unbox the double in FP[rD] into FP[rA]. Assumes FP[rD] is a double.
+//
+// - CheckedUnboxDouble rA, rD
+//
+// Unboxes FP[rD] into FP[rA] and skips the following instruction unless
+// FP[rD] is not a double or a Smi. When FP[rD] is a Smi, converts it to a
+// double.
+ASSEMBLER_TEST_GENERATE(Unbox, assembler) {
+ __ Frame(2);
+ __ LoadConstant(0, Double::Handle(Double::New(42.0, Heap::kOld)));
+ __ UnboxDouble(1, 0);
+ __ Return(1);
+}
+
+
+ASSEMBLER_TEST_RUN(Unbox, test) {
+ EXPECT_EQ(42.0, EXECUTE_TEST_CODE_DOUBLE(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(CheckedUnboxDouble, assembler) {
+ __ Frame(2);
+ __ LoadConstant(0, Double::Handle(Double::New(42.0, Heap::kOld)));
+ __ CheckedUnboxDouble(1, 0);
+ __ LoadConstant(1, Smi::Handle(Smi::New(0)));
+ __ Return(1);
+}
+
+
+ASSEMBLER_TEST_RUN(CheckedUnboxDouble, test) {
+ EXPECT_EQ(42.0, EXECUTE_TEST_CODE_DOUBLE(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(CheckedUnboxSmi, assembler) {
+ __ Frame(2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ CheckedUnboxDouble(1, 0);
+ __ LoadConstant(1, Smi::Handle(Smi::New(0)));
+ __ Return(1);
+}
+
+
+ASSEMBLER_TEST_RUN(CheckedUnboxSmi, test) {
+ EXPECT_EQ(42.0, EXECUTE_TEST_CODE_DOUBLE(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(CheckedUnboxFail, assembler) {
+ __ Frame(2);
+ __ LoadConstant(0, Bool::True());
+ __ LoadConstant(1, Smi::Handle(Smi::New(-1)));
+ __ CheckedUnboxDouble(1, 0);
+ __ LoadConstant(1, Smi::Handle(Smi::New(42)));
+ __ Return(1);
+}
+
+
+ASSEMBLER_TEST_RUN(CheckedUnboxFail, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+// - DAdd, DSub, DMul, DDiv rA, rB, rC
+//
+// Arithmetic operaions on unboxed doubles. FP[rA] <- FP[rB] op FP[rC].
+ASSEMBLER_TEST_GENERATE(DAdd, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Double::Handle(Double::New(41.0, Heap::kOld)));
+ __ LoadConstant(1, Double::Handle(Double::New(1.0, Heap::kOld)));
+ __ UnboxDouble(0, 0);
+ __ UnboxDouble(1, 1);
+ __ DAdd(2, 1, 0);
+ __ Return(2);
+}
+
+
+ASSEMBLER_TEST_RUN(DAdd, test) {
+ EXPECT_EQ(42.0, EXECUTE_TEST_CODE_DOUBLE(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(DSub, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Double::Handle(Double::New(1.0, Heap::kOld)));
+ __ LoadConstant(1, Double::Handle(Double::New(43.0, Heap::kOld)));
+ __ UnboxDouble(0, 0);
+ __ UnboxDouble(1, 1);
+ __ DSub(2, 1, 0);
+ __ Return(2);
+}
+
+
+ASSEMBLER_TEST_RUN(DSub, test) {
+ EXPECT_EQ(42.0, EXECUTE_TEST_CODE_DOUBLE(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(DMul, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Double::Handle(Double::New(6.0, Heap::kOld)));
+ __ LoadConstant(1, Double::Handle(Double::New(7.0, Heap::kOld)));
+ __ UnboxDouble(0, 0);
+ __ UnboxDouble(1, 1);
+ __ DMul(2, 1, 0);
+ __ Return(2);
+}
+
+
+ASSEMBLER_TEST_RUN(DMul, test) {
+ EXPECT_EQ(42.0, EXECUTE_TEST_CODE_DOUBLE(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(DDiv, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Double::Handle(Double::New(2.0, Heap::kOld)));
+ __ LoadConstant(1, Double::Handle(Double::New(84.0, Heap::kOld)));
+ __ UnboxDouble(0, 0);
+ __ UnboxDouble(1, 1);
+ __ DDiv(2, 1, 0);
+ __ Return(2);
+}
+
+
+ASSEMBLER_TEST_RUN(DDiv, test) {
+ EXPECT_EQ(42.0, EXECUTE_TEST_CODE_DOUBLE(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(DNeg, assembler) {
+ __ Frame(2);
+ __ LoadConstant(0, Double::Handle(Double::New(-42.0, Heap::kOld)));
+ __ UnboxDouble(0, 0);
+ __ DNeg(1, 0);
+ __ Return(1);
+}
+
+
+ASSEMBLER_TEST_RUN(DNeg, test) {
+ EXPECT_EQ(42.0, EXECUTE_TEST_CODE_DOUBLE(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(DSqrt, assembler) {
+ __ Frame(2);
+ __ LoadConstant(0, Double::Handle(Double::New(36.0, Heap::kOld)));
+ __ UnboxDouble(0, 0);
+ __ DSqrt(1, 0);
+ __ Return(1);
+}
+
+
+ASSEMBLER_TEST_RUN(DSqrt, test) {
+ EXPECT_EQ(6.0, EXECUTE_TEST_CODE_DOUBLE(test->code()));
+}
+
+
+// - SmiToDouble rA, rD
+//
+// Convert the Smi in FP[rD] to an unboxed double in FP[rA].
+//
+// - DoubleToSmi rA, rD
+//
+// If the unboxed double in FP[rD] can be converted to a Smi in FP[rA], then
+// this instruction does so, and skips the following instruction. Otherwise,
+// the following instruction is not skipped.
+ASSEMBLER_TEST_GENERATE(SmiToDouble, assembler) {
+ __ Frame(2);
+ __ LoadConstant(0, Smi::Handle(Smi::New(42)));
+ __ SmiToDouble(1, 0);
+ __ Return(1);
+}
+
+
+ASSEMBLER_TEST_RUN(SmiToDouble, test) {
+ EXPECT_EQ(42.0, EXECUTE_TEST_CODE_DOUBLE(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(DoubleToSmi, assembler) {
+ __ Frame(2);
+ __ LoadConstant(0, Double::Handle(Double::New(42.0, Heap::kOld)));
+ __ LoadConstant(1, Smi::Handle(Smi::New(-1)));
+ __ UnboxDouble(0, 0);
+ __ DoubleToSmi(1, 0);
+ __ LoadConstant(1, Smi::Handle(Smi::New(-1)));
+ __ Return(1);
+}
+
+
+ASSEMBLER_TEST_RUN(DoubleToSmi, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(DoubleToSmiNearMax, assembler) {
+ const double m = static_cast<double>(Smi::kMaxValue - 1000);
+ __ Frame(2);
+ __ LoadConstant(0, Double::Handle(Double::New(m, Heap::kOld)));
+ __ LoadConstant(1, Smi::Handle(Smi::New(42)));
+ __ UnboxDouble(0, 0);
+ __ DoubleToSmi(0, 0);
+ __ LoadConstant(1, Smi::Handle(Smi::New(-1)));
+ __ Return(1);
+}
+
+
+ASSEMBLER_TEST_RUN(DoubleToSmiNearMax, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(DoubleToSmiNearMin, assembler) {
+ const double m = static_cast<double>(Smi::kMinValue);
+ __ Frame(2);
+ __ LoadConstant(0, Double::Handle(Double::New(m, Heap::kOld)));
+ __ LoadConstant(1, Smi::Handle(Smi::New(42)));
+ __ UnboxDouble(0, 0);
+ __ DoubleToSmi(0, 0);
+ __ LoadConstant(1, Smi::Handle(Smi::New(-1)));
+ __ Return(1);
+}
+
+
+ASSEMBLER_TEST_RUN(DoubleToSmiNearMin, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(DoubleToSmiFailPos, assembler) {
+ const double pos_overflow = static_cast<double>(Smi::kMaxValue + 1);
+ __ Frame(2);
+ __ LoadConstant(0, Double::Handle(Double::New(pos_overflow, Heap::kOld)));
+ __ LoadConstant(1, Smi::Handle(Smi::New(-1)));
+ __ UnboxDouble(0, 0);
+ __ DoubleToSmi(1, 0);
+ __ LoadConstant(1, Smi::Handle(Smi::New(42)));
+ __ Return(1);
+}
+
+
+ASSEMBLER_TEST_RUN(DoubleToSmiFailPos, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(DoubleToSmiFailNeg, assembler) {
+ const double neg_overflow = static_cast<double>(Smi::kMinValue - 1000);
+ __ Frame(2);
+ __ LoadConstant(0, Double::Handle(Double::New(neg_overflow, Heap::kOld)));
+ __ LoadConstant(1, Smi::Handle(Smi::New(-1)));
+ __ UnboxDouble(0, 0);
+ __ DoubleToSmi(1, 0);
+ __ LoadConstant(1, Smi::Handle(Smi::New(42)));
+ __ Return(1);
+}
+
+
+ASSEMBLER_TEST_RUN(DoubleToSmiFailNeg, test) {
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INTPTR(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(DMin, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Double::Handle(Double::New(42.0, Heap::kOld)));
+ __ LoadConstant(1, Double::Handle(Double::New(500.0, Heap::kOld)));
+ __ UnboxDouble(0, 0);
+ __ UnboxDouble(1, 1);
+ __ DMin(2, 0, 1);
+ __ Return(2);
+}
+
+
+ASSEMBLER_TEST_RUN(DMin, test) {
+ EXPECT_EQ(42.0, EXECUTE_TEST_CODE_DOUBLE(test->code()));
+}
+
+
+ASSEMBLER_TEST_GENERATE(DMax, assembler) {
+ __ Frame(3);
+ __ LoadConstant(0, Double::Handle(Double::New(42.0, Heap::kOld)));
+ __ LoadConstant(1, Double::Handle(Double::New(5.0, Heap::kOld)));
+ __ UnboxDouble(0, 0);
+ __ UnboxDouble(1, 1);
+ __ DMax(2, 0, 1);
+ __ Return(2);
+}
+
+
+ASSEMBLER_TEST_RUN(DMax, test) {
+ EXPECT_EQ(42.0, EXECUTE_TEST_CODE_DOUBLE(test->code()));
+}
+
+#endif // defined(ARCH_IS_64_BIT)
+
} // namespace dart
#endif // defined(TARGET_ARCH_DBC)
diff --git a/runtime/vm/assembler_ia32.cc b/runtime/vm/assembler_ia32.cc
index 1bc37d8..bb57905 100644
--- a/runtime/vm/assembler_ia32.cc
+++ b/runtime/vm/assembler_ia32.cc
@@ -2569,6 +2569,7 @@
}
+#ifndef PRODUCT
void Assembler::MaybeTraceAllocation(intptr_t cid,
Register temp_reg,
Label* trace,
@@ -2626,6 +2627,7 @@
intptr_t size_offset = ClassTable::SizeOffsetFor(cid, space == Heap::kNew);
addl(Address(temp_reg, size_offset), Immediate(size_in_bytes));
}
+#endif // !PRODUCT
void Assembler::TryAllocate(const Class& cls,
@@ -2939,47 +2941,6 @@
}
-void Assembler::ComputeRange(Register result,
- Register value,
- Register lo_temp,
- Register hi_temp,
- Label* not_mint) {
- Label done;
- movl(result, value);
- shrl(result, Immediate(kBitsPerWord - 1)); // Sign bit.
- testl(value, Immediate(kSmiTagMask));
- j(ZERO, &done, Assembler::kNearJump);
- CompareClassId(value, kMintCid, result);
- j(NOT_EQUAL, not_mint);
- movl(lo_temp, FieldAddress(value, Mint::value_offset()));
- movl(hi_temp, FieldAddress(value, Mint::value_offset() + kWordSize));
- movl(result, Immediate(ICData::kInt32RangeBit));
- subl(result, hi_temp); // 10 (positive int32), 11 (negative int32)
- sarl(lo_temp, Immediate(kBitsPerWord - 1));
- cmpl(lo_temp, hi_temp);
- j(EQUAL, &done, Assembler::kNearJump);
- movl(result, Immediate(ICData::kUint32RangeBit)); // Uint32
- cmpl(hi_temp, Immediate(0));
- j(EQUAL, &done, Assembler::kNearJump);
- movl(result, Immediate(ICData::kInt64RangeBit)); // Int64
- Bind(&done);
-}
-
-
-void Assembler::UpdateRangeFeedback(Register value,
- intptr_t index,
- Register ic_data,
- Register scratch1,
- Register scratch2,
- Register scratch3,
- Label* miss) {
- ASSERT(ICData::IsValidRangeFeedbackIndex(index));
- ComputeRange(scratch1, value, scratch2, scratch3, miss);
- shll(scratch1, Immediate(ICData::RangeFeedbackShift(index)));
- orl(FieldAddress(ic_data, ICData::state_bits_offset()), scratch1);
-}
-
-
Address Assembler::ElementAddressForIntIndex(bool is_external,
intptr_t cid,
intptr_t index_scale,
diff --git a/runtime/vm/assembler_ia32.h b/runtime/vm/assembler_ia32.h
index 77f77a6..df3d6ff 100644
--- a/runtime/vm/assembler_ia32.h
+++ b/runtime/vm/assembler_ia32.h
@@ -740,20 +740,6 @@
Register scratch,
Label* is_smi);
- void ComputeRange(Register result,
- Register value,
- Register lo_temp,
- Register hi_temp,
- Label* miss);
-
- void UpdateRangeFeedback(Register value,
- intptr_t index,
- Register ic_data,
- Register scratch1,
- Register scratch2,
- Register scratch3,
- Label* miss);
-
static Address ElementAddressForIntIndex(bool is_external,
intptr_t cid,
intptr_t index_scale,
@@ -781,7 +767,11 @@
sarl(reg, Immediate(kSmiTagSize));
}
- intptr_t PreferredLoopAlignment() { return 16; }
+ void BranchIfNotSmi(Register reg, Label* label) {
+ testl(reg, Immediate(kSmiTagMask));
+ j(NOT_ZERO, label);
+ }
+
void Align(intptr_t alignment, intptr_t offset);
void Bind(Label* label);
void Jump(Label* label) { jmp(label); }
diff --git a/runtime/vm/assembler_ia32_test.cc b/runtime/vm/assembler_ia32_test.cc
index 2ce9da2..116cc9e 100644
--- a/runtime/vm/assembler_ia32_test.cc
+++ b/runtime/vm/assembler_ia32_test.cc
@@ -3425,58 +3425,6 @@
EXPECT_EQ(1, reinterpret_cast<BitTest>(test->entry())());
}
-
-ASSEMBLER_TEST_GENERATE(ComputeRange, assembler) {
- Label miss, done;
- __ movl(ECX, Address(ESP, 1 * kWordSize));
-
- __ pushl(ESI);
- __ pushl(EDI);
- __ ComputeRange(EAX, ECX, ESI, EDI, &miss);
- __ jmp(&done);
-
- __ Bind(&miss);
- __ movl(EAX, Immediate(-1));
-
- __ Bind(&done);
- __ popl(EDI);
- __ popl(ESI);
- __ ret();
-}
-
-
-ASSEMBLER_TEST_RUN(ComputeRange, test) {
- typedef intptr_t (*ComputeRange)(RawObject* value);
- ComputeRange range_of = reinterpret_cast<ComputeRange>(test->entry());
-
- EXPECT_EQ(0, range_of(Smi::New(0)));
- EXPECT_EQ(0, range_of(Smi::New(1)));
- EXPECT_EQ(ICData::kSignedRangeBit, range_of(Smi::New(-1)));
- EXPECT_EQ(0, range_of(Smi::New(Smi::kMaxValue)));
- EXPECT_EQ(ICData::kSignedRangeBit, range_of(Smi::New(Smi::kMinValue)));
-
- EXPECT_EQ(ICData::kInt32RangeBit, range_of(Integer::New(Smi::kMaxValue + 1)));
- EXPECT_EQ(ICData::kInt32RangeBit | ICData::kSignedRangeBit,
- range_of(Integer::New(Smi::kMinValue - 1)));
- EXPECT_EQ(ICData::kInt32RangeBit, range_of(Integer::New(kMaxInt32)));
- EXPECT_EQ(ICData::kInt32RangeBit | ICData::kSignedRangeBit,
- range_of(Integer::New(kMinInt32)));
-
- EXPECT_EQ(ICData::kUint32RangeBit,
- range_of(Integer::New(static_cast<int64_t>(kMaxInt32) + 1)));
- EXPECT_EQ(ICData::kUint32RangeBit, range_of(Integer::New(kMaxUint32)));
-
- EXPECT_EQ(ICData::kInt64RangeBit,
- range_of(Integer::New(static_cast<int64_t>(kMaxUint32) + 1)));
- EXPECT_EQ(ICData::kInt64RangeBit,
- range_of(Integer::New(static_cast<int64_t>(kMinInt32) - 1)));
- EXPECT_EQ(ICData::kInt64RangeBit, range_of(Integer::New(kMaxInt64)));
- EXPECT_EQ(ICData::kInt64RangeBit, range_of(Integer::New(kMinInt64)));
-
- EXPECT_EQ(-1, range_of(Bool::True().raw()));
-}
-
-
} // namespace dart
#endif // defined TARGET_ARCH_IA32
diff --git a/runtime/vm/assembler_mips.cc b/runtime/vm/assembler_mips.cc
index ffd927d..954cea6 100644
--- a/runtime/vm/assembler_mips.cc
+++ b/runtime/vm/assembler_mips.cc
@@ -826,49 +826,6 @@
}
-void Assembler::ComputeRange(Register result,
- Register value,
- Label* miss) {
- const Register hi = TMP;
- const Register lo = CMPRES2;
-
- Label done;
- srl(result, value, kBitsPerWord - 1);
- andi(CMPRES1, value, Immediate(kSmiTagMask));
- beq(CMPRES1, ZR, &done);
-
- LoadClassId(CMPRES1, value);
- BranchNotEqual(CMPRES1, Immediate(kMintCid), miss);
- LoadFieldFromOffset(hi, value, Mint::value_offset() + kWordSize);
- LoadFieldFromOffset(lo, value, Mint::value_offset());
- sra(lo, lo, kBitsPerWord - 1);
-
- LoadImmediate(result, ICData::kInt32RangeBit);
-
- beq(hi, lo, &done);
- delay_slot()->subu(result, result, hi);
-
- beq(hi, ZR, &done);
- delay_slot()->addiu(result, ZR, Immediate(ICData::kUint32RangeBit));
- LoadImmediate(result, ICData::kInt64RangeBit);
- Bind(&done);
-}
-
-
-void Assembler::UpdateRangeFeedback(Register value,
- intptr_t index,
- Register ic_data,
- Register scratch,
- Label* miss) {
- ASSERT(ICData::IsValidRangeFeedbackIndex(index));
- ComputeRange(scratch, value, miss);
- LoadFieldFromOffset(TMP, ic_data, ICData::state_bits_offset());
- sll(scratch, scratch, ICData::RangeFeedbackShift(index));
- or_(TMP, TMP, scratch);
- StoreFieldToOffset(TMP, ic_data, ICData::state_bits_offset());
-}
-
-
void Assembler::EnterFrame() {
ASSERT(!in_delay_slot_);
addiu(SP, SP, Immediate(-2 * kWordSize));
@@ -903,6 +860,26 @@
}
+#ifndef PRODUCT
+void Assembler::MaybeTraceAllocation(intptr_t cid,
+ Register temp_reg,
+ Label* trace) {
+ ASSERT(cid > 0);
+ ASSERT(!in_delay_slot_);
+ ASSERT(temp_reg != kNoRegister);
+ ASSERT(temp_reg != TMP);
+ intptr_t state_offset = ClassTable::StateOffsetFor(cid);
+ LoadIsolate(temp_reg);
+ intptr_t table_offset =
+ Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid);
+ lw(temp_reg, Address(temp_reg, table_offset));
+ AddImmediate(temp_reg, state_offset);
+ lw(temp_reg, Address(temp_reg, 0));
+ andi(CMPRES1, temp_reg, Immediate(ClassHeapStats::TraceAllocationMask()));
+ bne(CMPRES1, ZR, trace);
+}
+
+
void Assembler::UpdateAllocationStats(intptr_t cid,
Register temp_reg,
Heap::Space space) {
@@ -950,25 +927,7 @@
addu(TMP, TMP, size_reg);
sw(TMP, Address(temp_reg, size_field_offset));
}
-
-
-void Assembler::MaybeTraceAllocation(intptr_t cid,
- Register temp_reg,
- Label* trace) {
- ASSERT(cid > 0);
- ASSERT(!in_delay_slot_);
- ASSERT(temp_reg != kNoRegister);
- ASSERT(temp_reg != TMP);
- intptr_t state_offset = ClassTable::StateOffsetFor(cid);
- LoadIsolate(temp_reg);
- intptr_t table_offset =
- Isolate::class_table_offset() + ClassTable::TableOffsetFor(cid);
- lw(temp_reg, Address(temp_reg, table_offset));
- AddImmediate(temp_reg, state_offset);
- lw(temp_reg, Address(temp_reg, 0));
- andi(CMPRES1, temp_reg, Immediate(ClassHeapStats::TraceAllocationMask()));
- bne(CMPRES1, ZR, trace);
-}
+#endif // !PRODUCT
void Assembler::TryAllocate(const Class& cls,
diff --git a/runtime/vm/assembler_mips.h b/runtime/vm/assembler_mips.h
index 39b06a4..87717b6 100644
--- a/runtime/vm/assembler_mips.h
+++ b/runtime/vm/assembler_mips.h
@@ -1472,6 +1472,11 @@
sra(dst, src, kSmiTagSize);
}
+ void BranchIfNotSmi(Register reg, Label* label) {
+ andi(CMPRES1, reg, Immediate(kSmiTagMask));
+ bne(CMPRES1, ZR, label);
+ }
+
void LoadFromOffset(Register reg, Register base, int32_t offset) {
ASSERT(!in_delay_slot_);
if (Utils::IsInt(kImmBits, offset)) {
@@ -1549,16 +1554,6 @@
void LoadClassIdMayBeSmi(Register result, Register object);
void LoadTaggedClassIdMayBeSmi(Register result, Register object);
- void ComputeRange(Register result,
- Register value,
- Label* miss);
-
- void UpdateRangeFeedback(Register value,
- intptr_t index,
- Register ic_data,
- Register scratch,
- Label* miss);
-
void StoreIntoObject(Register object, // Object we are storing into.
const Address& dest, // Where we are storing into.
Register value, // Value we are storing.
diff --git a/runtime/vm/assembler_mips_test.cc b/runtime/vm/assembler_mips_test.cc
index 2072751..2a77101 100644
--- a/runtime/vm/assembler_mips_test.cc
+++ b/runtime/vm/assembler_mips_test.cc
@@ -2141,57 +2141,6 @@
}
-ASSEMBLER_TEST_GENERATE(ComputeRange, assembler) {
- Label miss, done;
- __ ComputeRange(V0, A0, &miss);
- __ b(&done);
-
- __ Bind(&miss);
- __ LoadImmediate(V0, -1);
-
- __ Bind(&done);
- __ Ret();
-}
-
-
-ASSEMBLER_TEST_RUN(ComputeRange, test) {
- typedef intptr_t (*ComputeRange)(intptr_t value) DART_UNUSED;
-
-#define RANGE_OF(v) \
- (EXECUTE_TEST_CODE_INTPTR_INTPTR( \
- ComputeRange, test->entry(), reinterpret_cast<intptr_t>(v)))
-
- EXPECT_EQ(0, RANGE_OF(Smi::New(0)));
- EXPECT_EQ(0, RANGE_OF(Smi::New(1)));
- EXPECT_EQ(ICData::kSignedRangeBit, RANGE_OF(Smi::New(-1)));
- EXPECT_EQ(0, RANGE_OF(Smi::New(Smi::kMaxValue)));
- EXPECT_EQ(ICData::kSignedRangeBit, RANGE_OF(Smi::New(Smi::kMinValue)));
-
- EXPECT_EQ(ICData::kInt32RangeBit, RANGE_OF(Integer::New(Smi::kMaxValue + 1)));
- EXPECT_EQ(ICData::kInt32RangeBit | ICData::kSignedRangeBit,
- RANGE_OF(Integer::New(Smi::kMinValue - 1)));
- EXPECT_EQ(ICData::kInt32RangeBit, RANGE_OF(Integer::New(kMaxInt32)));
- EXPECT_EQ(ICData::kInt32RangeBit | ICData::kSignedRangeBit,
- RANGE_OF(Integer::New(kMinInt32)));
-
- EXPECT_EQ(ICData::kUint32RangeBit,
- RANGE_OF(Integer::New(static_cast<int64_t>(kMaxInt32) + 1)));
- EXPECT_EQ(ICData::kUint32RangeBit,
- RANGE_OF(Integer::New(kMaxUint32)));
-
- EXPECT_EQ(ICData::kInt64RangeBit,
- RANGE_OF(Integer::New(static_cast<int64_t>(kMaxUint32) + 1)));
- EXPECT_EQ(ICData::kInt64RangeBit,
- RANGE_OF(Integer::New(static_cast<int64_t>(kMinInt32) - 1)));
- EXPECT_EQ(ICData::kInt64RangeBit, RANGE_OF(Integer::New(kMaxInt64)));
- EXPECT_EQ(ICData::kInt64RangeBit, RANGE_OF(Integer::New(kMinInt64)));
-
- EXPECT_EQ(-1, RANGE_OF(Bool::True().raw()));
-
-#undef RANGE_OF
-}
-
-
ASSEMBLER_TEST_GENERATE(Semaphore, assembler) {
__ EnterFrame();
__ LoadImmediate(T0, 40);
diff --git a/runtime/vm/assembler_x64.cc b/runtime/vm/assembler_x64.cc
index c266bf6..1902779 100644
--- a/runtime/vm/assembler_x64.cc
+++ b/runtime/vm/assembler_x64.cc
@@ -3321,6 +3321,7 @@
}
+#ifndef PRODUCT
void Assembler::MaybeTraceAllocation(intptr_t cid,
Label* trace,
bool near_jump) {
@@ -3375,6 +3376,7 @@
intptr_t size_offset = ClassTable::SizeOffsetFor(cid, space == Heap::kNew);
addq(Address(temp_reg, size_offset), Immediate(size_in_bytes));
}
+#endif // !PRODUCT
void Assembler::TryAllocate(const Class& cls,
@@ -3673,48 +3675,6 @@
}
-void Assembler::ComputeRange(Register result, Register value, Label* not_mint) {
- Label done, not_smi;
- testl(value, Immediate(kSmiTagMask));
- j(NOT_ZERO, ¬_smi, Assembler::kNearJump);
-
- sarq(value, Immediate(32)); // Take the tag into account.
- movq(result, Immediate(ICData::kUint32RangeBit)); // Uint32
- cmpq(value, Immediate(1));
- j(EQUAL, &done, Assembler::kNearJump);
-
- movq(result, Immediate(ICData::kInt32RangeBit));
- subq(result, value); // 10 (positive int32), 11 (negative int32)
- negq(value);
- cmpq(value, Immediate(1));
- j(BELOW_EQUAL, &done);
-
- // On 64-bit we don't need to track sign of smis outside of the Int32 range.
- // Just pretend they are all signed.
- movq(result, Immediate(ICData::kSignedRangeBit));
- jmp(&done);
-
- Bind(¬_smi);
- CompareClassId(value, kMintCid);
- j(NOT_EQUAL, not_mint);
- movq(result, Immediate(ICData::kInt64RangeBit));
-
- Bind(&done);
-}
-
-
-void Assembler::UpdateRangeFeedback(Register value,
- intptr_t index,
- Register ic_data,
- Register scratch,
- Label* miss) {
- ASSERT(ICData::IsValidRangeFeedbackIndex(index));
- ComputeRange(scratch, value, miss);
- shll(scratch, Immediate(ICData::RangeFeedbackShift(index)));
- orl(FieldAddress(ic_data, ICData::state_bits_offset()), scratch);
-}
-
-
Address Assembler::ElementAddressForIntIndex(bool is_external,
intptr_t cid,
intptr_t index_scale,
diff --git a/runtime/vm/assembler_x64.h b/runtime/vm/assembler_x64.h
index f31d37b..f4ce132 100644
--- a/runtime/vm/assembler_x64.h
+++ b/runtime/vm/assembler_x64.h
@@ -861,14 +861,11 @@
sarq(reg, Immediate(kSmiTagSize));
}
- void ComputeRange(Register result, Register value, Label* miss);
- void UpdateRangeFeedback(Register value,
- intptr_t index,
- Register ic_data,
- Register scratch,
- Label* miss);
+ void BranchIfNotSmi(Register reg, Label* label) {
+ testq(reg, Immediate(kSmiTagMask));
+ j(NOT_ZERO, label);
+ }
- int PreferredLoopAlignment() { return 16; }
void Align(int alignment, intptr_t offset);
void Bind(Label* label);
void Jump(Label* label) { jmp(label); }
diff --git a/runtime/vm/assembler_x64_test.cc b/runtime/vm/assembler_x64_test.cc
index eb8219d..681a599 100644
--- a/runtime/vm/assembler_x64_test.cc
+++ b/runtime/vm/assembler_x64_test.cc
@@ -3589,55 +3589,6 @@
EXPECT_EQ(0, res);
}
-
-ASSEMBLER_TEST_GENERATE(ComputeRange, assembler) {
- Label miss;
- __ movq(RDX, CallingConventions::kArg1Reg);
- __ ComputeRange(RAX, RDX, &miss);
- __ ret();
-
- __ Bind(&miss);
- __ movq(RAX, Immediate(0));
- __ ret();
-}
-
-
-ASSEMBLER_TEST_RUN(ComputeRange, test) {
- typedef intptr_t (*ComputeRange)(RawObject*);
- ComputeRange range_of = reinterpret_cast<ComputeRange>(test->entry());
-
- EXPECT_EQ(ICData::kInt32RangeBit, range_of(Smi::New(0)));
- EXPECT_EQ(ICData::kInt32RangeBit, range_of(Smi::New(1)));
- EXPECT_EQ(ICData::kInt32RangeBit, range_of(Smi::New(kMaxInt32)));
- EXPECT_EQ(ICData::kInt32RangeBit | ICData::kSignedRangeBit,
- range_of(Smi::New(-1)));
- EXPECT_EQ(ICData::kInt32RangeBit | ICData::kSignedRangeBit,
- range_of(Smi::New(kMinInt32)));
-
- EXPECT_EQ(ICData::kUint32RangeBit,
- range_of(Smi::New(static_cast<int64_t>(kMaxInt32) + 1)));
- EXPECT_EQ(ICData::kUint32RangeBit,
- range_of(Smi::New(kMaxUint32)));
-
- // On 64-bit platforms we don't track the sign of the smis outside of
- // int32 range because it is not needed to distinguish kInt32Range from
- // kUint32Range.
- EXPECT_EQ(ICData::kSignedRangeBit,
- range_of(Smi::New(static_cast<int64_t>(kMinInt32) - 1)));
- EXPECT_EQ(ICData::kSignedRangeBit,
- range_of(Smi::New(static_cast<int64_t>(kMaxUint32) + 1)));
- EXPECT_EQ(ICData::kSignedRangeBit, range_of(Smi::New(Smi::kMaxValue)));
- EXPECT_EQ(ICData::kSignedRangeBit, range_of(Smi::New(Smi::kMinValue)));
-
- EXPECT_EQ(ICData::kInt64RangeBit, range_of(Integer::New(Smi::kMaxValue + 1)));
- EXPECT_EQ(ICData::kInt64RangeBit, range_of(Integer::New(Smi::kMinValue - 1)));
- EXPECT_EQ(ICData::kInt64RangeBit, range_of(Integer::New(kMaxInt64)));
- EXPECT_EQ(ICData::kInt64RangeBit, range_of(Integer::New(kMinInt64)));
-
- EXPECT_EQ(0, range_of(Bool::True().raw()));
-}
-
-
} // namespace dart
#endif // defined TARGET_ARCH_X64
diff --git a/runtime/vm/atomic_fuchsia.h b/runtime/vm/atomic_fuchsia.h
index d6c0f57..67dd329 100644
--- a/runtime/vm/atomic_fuchsia.h
+++ b/runtime/vm/atomic_fuchsia.h
@@ -13,34 +13,30 @@
#error This file should only be included on Fuchsia builds.
#endif
-#include "platform/assert.h"
-
namespace dart {
inline uintptr_t AtomicOperations::FetchAndIncrement(uintptr_t* p) {
- UNIMPLEMENTED();
- return 0;
+ return __sync_fetch_and_add(p, 1);
}
inline void AtomicOperations::IncrementBy(intptr_t* p, intptr_t value) {
- UNIMPLEMENTED();
+ __sync_fetch_and_add(p, value);
}
inline void AtomicOperations::IncrementInt64By(int64_t* p, int64_t value) {
- UNIMPLEMENTED();
+ __sync_fetch_and_add(p, value);
}
inline uintptr_t AtomicOperations::FetchAndDecrement(uintptr_t* p) {
- UNIMPLEMENTED();
- return 0;
+ return __sync_fetch_and_sub(p, 1);
}
inline void AtomicOperations::DecrementBy(intptr_t* p, intptr_t value) {
- UNIMPLEMENTED();
+ __sync_fetch_and_sub(p, value);
}
@@ -48,16 +44,14 @@
inline uword AtomicOperations::CompareAndSwapWord(uword* ptr,
uword old_value,
uword new_value) {
- UNIMPLEMENTED();
- return 0;
+ return __sync_val_compare_and_swap(ptr, old_value, new_value);
}
inline uint32_t AtomicOperations::CompareAndSwapUint32(uint32_t* ptr,
uint32_t old_value,
uint32_t new_value) {
- UNIMPLEMENTED();
- return 0;
+ return __sync_val_compare_and_swap(ptr, old_value, new_value);
}
#endif // !defined(USING_SIMULATOR_ATOMICS)
diff --git a/runtime/vm/become.cc b/runtime/vm/become.cc
index 13b7439..a4d9fd1 100644
--- a/runtime/vm/become.cc
+++ b/runtime/vm/become.cc
@@ -148,6 +148,17 @@
};
+void Become::MakeDummyObject(const Instance& instance) {
+ // Make the forward pointer point to itself.
+ // This is needed to distinguish it from a real forward object.
+ ForwardObjectTo(instance.raw(), instance.raw());
+}
+
+static bool IsDummyObject(RawObject* object) {
+ if (!object->IsForwardingCorpse()) return false;
+ return GetForwardedObject(object) == object;
+}
+
void Become::ElementsForwardIdentity(const Array& before, const Array& after) {
Thread* thread = Thread::Current();
Isolate* isolate = thread->isolate();
@@ -174,7 +185,7 @@
if (before_obj->IsVMHeapObject()) {
FATAL("become: Cannot forward VM heap objects");
}
- if (before_obj->IsForwardingCorpse()) {
+ if (before_obj->IsForwardingCorpse() && !IsDummyObject(before_obj)) {
FATAL("become: Cannot forward to multiple targets");
}
if (after_obj->IsForwardingCorpse()) {
diff --git a/runtime/vm/become.h b/runtime/vm/become.h
index b78524d..8ce164e 100644
--- a/runtime/vm/become.h
+++ b/runtime/vm/become.h
@@ -80,6 +80,11 @@
// in 'after'. Every element in 'before' is guaranteed to be not reachable.
// Useful for atomically applying behavior and schema changes.
static void ElementsForwardIdentity(const Array& before, const Array& after);
+
+ // Convert and instance object into a dummy object,
+ // making the instance independent of its class.
+ // (used for morphic instances during reload).
+ static void MakeDummyObject(const Instance& instance);
};
} // namespace dart
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 4bb5e93..161d0b2 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -21,6 +21,7 @@
V(Object_noSuchMethod, 6) \
V(Object_runtimeType, 1) \
V(Object_instanceOf, 4) \
+ V(Object_simpleInstanceOf, 2) \
V(Object_instanceOfNum, 2) \
V(Object_instanceOfInt, 2) \
V(Object_instanceOfSmi, 2) \
@@ -365,6 +366,7 @@
V(VMService_CancelStream, 1) \
V(VMService_RequestAssets, 0) \
V(VMService_DecodeAssets, 1) \
+ V(VMService_spawnUriNotify, 2) \
// List of bootstrap native entry points used in the dart:mirror library.
#define MIRRORS_BOOTSTRAP_NATIVE_LIST(V) \
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index 6554d23..1191301 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -2521,12 +2521,15 @@
// getter function object for each enumeration value and for the
// values field. We also don't have to generate the code for these getters
// from thin air (no source code is available).
-void ClassFinalizer::AllocateEnumValues(const Class &enum_cls) {
+void ClassFinalizer::AllocateEnumValues(const Class& enum_cls) {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
const Field& index_field =
Field::Handle(zone, enum_cls.LookupInstanceField(Symbols::Index()));
ASSERT(!index_field.IsNull());
+ const Field& name_field = Field::Handle(zone,
+ enum_cls.LookupInstanceFieldAllowPrivate(Symbols::_name()));
+ ASSERT(!name_field.IsNull());
const Field& values_field =
Field::Handle(zone, enum_cls.LookupStaticField(Symbols::Values()));
ASSERT(!values_field.IsNull());
@@ -2539,6 +2542,11 @@
Instance& ordinal_value = Instance::Handle(zone);
Instance& enum_value = Instance::Handle(zone);
+ const String& enum_name = String::Handle(enum_cls.ScrubbedName());
+ const String& name_prefix =
+ String::Handle(String::Concat(enum_name, Symbols::Dot()));
+
+ String& enum_ident = String::Handle();
for (intptr_t i = 0; i < fields.Length(); i++) {
field = Field::RawCast(fields.At(i));
if (!field.is_static()) continue;
@@ -2547,8 +2555,18 @@
// contain the smi value of the ordinal number, which was stored in
// the field by the parser. Other fields contain non-smi values.
if (!ordinal_value.IsSmi()) continue;
+ enum_ident = field.name();
+ // Construct the string returned by toString.
+ ASSERT(!enum_ident.IsNull());
+ // For the user-visible name of the enumeration value, we need to
+ // unmangle private names.
+ if (enum_ident.CharAt(0) == '_') {
+ enum_ident = String::ScrubName(enum_ident);
+ }
+ enum_ident = Symbols::FromConcat(thread, name_prefix, enum_ident);
enum_value = Instance::New(enum_cls, Heap::kOld);
enum_value.SetField(index_field, ordinal_value);
+ enum_value.SetField(name_field, enum_ident);
const char* error_msg = "";
enum_value = enum_value.CheckAndCanonicalize(thread, &error_msg);
ASSERT(!enum_value.IsNull());
diff --git a/runtime/vm/class_table.cc b/runtime/vm/class_table.cc
index 4549fb8..ed2ea00 100644
--- a/runtime/vm/class_table.cc
+++ b/runtime/vm/class_table.cc
@@ -19,9 +19,9 @@
ClassTable::ClassTable()
: top_(kNumPredefinedCids), capacity_(0), table_(NULL),
- old_tables_(new MallocGrowableArray<RawClass**>()),
- class_heap_stats_table_(NULL),
- predefined_class_heap_stats_table_(NULL) {
+ old_tables_(new MallocGrowableArray<RawClass**>()) {
+ NOT_IN_PRODUCT(class_heap_stats_table_ = NULL);
+ NOT_IN_PRODUCT(predefined_class_heap_stats_table_ = NULL);
if (Dart::vm_isolate() == NULL) {
capacity_ = initial_capacity_;
table_ = reinterpret_cast<RawClass**>(
@@ -39,17 +39,22 @@
table_[kForwardingCorpse] = vm_class_table->At(kForwardingCorpse);
table_[kDynamicCid] = vm_class_table->At(kDynamicCid);
table_[kVoidCid] = vm_class_table->At(kVoidCid);
+
+#ifndef PRODUCT
class_heap_stats_table_ = reinterpret_cast<ClassHeapStats*>(
calloc(capacity_, sizeof(ClassHeapStats))); // NOLINT
for (intptr_t i = 0; i < capacity_; i++) {
class_heap_stats_table_[i].Initialize();
}
+#endif // !PRODUCT
}
+#ifndef PRODUCT
predefined_class_heap_stats_table_ = reinterpret_cast<ClassHeapStats*>(
calloc(kNumPredefinedCids, sizeof(ClassHeapStats))); // NOLINT
for (intptr_t i = 0; i < kNumPredefinedCids; i++) {
predefined_class_heap_stats_table_[i].Initialize();
}
+#endif // !PRODUCT
}
@@ -57,9 +62,9 @@
: top_(original->top_),
capacity_(original->top_),
table_(original->table_),
- old_tables_(NULL),
- class_heap_stats_table_(NULL),
- predefined_class_heap_stats_table_(NULL) {
+ old_tables_(NULL) {
+ NOT_IN_PRODUCT(class_heap_stats_table_ = NULL);
+ NOT_IN_PRODUCT(predefined_class_heap_stats_table_ = NULL);
}
@@ -68,12 +73,12 @@
FreeOldTables();
delete old_tables_;
free(table_);
- free(predefined_class_heap_stats_table_);
- free(class_heap_stats_table_);
+ NOT_IN_PRODUCT(free(predefined_class_heap_stats_table_));
+ NOT_IN_PRODUCT(free(class_heap_stats_table_));
} else {
// This instance was a shallow copy. It doesn't own any memory.
- ASSERT(predefined_class_heap_stats_table_ == NULL);
- ASSERT(class_heap_stats_table_ == NULL);
+ NOT_IN_PRODUCT(ASSERT(predefined_class_heap_stats_table_ == NULL));
+ NOT_IN_PRODUCT(ASSERT(class_heap_stats_table_ == NULL));
}
}
@@ -85,6 +90,7 @@
}
+#ifndef PRODUCT
void ClassTable::SetTraceAllocationFor(intptr_t cid, bool trace) {
ClassHeapStats* stats = PreliminaryStatsAt(cid);
stats->set_trace_allocation(trace);
@@ -95,6 +101,7 @@
ClassHeapStats* stats = PreliminaryStatsAt(cid);
return stats->trace_allocation();
}
+#endif // !PRODUCT
void ClassTable::Register(const Class& cls) {
@@ -120,17 +127,19 @@
RawClass** new_table = reinterpret_cast<RawClass**>(
malloc(new_capacity * sizeof(RawClass*))); // NOLINT
memmove(new_table, table_, capacity_ * sizeof(RawClass*));
+#ifndef PRODUCT
ClassHeapStats* new_stats_table = reinterpret_cast<ClassHeapStats*>(
realloc(class_heap_stats_table_,
new_capacity * sizeof(ClassHeapStats))); // NOLINT
+#endif
for (intptr_t i = capacity_; i < new_capacity; i++) {
new_table[i] = NULL;
- new_stats_table[i].Initialize();
+ NOT_IN_PRODUCT(new_stats_table[i].Initialize());
}
capacity_ = new_capacity;
old_tables_->Add(table_);
table_ = new_table; // TODO(koda): This should use atomics.
- class_heap_stats_table_ = new_stats_table;
+ NOT_IN_PRODUCT(class_heap_stats_table_ = new_stats_table);
}
ASSERT(top_ < capacity_);
if (!Class::is_valid_id(top_)) {
@@ -156,17 +165,19 @@
RawClass** new_table = reinterpret_cast<RawClass**>(
malloc(new_capacity * sizeof(RawClass*))); // NOLINT
memmove(new_table, table_, capacity_ * sizeof(RawClass*));
+#ifndef PRODUCT
ClassHeapStats* new_stats_table = reinterpret_cast<ClassHeapStats*>(
realloc(class_heap_stats_table_,
new_capacity * sizeof(ClassHeapStats))); // NOLINT
+#endif
for (intptr_t i = capacity_; i < new_capacity; i++) {
new_table[i] = NULL;
- new_stats_table[i].Initialize();
+ NOT_IN_PRODUCT(new_stats_table[i].Initialize());
}
capacity_ = new_capacity;
old_tables_->Add(table_);
table_ = new_table; // TODO(koda): This should use atomics.
- class_heap_stats_table_ = new_stats_table;
+ NOT_IN_PRODUCT(class_heap_stats_table_ = new_stats_table);
ASSERT(capacity_increment_ >= 1);
}
@@ -252,7 +263,6 @@
}
}
}
-#endif // PRODUCT
void ClassHeapStats::Initialize() {
@@ -264,6 +274,7 @@
promoted_count = 0;
promoted_size = 0;
state_ = 0;
+ USE(align_);
}
@@ -332,7 +343,6 @@
}
-#ifndef PRODUCT
void ClassHeapStats::PrintToJSONObject(const Class& cls,
JSONObject* obj) const {
if (!FLAG_support_service) {
@@ -369,7 +379,6 @@
obj->AddProperty("promotedInstances", promoted_count);
obj->AddProperty("promotedBytes", promoted_size);
}
-#endif
void ClassTable::UpdateAllocatedNew(intptr_t cid, intptr_t size) {
@@ -496,7 +505,6 @@
}
-#ifndef PRODUCT
void ClassTable::AllocationProfilePrintJSON(JSONStream* stream) {
if (!FLAG_support_service) {
return;
@@ -538,7 +546,6 @@
}
}
}
-#endif
void ClassTable::ResetAllocationAccumulators() {
@@ -566,6 +573,7 @@
ASSERT(size >= 0);
stats->post_gc.AddNew(size);
}
+#endif // !PRODUCT
} // namespace dart
diff --git a/runtime/vm/class_table.h b/runtime/vm/class_table.h
index 9a12fc3e..a7e38ba 100644
--- a/runtime/vm/class_table.h
+++ b/runtime/vm/class_table.h
@@ -20,6 +20,7 @@
class ObjectPointerVisitor;
class RawClass;
+#ifndef PRODUCT
template<typename T>
class AllocStats {
public:
@@ -141,8 +142,9 @@
intptr_t old_pre_new_gc_count_;
intptr_t old_pre_new_gc_size_;
intptr_t state_;
+ intptr_t align_; // Make SIMARM and ARM agree on the size of ClassHeapStats.
};
-
+#endif // !PRODUCT
class ClassTable {
public:
@@ -194,15 +196,16 @@
void Validate();
void Print();
-#ifndef PRODUCT
- void PrintToJSONObject(JSONObject* object);
-#endif
// Used by the generated code.
static intptr_t table_offset() {
return OFFSET_OF(ClassTable, table_);
}
+ // Used by the generated code.
+ static intptr_t ClassOffsetFor(intptr_t cid);
+
+#ifndef PRODUCT
// Called whenever a class is allocated in the runtime.
void UpdateAllocatedNew(intptr_t cid, intptr_t size);
void UpdateAllocatedOld(intptr_t cid, intptr_t size);
@@ -215,9 +218,6 @@
void UpdatePromoted();
// Used by the generated code.
- static intptr_t ClassOffsetFor(intptr_t cid);
-
- // Used by the generated code.
ClassHeapStats** TableAddressFor(intptr_t cid);
static intptr_t TableOffsetFor(intptr_t cid);
@@ -235,6 +235,9 @@
void AllocationProfilePrintJSON(JSONStream* stream);
void ResetAllocationAccumulators();
+ void PrintToJSONObject(JSONObject* object);
+#endif // !PRODUCT
+
// Deallocates table copies. Do not call during concurrent access to table.
void FreeOldTables();
@@ -257,14 +260,15 @@
RawClass** table_;
MallocGrowableArray<RawClass**>* old_tables_;
+#ifndef PRODUCT
ClassHeapStats* class_heap_stats_table_;
-
ClassHeapStats* predefined_class_heap_stats_table_;
// May not have updated size for variable size classes.
ClassHeapStats* PreliminaryStatsAt(intptr_t cid);
void UpdateLiveOld(intptr_t cid, intptr_t size, intptr_t count = 1);
void UpdateLiveNew(intptr_t cid, intptr_t size);
+#endif // !PRODUCT
DISALLOW_COPY_AND_ASSIGN(ClassTable);
};
diff --git a/runtime/vm/clustered_snapshot.cc b/runtime/vm/clustered_snapshot.cc
index e938fef..6f958fd 100644
--- a/runtime/vm/clustered_snapshot.cc
+++ b/runtime/vm/clustered_snapshot.cc
@@ -78,15 +78,15 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kClassCid);
intptr_t count = predefined_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawClass* cls = predefined_[i];
intptr_t class_id = cls->ptr()->id_;
- s->Write<intptr_t>(class_id);
+ s->WriteCid(class_id);
s->AssignRef(cls);
}
count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawClass* cls = objects_[i];
s->AssignRef(cls);
@@ -137,10 +137,10 @@
void ReadAlloc(Deserializer* d) {
predefined_start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
ClassTable* table = d->isolate()->class_table();
for (intptr_t i = 0; i < count; i++) {
- intptr_t class_id = d->Read<intptr_t>();
+ intptr_t class_id = d->ReadCid();
ASSERT(table->HasValidClassAt(class_id));
RawClass* cls = table->At(class_id);
ASSERT(cls != NULL);
@@ -149,7 +149,7 @@
predefined_stop_index_ = d->next_index();
start_index_ = d->next_index();
- count = d->Read<intptr_t>();
+ count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(AllocateUninitialized(old_space,
Class::InstanceSize()));
@@ -174,8 +174,13 @@
intptr_t class_id = d->ReadCid();
cls->ptr()->id_ = class_id;
- cls->ptr()->instance_size_in_words_ = d->Read<int32_t>();
- cls->ptr()->next_field_offset_in_words_ = d->Read<int32_t>();
+ if (!RawObject::IsInternalVMdefinedClassId(class_id)) {
+ cls->ptr()->instance_size_in_words_ = d->Read<int32_t>();
+ cls->ptr()->next_field_offset_in_words_ = d->Read<int32_t>();
+ } else {
+ d->Read<int32_t>(); // Skip.
+ d->Read<int32_t>(); // Skip.
+ }
cls->ptr()->type_arguments_field_offset_in_words_ = d->Read<int32_t>();
cls->ptr()->num_type_arguments_ = d->Read<uint16_t>();
cls->ptr()->num_own_type_arguments_ = d->Read<uint16_t>();
@@ -261,7 +266,7 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kUnresolvedClassCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawUnresolvedClass* cls = objects_[i];
s->AssignRef(cls);
@@ -270,7 +275,7 @@
void WriteFill(Serializer* s) {
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawUnresolvedClass* cls = objects_[i];
RawObject** from = cls->from();
@@ -295,7 +300,7 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(AllocateUninitialized(old_space,
UnresolvedClass::InstanceSize()));
@@ -342,11 +347,11 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kTypeArgumentsCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawTypeArguments* type_args = objects_[i];
intptr_t length = Smi::Value(type_args->ptr()->length_);
- s->Write<intptr_t>(length);
+ s->Write<int32_t>(length);
s->AssignRef(type_args);
}
}
@@ -356,7 +361,7 @@
for (intptr_t i = 0; i < count; i++) {
RawTypeArguments* type_args = objects_[i];
intptr_t length = Smi::Value(type_args->ptr()->length_);
- s->Write<intptr_t>(length);
+ s->Write<int32_t>(length);
s->Write<bool>(type_args->IsCanonical());
intptr_t hash = Smi::Value(type_args->ptr()->hash_);
s->Write<int32_t>(hash);
@@ -380,9 +385,9 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
- intptr_t length = d->Read<intptr_t>();
+ intptr_t length = d->Read<int32_t>();
d->AssignRef(AllocateUninitialized(old_space,
TypeArguments::InstanceSize(length)));
}
@@ -395,7 +400,7 @@
for (intptr_t id = start_index_; id < stop_index_; id++) {
RawTypeArguments* type_args =
reinterpret_cast<RawTypeArguments*>(d->Ref(id));
- intptr_t length = d->Read<intptr_t>();
+ intptr_t length = d->Read<int32_t>();
bool is_canonical = d->Read<bool>();
Deserializer::InitializeHeader(type_args, kTypeArgumentsCid,
TypeArguments::InstanceSize(length),
@@ -432,7 +437,7 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kPatchClassCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawPatchClass* cls = objects_[i];
s->AssignRef(cls);
@@ -464,7 +469,7 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(AllocateUninitialized(old_space,
PatchClass::InstanceSize()));
@@ -514,7 +519,7 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kFunctionCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawFunction* func = objects_[i];
s->AssignRef(func);
@@ -572,7 +577,7 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(AllocateUninitialized(old_space,
Function::InstanceSize()));
@@ -684,7 +689,7 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kClosureDataCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawClosureData* data = objects_[i];
s->AssignRef(data);
@@ -716,7 +721,7 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(AllocateUninitialized(old_space,
ClosureData::InstanceSize()));
@@ -760,7 +765,7 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kRedirectionDataCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawRedirectionData* data = objects_[i];
s->AssignRef(data);
@@ -792,7 +797,7 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(AllocateUninitialized(old_space,
RedirectionData::InstanceSize()));
@@ -864,7 +869,7 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kFieldCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawField* field = objects_[i];
s->AssignRef(field);
@@ -929,7 +934,7 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(AllocateUninitialized(old_space, Field::InstanceSize()));
}
@@ -1006,7 +1011,7 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kLiteralTokenCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawLiteralToken* token = objects_[i];
s->AssignRef(token);
@@ -1039,7 +1044,7 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(AllocateUninitialized(old_space,
LiteralToken::InstanceSize()));
@@ -1085,7 +1090,7 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kTokenStreamCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawTokenStream* stream = objects_[i];
s->AssignRef(stream);
@@ -1117,7 +1122,7 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(AllocateUninitialized(old_space,
TokenStream::InstanceSize()));
@@ -1161,7 +1166,7 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kScriptCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawScript* script = objects_[i];
s->AssignRef(script);
@@ -1198,7 +1203,7 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(AllocateUninitialized(old_space, Script::InstanceSize()));
}
@@ -1251,7 +1256,7 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kLibraryCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawLibrary* lib = objects_[i];
s->AssignRef(lib);
@@ -1289,7 +1294,7 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(AllocateUninitialized(old_space, Library::InstanceSize()));
}
@@ -1361,7 +1366,7 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kNamespaceCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawNamespace* ns = objects_[i];
s->AssignRef(ns);
@@ -1393,7 +1398,7 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(AllocateUninitialized(old_space, Namespace::InstanceSize()));
}
@@ -1436,7 +1441,7 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kCodeCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawCode* code = objects_[i];
s->AssignRef(code);
@@ -1496,7 +1501,7 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(AllocateUninitialized(old_space, Code::InstanceSize(0)));
}
@@ -1571,11 +1576,11 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kObjectPoolCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawObjectPool* pool = objects_[i];
intptr_t length = pool->ptr()->length_;
- s->Write<intptr_t>(length);
+ s->Write<int32_t>(length);
s->AssignRef(pool);
}
}
@@ -1586,7 +1591,7 @@
RawObjectPool* pool = objects_[i];
RawTypedData* info_array = pool->ptr()->info_array_;
intptr_t length = pool->ptr()->length_;
- s->Write<intptr_t>(length);
+ s->Write<int32_t>(length);
for (intptr_t j = 0; j < length; j++) {
ObjectPool::EntryType entry_type =
static_cast<ObjectPool::EntryType>(info_array->ptr()->data()[j]);
@@ -1638,9 +1643,9 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
- intptr_t length = d->Read<intptr_t>();
+ intptr_t length = d->Read<int32_t>();
d->AssignRef(AllocateUninitialized(old_space,
ObjectPool::InstanceSize(length)));
}
@@ -1651,7 +1656,7 @@
bool is_vm_object = d->isolate() == Dart::vm_isolate();
PageSpace* old_space = d->heap()->old_space();
for (intptr_t id = start_index_; id < stop_index_; id += 1) {
- intptr_t length = d->Read<intptr_t>();
+ intptr_t length = d->Read<int32_t>();
RawTypedData* info_array = reinterpret_cast<RawTypedData*>(
AllocateUninitialized(old_space, TypedData::InstanceSize(length)));
Deserializer::InitializeHeader(info_array, kTypedDataUint8ArrayCid,
@@ -1728,7 +1733,7 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(cid_);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawObject* object = objects_[i];
int32_t rodata_offset = s->GetRODataOffset(object);
@@ -1753,7 +1758,7 @@
virtual ~RODataDeserializationCluster() { }
void ReadAlloc(Deserializer* d) {
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
int32_t rodata_offset = d->Read<int32_t>();
d->AssignRef(d->GetObjectAt(rodata_offset));
@@ -1795,11 +1800,11 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kExceptionHandlersCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawExceptionHandlers* handlers = objects_[i];
intptr_t length = handlers->ptr()->num_entries_;
- s->Write<intptr_t>(length);
+ s->Write<int32_t>(length);
s->AssignRef(handlers);
}
}
@@ -1809,7 +1814,7 @@
for (intptr_t i = 0; i < count; i++) {
RawExceptionHandlers* handlers = objects_[i];
intptr_t length = handlers->ptr()->num_entries_;
- s->Write<intptr_t>(length);
+ s->Write<int32_t>(length);
s->WriteRef(handlers->ptr()->handled_types_data_);
uint8_t* data = reinterpret_cast<uint8_t*>(handlers->ptr()->data());
@@ -1832,9 +1837,9 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
- intptr_t length = d->Read<intptr_t>();
+ intptr_t length = d->Read<int32_t>();
d->AssignRef(AllocateUninitialized(old_space,
ExceptionHandlers::InstanceSize(length)));
}
@@ -1847,7 +1852,7 @@
for (intptr_t id = start_index_; id < stop_index_; id++) {
RawExceptionHandlers* handlers =
reinterpret_cast<RawExceptionHandlers*>(d->Ref(id));
- intptr_t length = d->Read<intptr_t>();
+ intptr_t length = d->Read<int32_t>();
Deserializer::InitializeHeader(handlers, kExceptionHandlersCid,
ExceptionHandlers::InstanceSize(length),
is_vm_object);
@@ -1882,11 +1887,11 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kContextCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawContext* context = objects_[i];
intptr_t length = context->ptr()->num_variables_;
- s->Write<intptr_t>(length);
+ s->Write<int32_t>(length);
s->AssignRef(context);
}
}
@@ -1896,7 +1901,7 @@
for (intptr_t i = 0; i < count; i++) {
RawContext* context = objects_[i];
intptr_t length = context->ptr()->num_variables_;
- s->Write<intptr_t>(length);
+ s->Write<int32_t>(length);
s->WriteRef(context->ptr()->parent_);
for (intptr_t j = 0; j < length; j++) {
s->WriteRef(context->ptr()->data()[j]);
@@ -1917,9 +1922,9 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
- intptr_t length = d->Read<intptr_t>();
+ intptr_t length = d->Read<int32_t>();
d->AssignRef(AllocateUninitialized(old_space,
Context::InstanceSize(length)));
}
@@ -1931,7 +1936,7 @@
for (intptr_t id = start_index_; id < stop_index_; id++) {
RawContext* context = reinterpret_cast<RawContext*>(d->Ref(id));
- intptr_t length = d->Read<intptr_t>();
+ intptr_t length = d->Read<int32_t>();
Deserializer::InitializeHeader(context, kContextCid,
Context::InstanceSize(length),
is_vm_object);
@@ -1965,11 +1970,11 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kContextScopeCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawContextScope* scope = objects_[i];
intptr_t length = scope->ptr()->num_variables_;
- s->Write<intptr_t>(length);
+ s->Write<int32_t>(length);
s->AssignRef(scope);
}
}
@@ -1979,7 +1984,7 @@
for (intptr_t i = 0; i < count; i++) {
RawContextScope* scope = objects_[i];
intptr_t length = scope->ptr()->num_variables_;
- s->Write<intptr_t>(length);
+ s->Write<int32_t>(length);
s->Write<bool>(scope->ptr()->is_implicit_);
RawObject** from = scope->from();
RawObject** to = scope->to(length);
@@ -2002,9 +2007,9 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
- intptr_t length = d->Read<intptr_t>();
+ intptr_t length = d->Read<int32_t>();
d->AssignRef(AllocateUninitialized(old_space,
ContextScope::InstanceSize(length)));
}
@@ -2016,7 +2021,7 @@
for (intptr_t id = start_index_; id < stop_index_; id++) {
RawContextScope* scope = reinterpret_cast<RawContextScope*>(d->Ref(id));
- intptr_t length = d->Read<intptr_t>();
+ intptr_t length = d->Read<int32_t>();
Deserializer::InitializeHeader(scope, kContextScopeCid,
ContextScope::InstanceSize(length),
is_vm_object);
@@ -2051,7 +2056,7 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kICDataCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawICData* ic = objects_[i];
s->AssignRef(ic);
@@ -2071,7 +2076,7 @@
s->Write<int32_t>(ic->ptr()->deopt_id_);
s->Write<uint32_t>(ic->ptr()->state_bits_);
#if defined(TAG_IC_DATA)
- s->Write<intptr_t>(ic->ptr()->tag_);
+ s->Write<int32_t>(ic->ptr()->tag_);
#endif
}
}
@@ -2089,7 +2094,7 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(AllocateUninitialized(old_space, ICData::InstanceSize()));
}
@@ -2116,7 +2121,7 @@
ic->ptr()->deopt_id_ = d->Read<int32_t>();
ic->ptr()->state_bits_ = d->Read<int32_t>();
#if defined(TAG_IC_DATA)
- ic->ptr()->tag_ = d->Read<intptr_t>();
+ ic->ptr()->tag_ = d->Read<int32_t>();
#endif
}
}
@@ -2165,7 +2170,7 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kMegamorphicCacheCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawMegamorphicCache* cache = objects_[i];
s->AssignRef(cache);
@@ -2198,7 +2203,7 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(AllocateUninitialized(old_space,
MegamorphicCache::InstanceSize()));
@@ -2240,7 +2245,7 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kSubtypeTestCacheCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawSubtypeTestCache* cache = objects_[i];
s->AssignRef(cache);
@@ -2268,7 +2273,7 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(AllocateUninitialized(old_space,
SubtypeTestCache::InstanceSize()));
@@ -2310,7 +2315,7 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kLanguageErrorCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawLanguageError* error = objects_[i];
s->AssignRef(error);
@@ -2345,7 +2350,7 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(AllocateUninitialized(old_space,
LanguageError::InstanceSize()));
@@ -2393,7 +2398,7 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kUnhandledExceptionCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawUnhandledException* exception = objects_[i];
s->AssignRef(exception);
@@ -2425,7 +2430,7 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(AllocateUninitialized(old_space,
UnhandledException::InstanceSize()));
@@ -2456,10 +2461,9 @@
public:
explicit InstanceSerializationCluster(intptr_t cid) : cid_(cid) {
RawClass* cls = Isolate::Current()->class_table()->At(cid);
- next_field_offset_ =
- cls->ptr()->next_field_offset_in_words_ << kWordSizeLog2;
+ next_field_offset_in_words_ = cls->ptr()->next_field_offset_in_words_;
instance_size_in_words_ = cls->ptr()->instance_size_in_words_;
- ASSERT(next_field_offset_ > 0);
+ ASSERT(next_field_offset_in_words_ > 0);
ASSERT(instance_size_in_words_ > 0);
}
virtual ~InstanceSerializationCluster() { }
@@ -2468,8 +2472,9 @@
RawInstance* instance = Instance::RawCast(object);
objects_.Add(instance);
+ intptr_t next_field_offset = next_field_offset_in_words_ << kWordSizeLog2;
intptr_t offset = Instance::NextFieldOffset();
- while (offset < next_field_offset_) {
+ while (offset < next_field_offset) {
RawObject* raw_obj = *reinterpret_cast<RawObject**>(
reinterpret_cast<uword>(instance->ptr()) + offset);
s->Push(raw_obj);
@@ -2478,12 +2483,12 @@
}
void WriteAlloc(Serializer* s) {
- s->Write<intptr_t>(cid_);
+ s->WriteCid(cid_);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
- s->Write<intptr_t>(next_field_offset_);
- s->Write<intptr_t>(instance_size_in_words_);
+ s->Write<int32_t>(next_field_offset_in_words_);
+ s->Write<int32_t>(instance_size_in_words_);
for (intptr_t i = 0; i < count; i++) {
RawInstance* instance = objects_[i];
@@ -2492,12 +2497,13 @@
}
void WriteFill(Serializer* s) {
+ intptr_t next_field_offset = next_field_offset_in_words_ << kWordSizeLog2;
intptr_t count = objects_.length();
for (intptr_t i = 0; i < count; i++) {
RawInstance* instance = objects_[i];
s->Write<bool>(instance->IsCanonical());
intptr_t offset = Instance::NextFieldOffset();
- while (offset < next_field_offset_) {
+ while (offset < next_field_offset) {
RawObject* raw_obj = *reinterpret_cast<RawObject**>(
reinterpret_cast<uword>(instance->ptr()) + offset);
s->WriteRef(raw_obj);
@@ -2508,7 +2514,7 @@
private:
const intptr_t cid_;
- intptr_t next_field_offset_;
+ intptr_t next_field_offset_in_words_;
intptr_t instance_size_in_words_;
GrowableArray<RawInstance*> objects_;
};
@@ -2522,9 +2528,9 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
- next_field_offset_ = d->Read<intptr_t>();
- instance_size_in_words_ = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
+ next_field_offset_in_words_ = d->Read<int32_t>();
+ instance_size_in_words_ = d->Read<int32_t>();
intptr_t instance_size =
Object::RoundedAllocationSize(instance_size_in_words_ * kWordSize);
for (intptr_t i = 0; i < count; i++) {
@@ -2534,6 +2540,7 @@
}
void ReadFill(Deserializer* d) {
+ intptr_t next_field_offset = next_field_offset_in_words_ << kWordSizeLog2;
intptr_t instance_size =
Object::RoundedAllocationSize(instance_size_in_words_ * kWordSize);
bool is_vm_object = d->isolate() == Dart::vm_isolate();
@@ -2545,7 +2552,7 @@
instance_size,
is_vm_object, is_canonical);
intptr_t offset = Instance::NextFieldOffset();
- while (offset < next_field_offset_) {
+ while (offset < next_field_offset) {
RawObject** p = reinterpret_cast<RawObject**>(
reinterpret_cast<uword>(instance->ptr()) + offset);
*p = d->ReadRef();
@@ -2563,7 +2570,7 @@
private:
const intptr_t cid_;
- intptr_t next_field_offset_;
+ intptr_t next_field_offset_in_words_;
intptr_t instance_size_in_words_;
};
@@ -2587,7 +2594,7 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kLibraryPrefixCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawLibraryPrefix* prefix = objects_[i];
s->AssignRef(prefix);
@@ -2622,7 +2629,7 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(AllocateUninitialized(old_space,
LibraryPrefix::InstanceSize()));
@@ -2680,13 +2687,13 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kTypeCid);
intptr_t count = canonical_objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawType* type = canonical_objects_[i];
s->AssignRef(type);
}
count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawType* type = objects_[i];
s->AssignRef(type);
@@ -2732,14 +2739,14 @@
void ReadAlloc(Deserializer* d) {
canonical_start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(AllocateUninitialized(old_space, Type::InstanceSize()));
}
canonical_stop_index_ = d->next_index();
start_index_ = d->next_index();
- count = d->Read<intptr_t>();
+ count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(AllocateUninitialized(old_space, Type::InstanceSize()));
}
@@ -2803,7 +2810,7 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kTypeRefCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawTypeRef* type = objects_[i];
s->AssignRef(type);
@@ -2835,7 +2842,7 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(AllocateUninitialized(old_space, TypeRef::InstanceSize()));
}
@@ -2879,7 +2886,7 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kTypeParameterCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawTypeParameter* type = objects_[i];
s->AssignRef(type);
@@ -2895,7 +2902,7 @@
for (RawObject** p = from; p <= to; p++) {
s->WriteRef(*p);
}
- s->Write<intptr_t>(type->ptr()->parameterized_class_id_);
+ s->Write<int32_t>(type->ptr()->parameterized_class_id_);
s->WriteTokenPosition(type->ptr()->token_pos_);
s->Write<int16_t>(type->ptr()->index_);
s->Write<int8_t>(type->ptr()->type_state_);
@@ -2915,7 +2922,7 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(AllocateUninitialized(old_space,
TypeParameter::InstanceSize()));
@@ -2936,7 +2943,7 @@
for (RawObject** p = from; p <= to; p++) {
*p = d->ReadRef();
}
- type->ptr()->parameterized_class_id_ = d->Read<intptr_t>();
+ type->ptr()->parameterized_class_id_ = d->Read<int32_t>();
type->ptr()->token_pos_ = d->ReadTokenPosition();
type->ptr()->index_ = d->Read<int16_t>();
type->ptr()->type_state_ = d->Read<int8_t>();
@@ -2964,7 +2971,7 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kBoundedTypeCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawBoundedType* type = objects_[i];
s->AssignRef(type);
@@ -2996,7 +3003,7 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(AllocateUninitialized(old_space,
BoundedType::InstanceSize()));
@@ -3040,7 +3047,7 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kClosureCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawClosure* closure = objects_[i];
s->AssignRef(closure);
@@ -3073,7 +3080,7 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(AllocateUninitialized(old_space, Closure::InstanceSize()));
}
@@ -3105,31 +3112,38 @@
virtual ~MintSerializationCluster() { }
void Trace(Serializer* s, RawObject* object) {
- RawMint* mint = Mint::RawCast(object);
- objects_.Add(mint);
+ if (!object->IsHeapObject()) {
+ RawSmi* smi = Smi::RawCast(object);
+ smis_.Add(smi);
+ } else {
+ RawMint* mint = Mint::RawCast(object);
+ mints_.Add(mint);
+ }
}
void WriteAlloc(Serializer* s) {
s->WriteCid(kMintCid);
- intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
- for (intptr_t i = 0; i < count; i++) {
- RawMint* mint = objects_[i];
+
+ s->Write<int32_t>(smis_.length() + mints_.length());
+ for (intptr_t i = 0; i < smis_.length(); i++) {
+ RawSmi* smi = smis_[i];
+ s->Write<bool>(true);
+ s->Write<int64_t>(Smi::Value(smi));
+ s->AssignRef(smi);
+ }
+ for (intptr_t i = 0; i < mints_.length(); i++) {
+ RawMint* mint = mints_[i];
+ s->Write<bool>(mint->IsCanonical());
+ s->Write<int64_t>(mint->ptr()->value_);
s->AssignRef(mint);
}
}
- void WriteFill(Serializer* s) {
- intptr_t count = objects_.length();
- for (intptr_t i = 0; i < count; i++) {
- RawMint* mint = objects_[i];
- s->Write<bool>(mint->IsCanonical());
- s->Write<int64_t>(mint->ptr()->value_);
- }
- }
+ void WriteFill(Serializer* s) { }
private:
- GrowableArray<RawMint*> objects_;
+ GrowableArray<RawSmi*> smis_;
+ GrowableArray<RawMint*> mints_;
};
@@ -3139,26 +3153,49 @@
virtual ~MintDeserializationCluster() { }
void ReadAlloc(Deserializer* d) {
- start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ bool is_vm_object = d->isolate() == Dart::vm_isolate();
+
+ start_index_ = d->next_index();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
- d->AssignRef(AllocateUninitialized(old_space, Mint::InstanceSize()));
+ bool is_canonical = d->Read<bool>();
+ int64_t value = d->Read<int64_t>();
+ if (Smi::IsValid(value)) {
+ d->AssignRef(Smi::New(value));
+ } else {
+ RawMint* mint = static_cast<RawMint*>(
+ AllocateUninitialized(old_space, Mint::InstanceSize()));
+ Deserializer::InitializeHeader(mint, kMintCid,
+ Mint::InstanceSize(),
+ is_vm_object, is_canonical);
+ mint->ptr()->value_ = value;
+ d->AssignRef(mint);
+ }
}
stop_index_ = d->next_index();
}
- void ReadFill(Deserializer* d) {
- bool is_vm_object = d->isolate() == Dart::vm_isolate();
+ void ReadFill(Deserializer* d) { }
- for (intptr_t id = start_index_; id < stop_index_; id++) {
- RawMint* mint = reinterpret_cast<RawMint*>(d->Ref(id));
- bool is_canonical = d->Read<bool>();
- Deserializer::InitializeHeader(mint, kMintCid,
- Mint::InstanceSize(),
- is_vm_object, is_canonical);
- mint->ptr()->value_ = d->Read<int64_t>();
+ void PostLoad(const Array& refs, Snapshot::Kind kind, Zone* zone) {
+ NOT_IN_PRODUCT(TimelineDurationScope tds(Thread::Current(),
+ Timeline::GetIsolateStream(), "PostLoadMint"));
+
+ const GrowableObjectArray& new_constants =
+ GrowableObjectArray::Handle(zone, GrowableObjectArray::New());
+ Object& number = Object::Handle(zone);
+ for (intptr_t i = start_index_; i < stop_index_; i++) {
+ number = refs.At(i);
+ if (number.IsMint() && number.IsCanonical()) {
+ new_constants.Add(number);
+ }
}
+ const Array& constants_array =
+ Array::Handle(zone, Array::MakeArray(new_constants));
+ const Class& mint_cls = Class::Handle(zone,
+ Isolate::Current()->object_store()->mint_class());
+ mint_cls.set_constants(constants_array);
}
};
@@ -3182,7 +3219,7 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kBigintCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawBigint* bigint = objects_[i];
s->AssignRef(bigint);
@@ -3215,7 +3252,7 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(AllocateUninitialized(old_space, Bigint::InstanceSize()));
}
@@ -3254,7 +3291,7 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kDoubleCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawDouble* dbl = objects_[i];
s->AssignRef(dbl);
@@ -3283,7 +3320,7 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(AllocateUninitialized(old_space, Double::InstanceSize()));
}
@@ -3324,7 +3361,7 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kGrowableObjectArrayCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawGrowableObjectArray* array = objects_[i];
s->AssignRef(array);
@@ -3358,7 +3395,7 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(AllocateUninitialized(old_space,
GrowableObjectArray::InstanceSize()));
@@ -3397,13 +3434,13 @@
}
void WriteAlloc(Serializer* s) {
- s->Write<intptr_t>(cid_);
+ s->WriteCid(cid_);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawTypedData* data = objects_[i];
intptr_t length = Smi::Value(data->ptr()->length_);
- s->Write<intptr_t>(length);
+ s->Write<int32_t>(length);
s->AssignRef(data);
}
}
@@ -3414,7 +3451,7 @@
for (intptr_t i = 0; i < count; i++) {
RawTypedData* data = objects_[i];
intptr_t length = Smi::Value(data->ptr()->length_);
- s->Write<intptr_t>(length);
+ s->Write<int32_t>(length);
s->Write<bool>(data->IsCanonical());
uint8_t* cdata = reinterpret_cast<uint8_t*>(data->ptr()->data());
s->WriteBytes(cdata, length * element_size);
@@ -3435,10 +3472,10 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
intptr_t element_size = TypedData::ElementSizeInBytes(cid_);
for (intptr_t i = 0; i < count; i++) {
- intptr_t length = d->Read<intptr_t>();
+ intptr_t length = d->Read<int32_t>();
d->AssignRef(AllocateUninitialized(old_space,
TypedData::InstanceSize(length * element_size)));
}
@@ -3451,7 +3488,7 @@
for (intptr_t id = start_index_; id < stop_index_; id++) {
RawTypedData* data = reinterpret_cast<RawTypedData*>(d->Ref(id));
- intptr_t length = d->Read<intptr_t>();
+ intptr_t length = d->Read<int32_t>();
bool is_canonical = d->Read<bool>();
intptr_t length_in_bytes = length * element_size;
Deserializer::InitializeHeader(data, cid_,
@@ -3480,9 +3517,9 @@
}
void WriteAlloc(Serializer* s) {
- s->Write<intptr_t>(cid_);
+ s->WriteCid(cid_);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawExternalTypedData* data = objects_[i];
s->AssignRef(data);
@@ -3495,7 +3532,7 @@
for (intptr_t i = 0; i < count; i++) {
RawExternalTypedData* data = objects_[i];
intptr_t length = Smi::Value(data->ptr()->length_);
- s->Write<intptr_t>(length);
+ s->Write<int32_t>(length);
uint8_t* cdata = reinterpret_cast<uint8_t*>(data->ptr()->data_);
s->WriteBytes(cdata, length * element_size);
}
@@ -3515,7 +3552,7 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(AllocateUninitialized(old_space,
ExternalTypedData::InstanceSize()));
@@ -3530,7 +3567,7 @@
for (intptr_t id = start_index_; id < stop_index_; id++) {
RawExternalTypedData* data =
reinterpret_cast<RawExternalTypedData*>(d->Ref(id));
- intptr_t length = d->Read<intptr_t>();
+ intptr_t length = d->Read<int32_t>();
Deserializer::InitializeHeader(data, cid_,
ExternalTypedData::InstanceSize(),
is_vm_object);
@@ -3564,7 +3601,7 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kStacktraceCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawStacktrace* trace = objects_[i];
s->AssignRef(trace);
@@ -3596,7 +3633,7 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(AllocateUninitialized(old_space,
Stacktrace::InstanceSize()));
@@ -3640,7 +3677,7 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kRegExpCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawRegExp* regexp = objects_[i];
s->AssignRef(regexp);
@@ -3657,7 +3694,7 @@
s->WriteRef(*p);
}
- s->Write<intptr_t>(regexp->ptr()->num_registers_);
+ s->Write<int32_t>(regexp->ptr()->num_registers_);
s->Write<int8_t>(regexp->ptr()->type_flags_);
}
}
@@ -3675,7 +3712,7 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(AllocateUninitialized(old_space,
RegExp::InstanceSize()));
@@ -3696,7 +3733,7 @@
*p = d->ReadRef();
}
- regexp->ptr()->num_registers_ = d->Read<intptr_t>();
+ regexp->ptr()->num_registers_ = d->Read<int32_t>();
regexp->ptr()->type_flags_ = d->Read<int8_t>();
}
}
@@ -3730,7 +3767,7 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kLinkedHashMapCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawLinkedHashMap* map = objects_[i];
s->AssignRef(map);
@@ -3750,7 +3787,7 @@
const intptr_t deleted_keys = Smi::Value(map->ptr()->deleted_keys_);
// Write out the number of (not deleted) key/value pairs that will follow.
- s->Write<intptr_t>((used_data >> 1) - deleted_keys);
+ s->Write<int32_t>((used_data >> 1) - deleted_keys);
RawArray* data_array = map->ptr()->data_;
RawObject** data_elements = data_array->ptr()->data();
@@ -3778,7 +3815,7 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
d->AssignRef(AllocateUninitialized(old_space,
LinkedHashMap::InstanceSize()));
@@ -3801,7 +3838,7 @@
reinterpret_cast<RawTypeArguments*>(d->ReadRef());
// TODO(rmacnak): Reserve ref ids and co-allocate in ReadAlloc.
- intptr_t pairs = d->Read<intptr_t>();
+ intptr_t pairs = d->Read<int32_t>();
intptr_t used_data = pairs << 1;
intptr_t data_size = Utils::Maximum(
Utils::RoundUpToPowerOfTwo(used_data),
@@ -3848,11 +3885,11 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(cid_);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawArray* array = objects_[i];
intptr_t length = Smi::Value(array->ptr()->length_);
- s->Write<intptr_t>(length);
+ s->Write<int32_t>(length);
s->AssignRef(array);
}
}
@@ -3862,7 +3899,7 @@
for (intptr_t i = 0; i < count; i++) {
RawArray* array = objects_[i];
intptr_t length = Smi::Value(array->ptr()->length_);
- s->Write<intptr_t>(length);
+ s->Write<int32_t>(length);
s->Write<bool>(array->IsCanonical());
s->WriteRef(array->ptr()->type_arguments_);
for (intptr_t j = 0; j < length; j++) {
@@ -3885,9 +3922,9 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
- intptr_t length = d->Read<intptr_t>();
+ intptr_t length = d->Read<int32_t>();
d->AssignRef(AllocateUninitialized(old_space,
Array::InstanceSize(length)));
}
@@ -3899,7 +3936,7 @@
for (intptr_t id = start_index_; id < stop_index_; id++) {
RawArray* array = reinterpret_cast<RawArray*>(d->Ref(id));
- intptr_t length = d->Read<intptr_t>();
+ intptr_t length = d->Read<int32_t>();
bool is_canonical = d->Read<bool>();
Deserializer::InitializeHeader(array, cid_,
Array::InstanceSize(length),
@@ -3931,11 +3968,11 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kOneByteStringCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawOneByteString* str = objects_[i];
intptr_t length = Smi::Value(str->ptr()->length_);
- s->Write<intptr_t>(length);
+ s->Write<int32_t>(length);
s->AssignRef(str);
}
}
@@ -3945,7 +3982,7 @@
for (intptr_t i = 0; i < count; i++) {
RawOneByteString* str = objects_[i];
intptr_t length = Smi::Value(str->ptr()->length_);
- s->Write<intptr_t>(length);
+ s->Write<int32_t>(length);
s->Write<bool>(str->IsCanonical());
intptr_t hash = Smi::Value(str->ptr()->hash_);
s->Write<int32_t>(hash);
@@ -3966,9 +4003,9 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
- intptr_t length = d->Read<intptr_t>();
+ intptr_t length = d->Read<int32_t>();
d->AssignRef(AllocateUninitialized(old_space,
OneByteString::InstanceSize(length)));
}
@@ -3980,13 +4017,13 @@
for (intptr_t id = start_index_; id < stop_index_; id++) {
RawOneByteString* str = reinterpret_cast<RawOneByteString*>(d->Ref(id));
- intptr_t length = d->Read<intptr_t>();
+ intptr_t length = d->Read<int32_t>();
bool is_canonical = d->Read<bool>();
Deserializer::InitializeHeader(str, kOneByteStringCid,
OneByteString::InstanceSize(length),
is_vm_object, is_canonical);
str->ptr()->length_ = Smi::New(length);
- str->ptr()->hash_ = Smi::New(d->Read<intptr_t>());
+ str->ptr()->hash_ = Smi::New(d->Read<int32_t>());
for (intptr_t j = 0; j < length; j++) {
str->ptr()->data()[j] = d->Read<uint8_t>();
}
@@ -4008,11 +4045,11 @@
void WriteAlloc(Serializer* s) {
s->WriteCid(kTwoByteStringCid);
intptr_t count = objects_.length();
- s->Write<intptr_t>(count);
+ s->Write<int32_t>(count);
for (intptr_t i = 0; i < count; i++) {
RawTwoByteString* str = objects_[i];
intptr_t length = Smi::Value(str->ptr()->length_);
- s->Write<intptr_t>(length);
+ s->Write<int32_t>(length);
s->AssignRef(str);
}
}
@@ -4022,7 +4059,7 @@
for (intptr_t i = 0; i < count; i++) {
RawTwoByteString* str = objects_[i];
intptr_t length = Smi::Value(str->ptr()->length_);
- s->Write<intptr_t>(length);
+ s->Write<int32_t>(length);
s->Write<bool>(str->IsCanonical());
intptr_t hash = Smi::Value(str->ptr()->hash_);
s->Write<int32_t>(hash);
@@ -4043,9 +4080,9 @@
void ReadAlloc(Deserializer* d) {
start_index_ = d->next_index();
PageSpace* old_space = d->heap()->old_space();
- intptr_t count = d->Read<intptr_t>();
+ intptr_t count = d->Read<int32_t>();
for (intptr_t i = 0; i < count; i++) {
- intptr_t length = d->Read<intptr_t>();
+ intptr_t length = d->Read<int32_t>();
d->AssignRef(AllocateUninitialized(old_space,
TwoByteString::InstanceSize(length)));
}
@@ -4058,7 +4095,7 @@
for (intptr_t id = start_index_; id < stop_index_; id++) {
RawTwoByteString* str =
reinterpret_cast<RawTwoByteString*>(d->Ref(id));
- intptr_t length = d->Read<intptr_t>();
+ intptr_t length = d->Read<int32_t>();
bool is_canonical = d->Read<bool>();
Deserializer::InitializeHeader(str, kTwoByteStringCid,
TwoByteString::InstanceSize(length),
@@ -4196,7 +4233,9 @@
void Serializer::Trace(RawObject* object) {
intptr_t cid;
if (!object->IsHeapObject()) {
- cid = kSmiCid;
+ // Smis are merged into the Mint cluster because Smis for the writer might
+ // become Mints for the reader and vice versa.
+ cid = kMintCid;
} else {
cid = object->GetClassId();
}
@@ -4227,7 +4266,7 @@
#if defined(DEBUG)
-static const intptr_t kSectionMarker = 0xABAB;
+static const int32_t kSectionMarker = 0xABAB;
#endif
void Serializer::Serialize() {
@@ -4244,6 +4283,11 @@
}
intptr_t num_objects = num_base_objects_ + num_written_objects_;
+#if defined(ARCH_IS_64_BIT)
+ if (!Utils::IsInt(32, num_objects)) {
+ FATAL("Ref overflow");
+ }
+#endif
Write<int32_t>(num_objects);
Write<int32_t>(num_clusters);
@@ -4253,7 +4297,7 @@
if (cluster != NULL) {
cluster->WriteAlloc(this);
#if defined(DEBUG)
- Write<intptr_t>(next_ref_index_);
+ Write<int32_t>(next_ref_index_);
#endif
}
}
@@ -4266,7 +4310,7 @@
if (cluster != NULL) {
cluster->WriteFill(this);
#if defined(DEBUG)
- Write<intptr_t>(kSectionMarker);
+ Write<int32_t>(kSectionMarker);
#endif
}
}
@@ -4336,7 +4380,7 @@
}
#if defined(DEBUG)
- Write<intptr_t>(kSectionMarker);
+ Write<int32_t>(kSectionMarker);
#endif
// Note we are not clearing the object id table. The full ref table
@@ -4379,7 +4423,7 @@
}
#if defined(DEBUG)
- Write<intptr_t>(kSectionMarker);
+ Write<int32_t>(kSectionMarker);
#endif
heap_->ResetObjectIdTable();
@@ -4599,7 +4643,7 @@
clusters_[i] = ReadCluster();
clusters_[i]->ReadAlloc(this);
#if defined(DEBUG)
- intptr_t serializers_next_ref_index_ = Read<intptr_t>();
+ intptr_t serializers_next_ref_index_ = Read<int32_t>();
ASSERT(serializers_next_ref_index_ == next_ref_index_);
#endif
}
@@ -4614,7 +4658,7 @@
for (intptr_t i = 0; i < num_clusters_; i++) {
clusters_[i]->ReadFill(this);
#if defined(DEBUG)
- intptr_t section_marker = Read<intptr_t>();
+ int32_t section_marker = Read<int32_t>();
ASSERT(section_marker == kSectionMarker);
#endif
}
@@ -4698,7 +4742,7 @@
}
#if defined(DEBUG)
- intptr_t section_marker = Read<intptr_t>();
+ int32_t section_marker = Read<int32_t>();
ASSERT(section_marker == kSectionMarker);
#endif
@@ -4739,7 +4783,7 @@
}
#if defined(DEBUG)
- intptr_t section_marker = Read<intptr_t>();
+ int32_t section_marker = Read<int32_t>();
ASSERT(section_marker == kSectionMarker);
#endif
@@ -4766,27 +4810,27 @@
}
-// 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
-// objects and their accompanying token streams.
-class ScriptVisitor : public ObjectVisitor {
+// An object visitor which will iterate over all the token stream 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 token streams so
+// they will be shared across all isolates.
+class SnapshotTokenStreamVisitor : public ObjectVisitor {
public:
- explicit ScriptVisitor(Thread* thread) :
+ explicit SnapshotTokenStreamVisitor(Thread* thread) :
objHandle_(Object::Handle(thread->zone())),
count_(0),
- scripts_(NULL) {}
+ token_streams_(NULL) {}
- ScriptVisitor(Thread* thread, const Array* scripts) :
+ SnapshotTokenStreamVisitor(Thread* thread, const Array* token_streams) :
objHandle_(Object::Handle(thread->zone())),
count_(0),
- scripts_(scripts) {}
+ token_streams_(token_streams) {}
void VisitObject(RawObject* obj) {
- if (obj->IsScript()) {
- if (scripts_ != NULL) {
+ if (obj->IsTokenStream()) {
+ if (token_streams_ != NULL) {
objHandle_ = obj;
- scripts_->SetAt(count_, objHandle_);
+ token_streams_->SetAt(count_, objHandle_);
}
count_ += 1;
}
@@ -4797,7 +4841,7 @@
private:
Object& objHandle_;
intptr_t count_;
- const Array* scripts_;
+ const Array* token_streams_;
};
@@ -4814,7 +4858,7 @@
vm_isolate_snapshot_size_(0),
isolate_snapshot_size_(0),
instructions_writer_(instructions_writer),
- scripts_(Array::Handle(zone())),
+ token_streams_(Array::Handle(zone())),
saved_symbol_table_(Array::Handle(zone())),
new_vm_symbol_table_(Array::Handle(zone())) {
ASSERT(isolate_snapshot_buffer_ != NULL);
@@ -4837,16 +4881,16 @@
NOT_IN_PRODUCT(TimelineDurationScope tds(thread(),
Timeline::GetIsolateStream(), "PrepareNewVMIsolate"));
- // Collect all the script objects and their accompanying token stream
- // objects into an array so that we can write it out as part of the VM
- // isolate snapshot. We first count the number of script objects, allocate
- // an array and then fill it up with the script objects.
- ScriptVisitor scripts_counter(thread());
- heap()->IterateOldObjects(&scripts_counter);
- Dart::vm_isolate()->heap()->IterateOldObjects(&scripts_counter);
- intptr_t count = scripts_counter.count();
- scripts_ = Array::New(count, Heap::kOld);
- ScriptVisitor script_visitor(thread(), &scripts_);
+ // Collect all the token stream objects into an array so that we can write
+ // it out as part of the VM isolate snapshot. We first count the number of
+ // token streams, allocate an array and then fill it up with the token
+ // streams.
+ SnapshotTokenStreamVisitor token_streams_counter(thread());
+ heap()->IterateOldObjects(&token_streams_counter);
+ Dart::vm_isolate()->heap()->IterateOldObjects(&token_streams_counter);
+ intptr_t count = token_streams_counter.count();
+ token_streams_ = Array::New(count, Heap::kOld);
+ SnapshotTokenStreamVisitor script_visitor(thread(), &token_streams_);
heap()->IterateOldObjects(&script_visitor);
Dart::vm_isolate()->heap()->IterateOldObjects(&script_visitor);
ASSERT(script_visitor.count() == count);
@@ -4873,7 +4917,7 @@
saved_symbol_table_ = Array::null();
}
new_vm_symbol_table_ = Array::null();
- scripts_ = Array::null();
+ token_streams_ = Array::null();
}
@@ -4894,11 +4938,11 @@
/*
* Now Write out the following
* - the symbol table
- * - all the scripts and token streams for these scripts
+ * - all the token streams
* - the stub code (precompiled snapshots only)
**/
intptr_t num_objects = serializer.WriteVMSnapshot(new_vm_symbol_table_,
- scripts_);
+ token_streams_);
serializer.FillHeader(serializer.kind());
vm_isolate_snapshot_size_ = serializer.bytes_written();
diff --git a/runtime/vm/clustered_snapshot.h b/runtime/vm/clustered_snapshot.h
index b2bdd0c..aae4e82 100644
--- a/runtime/vm/clustered_snapshot.h
+++ b/runtime/vm/clustered_snapshot.h
@@ -12,6 +12,7 @@
#include "vm/exceptions.h"
#include "vm/globals.h"
#include "vm/growable_array.h"
+#include "vm/hash_map.h"
#include "vm/heap.h"
#include "vm/isolate.h"
#include "vm/object.h"
@@ -83,15 +84,34 @@
};
-enum {
- kRefTagSize = 1,
- kRefTagShift = 1,
- kRefTagMask = 1,
- kSmiRefTag = 0x0,
- kHeapRefTag = 0x1,
+class SmiObjectIdPair {
+ public:
+ SmiObjectIdPair() : smi_(NULL), id_(0) { }
+ RawSmi* smi_;
+ intptr_t id_;
+
+ bool operator==(const SmiObjectIdPair& other) const {
+ return (smi_ == other.smi_) && (id_ == other.id_);
+ }
};
+class SmiObjectIdPairTrait {
+ public:
+ typedef RawSmi* Key;
+ typedef intptr_t Value;
+ typedef SmiObjectIdPair Pair;
+
+ static Key KeyOf(Pair kv) { return kv.smi_; }
+ static Value ValueOf(Pair kv) { return kv.id_; }
+ static inline intptr_t Hashcode(Key key) { return Smi::Value(key); }
+ static inline bool IsKeyEqual(Pair kv, Key key) { return kv.smi_ == key; }
+};
+
+
+typedef DirectChainedHashMap<SmiObjectIdPairTrait> SmiObjectIdMap;
+
+
class Serializer : public StackResource {
public:
Serializer(Thread* thread,
@@ -114,13 +134,36 @@
void AssignRef(RawObject* object) {
ASSERT(next_ref_index_ != 0);
- heap_->SetObjectId(object, next_ref_index_);
- ASSERT(heap_->GetObjectId(object) == next_ref_index_);
+ if (object->IsHeapObject()) {
+ heap_->SetObjectId(object, next_ref_index_);
+ ASSERT(heap_->GetObjectId(object) == next_ref_index_);
+ } else {
+ RawSmi* smi = Smi::RawCast(object);
+ SmiObjectIdPair* existing_pair = smi_ids_.Lookup(smi);
+ if (existing_pair != NULL) {
+ ASSERT(existing_pair->id_ == 1);
+ existing_pair->id_ = next_ref_index_;
+ } else {
+ SmiObjectIdPair new_pair;
+ new_pair.smi_ = smi;
+ new_pair.id_ = next_ref_index_;
+ smi_ids_.Insert(new_pair);
+ }
+ }
next_ref_index_++;
}
void Push(RawObject* object) {
if (!object->IsHeapObject()) {
+ RawSmi* smi = Smi::RawCast(object);
+ if (smi_ids_.Lookup(smi) == NULL) {
+ SmiObjectIdPair pair;
+ pair.smi_ = smi;
+ pair.id_ = 1;
+ smi_ids_.Insert(pair);
+ stack_.Add(object);
+ num_written_objects_++;
+ }
return;
}
@@ -180,9 +223,12 @@
void WriteRef(RawObject* object) {
if (!object->IsHeapObject()) {
- ASSERT(static_cast<intptr_t>(kSmiRefTag) ==
- static_cast<intptr_t>(kSmiTag));
- Write<intptr_t>(reinterpret_cast<intptr_t>(object));
+ RawSmi* smi = Smi::RawCast(object);
+ intptr_t id = smi_ids_.Lookup(smi)->id_;
+ if (id == 0) {
+ FATAL("Missing ref");
+ }
+ Write<int32_t>(id);
return;
}
@@ -200,7 +246,7 @@
}
FATAL("Missing ref");
}
- Write<intptr_t>((id << kRefTagShift) | kHeapRefTag);
+ Write<int32_t>(id);
}
void WriteTokenPosition(TokenPosition pos) {
@@ -234,6 +280,7 @@
intptr_t num_base_objects_;
intptr_t num_written_objects_;
intptr_t next_ref_index_;
+ SmiObjectIdMap smi_ids_;
DISALLOW_IMPLICIT_CONSTRUCTORS(Serializer);
};
@@ -300,13 +347,8 @@
}
RawObject* ReadRef() {
- intptr_t index = Read<intptr_t>();
- if ((index & kRefTagMask) == kSmiRefTag) {
- ASSERT(static_cast<intptr_t>(kSmiRefTag) ==
- static_cast<intptr_t>(kSmiTag));
- return reinterpret_cast<RawSmi*>(index);
- }
- return Ref(index >> kRefTagShift);
+ int32_t index = Read<int32_t>();
+ return Ref(index);
}
TokenPosition ReadTokenPosition() {
@@ -400,7 +442,7 @@
intptr_t isolate_snapshot_size_;
ForwardList* forward_list_;
InstructionsWriter* instructions_writer_;
- Array& scripts_;
+ Array& token_streams_;
Array& saved_symbol_table_;
Array& new_vm_symbol_table_;
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index 4b572a7..ea33dae 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -91,6 +91,35 @@
}
+DEFINE_RUNTIME_ENTRY(RangeError, 2) {
+ const Instance& length = Instance::CheckedHandle(arguments.ArgAt(0));
+ const Instance& index = Instance::CheckedHandle(arguments.ArgAt(1));
+ if (!length.IsInteger()) {
+ // Throw: new ArgumentError.value(length, "length", "is not an integer");
+ const Array& args = Array::Handle(Array::New(3));
+ args.SetAt(0, length);
+ args.SetAt(1, Symbols::Length());
+ args.SetAt(2, String::Handle(String::New("is not an integer")));
+ Exceptions::ThrowByType(Exceptions::kArgumentValue, args);
+ }
+ if (!index.IsInteger()) {
+ // Throw: new ArgumentError.value(index, "index", "is not an integer");
+ const Array& args = Array::Handle(Array::New(3));
+ args.SetAt(0, index);
+ args.SetAt(1, Symbols::Index());
+ args.SetAt(2, String::Handle(String::New("is not an integer")));
+ Exceptions::ThrowByType(Exceptions::kArgumentValue, args);
+ }
+ // Throw: new RangeError.range(index, 0, length, "length");
+ const Array& args = Array::Handle(Array::New(4));
+ args.SetAt(0, index);
+ args.SetAt(1, Integer::Handle(Integer::New(0)));
+ args.SetAt(2, length);
+ args.SetAt(3, Symbols::Length());
+ Exceptions::ThrowByType(Exceptions::kRange, args);
+}
+
+
// Allocation of a fixed length array of given element type.
// This runtime entry is never called for allocating a List of a generic type,
// because a prior run time call instantiates the element type if necessary.
@@ -782,6 +811,25 @@
return result.raw();
}
+
+// Perform the subtype and return constant function based on the result.
+static RawFunction* ComputeTypeCheckTarget(const Instance& receiver,
+ const AbstractType& type,
+ const ArgumentsDescriptor& desc) {
+ const TypeArguments& checked_type_arguments = TypeArguments::Handle();
+ Error& error = Error::Handle();
+ bool result = receiver.IsInstanceOf(type, checked_type_arguments, &error);
+ ASSERT(error.IsNull());
+ ObjectStore* store = Isolate::Current()->object_store();
+ const Function& target
+ = Function::Handle(result
+ ? store->simple_instance_of_true_function()
+ : store->simple_instance_of_false_function());
+ ASSERT(!target.IsNull());
+ return target.raw();;
+}
+
+
static RawFunction* InlineCacheMissHandler(
const GrowableArray<const Instance*>& args,
const ICData& ic_data) {
@@ -790,8 +838,17 @@
arguments_descriptor(Array::Handle(ic_data.arguments_descriptor()));
String& function_name = String::Handle(ic_data.target_name());
ASSERT(function_name.IsSymbol());
+
Function& target_function = Function::Handle(
Resolver::ResolveDynamic(receiver, function_name, arguments_descriptor));
+
+ ObjectStore* store = Isolate::Current()->object_store();
+ if (target_function.raw() == store->simple_instance_of_function()) {
+ // Replace the target function with constant function.
+ const AbstractType& type = AbstractType::Cast(*args[1]);
+ target_function
+ = ComputeTypeCheckTarget(receiver, type, arguments_descriptor);
+ }
if (target_function.IsNull()) {
if (FLAG_trace_ic) {
OS::PrintErr("InlineCacheMissHandler NULL function for %s receiver: %s\n",
@@ -1242,9 +1299,11 @@
bool do_deopt = false;
bool do_stacktrace = false;
bool do_reload = false;
+ const intptr_t isolate_reload_every =
+ isolate->reload_every_n_stack_overflow_checks();
if ((FLAG_deoptimize_every > 0) ||
(FLAG_stacktrace_every > 0) ||
- (FLAG_reload_every > 0)) {
+ (isolate_reload_every > 0)) {
// TODO(turnidge): To make --deoptimize_every and
// --stacktrace-every faster we could move this increment/test to
// the generated code.
@@ -1257,14 +1316,14 @@
(count % FLAG_stacktrace_every) == 0) {
do_stacktrace = true;
}
- if ((FLAG_reload_every > 0) &&
- (count % FLAG_reload_every) == 0) {
+ if ((isolate_reload_every > 0) &&
+ (count % isolate_reload_every) == 0) {
do_reload = isolate->CanReload();
}
}
if ((FLAG_deoptimize_filter != NULL) ||
(FLAG_stacktrace_filter != NULL) ||
- FLAG_reload_every_optimized) {
+ FLAG_reload_every_optimized) {
DartFrameIterator iterator;
StackFrame* frame = iterator.NextFrame();
ASSERT(frame != NULL);
@@ -1297,10 +1356,16 @@
DeoptimizeFunctionsOnStack();
}
if (do_reload) {
- if (FLAG_reload_every_back_off) {
- FLAG_reload_every *= 2;
+#ifndef PRODUCT
+ // Maybe adjust the rate of future reloads.
+ isolate->MaybeIncreaseReloadEveryNStackOverflowChecks();
+ // Issue a reload.
+ isolate->ReloadSources();
+ const Error& error = Error::Handle(isolate->sticky_reload_error());
+ if (!error.IsNull()) {
+ FATAL1("*** Isolate reload failed: %s\n", error.ToErrorCString());
}
- NOT_IN_PRODUCT(isolate->ReloadSources();)
+#endif
}
if (FLAG_support_debugger && do_stacktrace) {
String& var_name = String::Handle();
@@ -1317,6 +1382,10 @@
intptr_t num_frames = stack->Length();
for (intptr_t i = 0; i < num_frames; i++) {
ActivationFrame* frame = stack->FrameAt(i);
+#ifndef DART_PRECOMPILED_RUNTIME
+ // Ensure that we have unoptimized code.
+ frame->function().EnsureHasCompiledUnoptimizedCode();
+#endif
// Variable locations and number are unknown when precompiling.
const int num_vars =
FLAG_precompiled_runtime ? 0 : frame->NumLocalVariables();
@@ -1341,8 +1410,16 @@
ASSERT(frame != NULL);
const Code& code = Code::ZoneHandle(frame->LookupDartCode());
ASSERT(!code.IsNull());
+ ASSERT(!code.is_optimized());
const Function& function = Function::Handle(code.function());
ASSERT(!function.IsNull());
+
+ // If the code of the frame does not match the function's unoptimized code,
+ // we bail out since the code was reset by an isolate reload.
+ if (code.raw() != function.unoptimized_code()) {
+ return;
+ }
+
// Since the code is referenced from the frame and the ZoneHandle,
// it cannot have been removed from the function.
ASSERT(function.HasCode());
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index cc3b691..1bc179c 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -1167,8 +1167,10 @@
done = true;
}
- // Clear the error if it was not a real error, but just a bailout.
- if (error.IsLanguageError() &&
+ // If is is not a background compilation, clear the error if it was not a
+ // real error, but just a bailout. If we're it a background compilation
+ // this will be dealt with in the caller.
+ if (!Compiler::IsBackgroundCompilation() && error.IsLanguageError() &&
(LanguageError::Cast(error).kind() == Report::kBailout)) {
thread()->clear_sticky_error();
}
@@ -1277,6 +1279,21 @@
THR_Print("Aborted background compilation: %s\n",
function.ToFullyQualifiedCString());
}
+ {
+ // If it was a bailout, then disable optimization.
+ Error& error = Error::Handle();
+ // We got an error during compilation.
+ error = thread->sticky_error();
+ thread->clear_sticky_error();
+ if (error.IsLanguageError() &&
+ LanguageError::Cast(error).kind() == Report::kBailout) {
+ if (FLAG_trace_compiler) {
+ THR_Print("--> disabling optimizations for '%s'\n",
+ function.ToFullyQualifiedCString());
+ }
+ function.SetIsOptimizable(false);
+ }
+ }
return Error::null();
}
// Optimizer bailed out. Disable optimizations and never try again.
@@ -1295,6 +1312,7 @@
// We got an error during compilation.
error = thread->sticky_error();
thread->clear_sticky_error();
+ // The non-optimizing compiler should not bail out.
ASSERT(error.IsLanguageError() &&
LanguageError::Cast(error).kind() != Report::kBailout);
return error.raw();
@@ -1870,8 +1888,9 @@
function = Function::null();
} else {
qelem = function_queue()->Remove();
- if (FLAG_stress_test_background_compilation) {
- const Function& old = Function::Handle(qelem->Function());
+ const Function& old = Function::Handle(qelem->Function());
+ if ((!old.HasOptimizedCode() && old.IsOptimizable()) ||
+ FLAG_stress_test_background_compilation) {
if (Compiler::CanOptimizeFunction(thread, old)) {
QueueElement* repeat_qelem = new QueueElement(old);
function_queue()->Add(repeat_qelem);
diff --git a/runtime/vm/constant_propagator.cc b/runtime/vm/constant_propagator.cc
index 6b97f7d..1f5290d 100644
--- a/runtime/vm/constant_propagator.cc
+++ b/runtime/vm/constant_propagator.cc
@@ -253,6 +253,10 @@
void ConstantPropagator::VisitCheckSmi(CheckSmiInstr* instr) { }
+void ConstantPropagator::VisitGenericCheckBound(GenericCheckBoundInstr* instr) {
+}
+
+
void ConstantPropagator::VisitCheckEitherNonSmi(
CheckEitherNonSmiInstr* instr) { }
diff --git a/runtime/vm/constants_dbc.h b/runtime/vm/constants_dbc.h
index 5d901b8..e84ae57 100644
--- a/runtime/vm/constants_dbc.h
+++ b/runtime/vm/constants_dbc.h
@@ -148,6 +148,11 @@
// Invoke function in SP[0] with arguments SP[-(1+ArgC)], ..., SP[-1] and
// argument descriptor PP[D].
//
+// - IndirectStaticCall ArgC, D
+//
+// Invoke the function given by the ICData in SP[0] with arguments
+// SP[-(1+ArgC)], ..., SP[-1] and argument descriptor PP[D].
+//
// - InstanceCall<N> ArgC, D; InstanceCall<N>Opt ArgC, D
//
// Lookup and invoke method with N checked arguments using ICData in PP[D]
@@ -183,11 +188,29 @@
// the immediately following instruction is skipped. These instructions
// expect their operands to be Smis, but don't check that they are.
//
+// - ShrImm rA, rB, rC
+//
+// FP[rA] <- FP[rB] >> rC. Shifts the Smi in FP[rB] right by rC. rC is
+// assumed to be a legal positive number by which righ-shifting is possible.
+//
+// - Min, Max rA, rB, rC
+//
+// FP[rA] <- {min, max}(FP[rB], FP[rC]). Assumes that FP[rB], and FP[rC] are
+// Smis.
+//
// - Neg rA , rD
//
// FP[rA] <- -FP[rD]. Assumes FP[rD] is a Smi. If there is no overflow the
// immediately following instruction is skipped.
//
+// - DMin, DMax, DAdd, DSub, DMul, DDiv, DPow, DMod rA, rB, rC
+//
+// Arithmetic operaions on unboxed doubles. FP[rA] <- FP[rB] op FP[rC].
+//
+// - DNeg, DCos, DSin, DSqrt rA, rD
+//
+// FP[rA] <- op(FP[rD]). Assumes FP[rD] is an unboxed double.
+//
// - BitOr, BitAnd, BitXor rA, rB, rC
//
// FP[rA] <- FP[rB] op FP[rC]. These instructions expect their operands to be
@@ -197,6 +220,30 @@
//
// FP[rA] <- ~FP[rD]. As above, assumes FP[rD] is a Smi.
//
+// - WriteIntoDouble rA, rD
+//
+// Box the double in FP[rD] with the result in FP[rA].
+//
+// - UnboxDouble rA, rD
+//
+// Unbox the double in FP[rD] into FP[rA]. Assumes FP[rD] is a double.
+//
+// - CheckedUnboxDouble rA, rD
+//
+// Unboxes FP[rD] into FP[rA] and skips the following instruction unless
+// FP[rD] is not a double or a Smi. When FP[rD] is a Smi, converts it to a
+// double.
+//
+// - SmiToDouble rA, rD
+//
+// Convert the Smi in FP[rD] to an unboxed double in FP[rA].
+//
+// - DoubleToSmi rA, rD
+//
+// If the unboxed double in FP[rD] can be converted to a Smi in FP[rA], then
+// this instruction does so, and skips the following instruction. Otherwise,
+// the following instruction is not skipped.
+//
// - StoreStaticT`OS D
//
// Stores TOS into the static field PP[D].
@@ -228,6 +275,13 @@
// Cond is Eq or Ne. Skips the next instruction unless the given condition
// holds.
//
+// - If<Cond> rA, rD
+//
+// Cond is Le, Lt, Ge, Gt, unsigned variants ULe, ULt, UGe, UGt, and
+// unboxed double variants DEq, DNe, DLe, DLt, DGe, DGt.
+// Skips the next instruction unless FP[rA] <Cond> FP[rD]. Assumes that
+// FP[rA] and FP[rD] are Smis or unboxed doubles as inidcated by <Cond>.
+//
// - CreateArrayTOS
//
// Allocate array of length SP[0] with type arguments SP[-1].
@@ -247,8 +301,23 @@
//
// - StoreIndexed rA, rB, rC
//
-// Store rC into array rA at index rB. No typechecking is done.
-// rA is assumed to be a RawArray, rB to be a smi.
+// Store FP[rC] into array FP[rA] at index FP[rB]. No typechecking is done.
+// FP[rA] is assumed to be a RawArray, FP[rB] to be a smi.
+//
+// - StoreFloat64Indexed rA, rB, rC
+//
+// Store the unboxed double in FP[rC] into the typed data array at FP[rA]
+// at index FP[rB].
+//
+// - LoadIndexed rA, rB, rC
+//
+// Loads from array FP[rB] at index FP[rC] into FP[rA]. No typechecking is
+// done. FP[rB] is assumed to be a RawArray, and to contain a Smi at FP[rC].
+//
+// - Load{Float64, OneByteString, TwoByteString}Indexed rA, rB, rC
+//
+// Loads from typed data array FP[rB] at index FP[rC] into an unboxed double,
+// or tagged Smi in FP[rA] as indicated by the type in the name.
//
// - StoreField rA, B, rC
//
@@ -376,13 +445,24 @@
// If FP[rA] & FP[rD] != 0, then skip the next instruction. FP[rA] and FP[rD]
// must be Smis.
//
+// - TestCids rA, D
+//
+// The next D instructions must be Nops whose D field encodes a class id. If
+// the class id of FP[rA] matches, jump to PC + N + 1 if the matching Nop's
+// A != 0 or PC + N + 2 if the matching Nop's A = 0. If no match is found,
+// jump to PC + N.
+//
// - CheckSmi rA
//
// If FP[rA] is a Smi, then skip the next instruction.
//
+// - CheckEitherNonSmi rA, rD
+//
+// If either FP[rA] or FP[rD] is not a Smi, then skip the next instruction.
+//
// - CheckClassId rA, D
//
-// If the object at FP[rA]'s class id matches the class id D, then skip the
+// If the class id in FP[rA] matches the class id D, then skip the
// following instruction.
//
// - CheckDenseSwitch rA, D
@@ -455,12 +535,12 @@
// tgt jump target relative to the PC of the current instruction
//
// TODO(vegorov) jump targets should be encoded relative to PC of the next
-// instruction because PC is incremeted immediately after fetch
+// instruction because PC is incremented immediately after fetch
// and before decoding.
//
#define BYTECODES_LIST(V) \
V(Trap, 0, ___, ___, ___) \
- V(Nop, D, lit, ___, ___) \
+ V(Nop, A_D, num, lit, ___) \
V(Compile, 0, ___, ___, ___) \
V(HotCheck, A_D, num, num, ___) \
V(Intrinsic, A, num, ___, ___) \
@@ -479,6 +559,7 @@
V(PushConstant, D, lit, ___, ___) \
V(StoreLocal, X, xeg, ___, ___) \
V(PopLocal, X, xeg, ___, ___) \
+ V(IndirectStaticCall, A_D, num, num, ___) \
V(StaticCall, A_D, num, num, ___) \
V(InstanceCall1, A_D, num, num, ___) \
V(InstanceCall2, A_D, num, num, ___) \
@@ -503,11 +584,31 @@
V(Mod, A_B_C, reg, reg, reg) \
V(Shl, A_B_C, reg, reg, reg) \
V(Shr, A_B_C, reg, reg, reg) \
+ V(ShrImm, A_B_C, reg, reg, num) \
V(Neg, A_D, reg, reg, ___) \
V(BitOr, A_B_C, reg, reg, reg) \
V(BitAnd, A_B_C, reg, reg, reg) \
V(BitXor, A_B_C, reg, reg, reg) \
V(BitNot, A_D, reg, reg, ___) \
+ V(Min, A_B_C, reg, reg, reg) \
+ V(Max, A_B_C, reg, reg, reg) \
+ V(WriteIntoDouble, A_D, reg, reg, ___) \
+ V(UnboxDouble, A_D, reg, reg, ___) \
+ V(CheckedUnboxDouble, A_D, reg, reg, ___) \
+ V(SmiToDouble, A_D, reg, reg, ___) \
+ V(DoubleToSmi, A_D, reg, reg, ___) \
+ V(DAdd, A_B_C, reg, reg, reg) \
+ V(DSub, A_B_C, reg, reg, reg) \
+ V(DMul, A_B_C, reg, reg, reg) \
+ V(DDiv, A_B_C, reg, reg, reg) \
+ V(DNeg, A_D, reg, reg, ___) \
+ V(DSqrt, A_D, reg, reg, ___) \
+ V(DMin, A_B_C, reg, reg, reg) \
+ V(DMax, A_B_C, reg, reg, reg) \
+ V(DCos, A_D, reg, reg, ___) \
+ V(DSin, A_D, reg, reg, ___) \
+ V(DPow, A_B_C, reg, reg, reg) \
+ V(DMod, A_B_C, reg, reg, reg) \
V(StoreStaticTOS, D, lit, ___, ___) \
V(PushStatic, D, lit, ___, ___) \
V(InitStaticTOS, 0, ___, ___, ___) \
@@ -517,6 +618,20 @@
V(IfEqStrictNumTOS, 0, ___, ___, ___) \
V(IfNeStrict, A_D, reg, reg, ___) \
V(IfEqStrict, A_D, reg, reg, ___) \
+ V(IfLe, A_D, reg, reg, ___) \
+ V(IfLt, A_D, reg, reg, ___) \
+ V(IfGe, A_D, reg, reg, ___) \
+ V(IfGt, A_D, reg, reg, ___) \
+ V(IfULe, A_D, reg, reg, ___) \
+ V(IfULt, A_D, reg, reg, ___) \
+ V(IfUGe, A_D, reg, reg, ___) \
+ V(IfUGt, A_D, reg, reg, ___) \
+ V(IfDNe, A_D, reg, reg, ___) \
+ V(IfDEq, A_D, reg, reg, ___) \
+ V(IfDLe, A_D, reg, reg, ___) \
+ V(IfDLt, A_D, reg, reg, ___) \
+ V(IfDGe, A_D, reg, reg, ___) \
+ V(IfDGt, A_D, reg, reg, ___) \
V(IfNeStrictNum, A_D, reg, reg, ___) \
V(IfEqStrictNum, A_D, reg, reg, ___) \
V(IfEqNull, A, reg, ___, ___) \
@@ -526,6 +641,11 @@
V(AllocateT, 0, ___, ___, ___) \
V(StoreIndexedTOS, 0, ___, ___, ___) \
V(StoreIndexed, A_B_C, reg, reg, reg) \
+ V(StoreFloat64Indexed, A_B_C, reg, reg, reg) \
+ V(LoadIndexed, A_B_C, reg, reg, reg) \
+ V(LoadFloat64Indexed, A_B_C, reg, reg, reg) \
+ V(LoadOneByteStringIndexed, A_B_C, reg, reg, reg) \
+ V(LoadTwoByteStringIndexed, A_B_C, reg, reg, reg) \
V(StoreField, A_B_C, reg, num, reg) \
V(StoreFieldTOS, D, num, ___, ___) \
V(LoadField, A_B_C, reg, reg, num) \
@@ -547,7 +667,9 @@
V(AssertAssignable, D, num, lit, ___) \
V(AssertBoolean, A, num, ___, ___) \
V(TestSmi, A_D, reg, reg, ___) \
+ V(TestCids, A_D, reg, num, ___) \
V(CheckSmi, A, reg, ___, ___) \
+ V(CheckEitherNonSmi, A_D, reg, reg, ___) \
V(CheckClassId, A_D, reg, num, ___) \
V(CheckDenseSwitch, A_D, reg, num, ___) \
V(CheckCids, A_B_C, reg, num, ___) \
@@ -619,6 +741,7 @@
DART_FORCE_INLINE static bool IsCallOpcode(Instr instr) {
switch (DecodeOpcode(instr)) {
case Bytecode::kStaticCall:
+ case Bytecode::kIndirectStaticCall:
case Bytecode::kInstanceCall1:
case Bytecode::kInstanceCall2:
case Bytecode::kInstanceCall1Opt:
@@ -650,7 +773,7 @@
const int16_t FPREG = 0;
const int16_t SPREG = 1;
-const intptr_t kNumberOfCpuRegisters = 20;
+const intptr_t kNumberOfCpuRegisters = 32;
const intptr_t kDartAvailableCpuRegs = -1;
const intptr_t kNoRegister = -1;
const intptr_t kReservedCpuRegisters = 0;
diff --git a/runtime/vm/cpuinfo_fuchsia.cc b/runtime/vm/cpuinfo_fuchsia.cc
index 04fe196..ad9e990 100644
--- a/runtime/vm/cpuinfo_fuchsia.cc
+++ b/runtime/vm/cpuinfo_fuchsia.cc
@@ -8,8 +8,7 @@
#include "vm/cpuinfo.h"
#include "platform/assert.h"
-
-// TODO(zra): Use "vm/cpuid.h"
+#include "vm/cpuid.h"
namespace dart {
@@ -17,30 +16,55 @@
const char* CpuInfo::fields_[kCpuInfoMax] = {0};
void CpuInfo::InitOnce() {
- UNIMPLEMENTED();
+ // TODO(zra): Add support for HOST_ARCH_ARM64
+#if defined(HOST_ARCH_IA32) || defined(HOST_ARCH_X64)
+ method_ = kCpuInfoCpuId;
+
+ // Initialize the CpuId information.
+ CpuId::InitOnce();
+
+ fields_[kCpuInfoProcessor] = "Processor";
+ fields_[kCpuInfoModel] = "Hardware";
+ fields_[kCpuInfoHardware] = "Hardware";
+ fields_[kCpuInfoFeatures] = "Features";
+#endif
}
void CpuInfo::Cleanup() {
- UNIMPLEMENTED();
+ if (method_ == kCpuInfoCpuId) {
+ CpuId::Cleanup();
+ }
}
bool CpuInfo::FieldContains(CpuInfoIndices idx, const char* search_string) {
- UNIMPLEMENTED();
- return false;
+ if (method_ == kCpuInfoCpuId) {
+ return strstr(CpuId::field(idx), search_string);
+ } else {
+ return false;
+ }
}
const char* CpuInfo::ExtractField(CpuInfoIndices idx) {
- UNIMPLEMENTED();
- return "<undefined>";
+ if (method_ == kCpuInfoCpuId) {
+ return CpuId::field(idx);
+ } else {
+ return strdup("");
+ }
}
bool CpuInfo::HasField(const char* field) {
- UNIMPLEMENTED();
- return false;
+ if (method_ == kCpuInfoCpuId) {
+ return (strcmp(field, fields_[kCpuInfoProcessor]) == 0) ||
+ (strcmp(field, fields_[kCpuInfoModel]) == 0) ||
+ (strcmp(field, fields_[kCpuInfoHardware]) == 0) ||
+ (strcmp(field, fields_[kCpuInfoFeatures]) == 0);
+ } else {
+ return false;
+ }
}
} // namespace dart
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index 62c7226..0bd8730 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -41,7 +41,6 @@
DECLARE_FLAG(bool, trace_time_all);
DEFINE_FLAG(bool, keep_code, false,
"Keep deoptimized code for profiling.");
-DEFINE_FLAG(bool, shutdown, true, "Do a clean shutdown of the VM");
DEFINE_FLAG(bool, trace_shutdown, false, "Trace VM shutdown on stderr");
Isolate* Dart::vm_isolate_ = NULL;
@@ -96,6 +95,7 @@
CHECK_OFFSET(Isolate::heap_offset(), 8);
CHECK_OFFSET(Thread::stack_limit_offset(), 4);
CHECK_OFFSET(Thread::object_null_offset(), 36);
+ NOT_IN_PRODUCT(CHECK_OFFSET(sizeof(ClassHeapStats), 120));
#endif
#if defined(TARGET_ARCH_MIPS)
// These offsets are embedded in precompiled instructions. We need simmips
@@ -104,6 +104,7 @@
CHECK_OFFSET(Isolate::heap_offset(), 8);
CHECK_OFFSET(Thread::stack_limit_offset(), 4);
CHECK_OFFSET(Thread::object_null_offset(), 36);
+ NOT_IN_PRODUCT(CHECK_OFFSET(sizeof(ClassHeapStats), 120));
#endif
#if defined(TARGET_ARCH_ARM64)
// These offsets are embedded in precompiled instructions. We need simarm64
@@ -112,6 +113,7 @@
CHECK_OFFSET(Isolate::heap_offset(), 16);
CHECK_OFFSET(Thread::stack_limit_offset(), 8);
CHECK_OFFSET(Thread::object_null_offset(), 72);
+ NOT_IN_PRODUCT(CHECK_OFFSET(sizeof(ClassHeapStats), 208));
#endif
#undef CHECK_OFFSET
}
@@ -375,105 +377,89 @@
Thread::ExitIsolate();
}
- if (FLAG_shutdown) {
- // Disable the creation of new isolates.
+ // Disable the creation of new isolates.
+ if (FLAG_trace_shutdown) {
+ OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Disabling isolate creation\n",
+ timestamp());
+ }
+ Isolate::DisableIsolateCreation();
+
+ // Send the OOB Kill message to all remaining application isolates.
+ if (FLAG_trace_shutdown) {
+ OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Killing all app isolates\n",
+ timestamp());
+ }
+ Isolate::KillAllIsolates(Isolate::kInternalKillMsg);
+
+ // Wait for all isolates, but the service and the vm isolate to shut down.
+ // Only do that if there is a service isolate running.
+ if (ServiceIsolate::IsRunning()) {
if (FLAG_trace_shutdown) {
- OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Disabling isolate creation\n",
+ OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Shutting down app isolates\n",
timestamp());
}
- Isolate::DisableIsolateCreation();
+ WaitForApplicationIsolateShutdown();
+ }
- // Send the OOB Kill message to all remaining application isolates.
- if (FLAG_trace_shutdown) {
- OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Killing all app isolates\n",
- timestamp());
- }
- Isolate::KillAllIsolates(Isolate::kInternalKillMsg);
+ // Shutdown the service isolate.
+ if (FLAG_trace_shutdown) {
+ OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Shutting down service isolate\n",
+ timestamp());
+ }
+ ServiceIsolate::Shutdown();
- // Wait for all isolates, but the service and the vm isolate to shut down.
- // Only do that if there is a service isolate running.
- if (ServiceIsolate::IsRunning()) {
- if (FLAG_trace_shutdown) {
- OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Shutting down app isolates\n",
- timestamp());
- }
- WaitForApplicationIsolateShutdown();
- }
+ // Wait for the remaining isolate (service isolate) to shutdown
+ // before shutting down the thread pool.
+ if (FLAG_trace_shutdown) {
+ OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Waiting for isolate shutdown\n",
+ timestamp());
+ }
+ WaitForIsolateShutdown();
- // Shutdown the service isolate.
- if (FLAG_trace_shutdown) {
- OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Shutting down service isolate\n",
- timestamp());
- }
- ServiceIsolate::Shutdown();
+ // Shutdown the thread pool. On return, all thread pool threads have exited.
+ if (FLAG_trace_shutdown) {
+ OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Deleting thread pool\n",
+ timestamp());
+ }
+ delete thread_pool_;
+ thread_pool_ = NULL;
- // Wait for the remaining isolate (service isolate) to shutdown
- // before shutting down the thread pool.
- if (FLAG_trace_shutdown) {
- OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Waiting for isolate shutdown\n",
- timestamp());
- }
- WaitForIsolateShutdown();
+ // Disable creation of any new OSThread structures which means no more new
+ // threads can do an EnterIsolate. This must come after isolate shutdown
+ // because new threads may need to be spawned to shutdown the isolates.
+ // This must come after deletion of the thread pool to avoid a race in which
+ // a thread spawned by the thread pool does not exit through the thread
+ // pool, messing up its bookkeeping.
+ if (FLAG_trace_shutdown) {
+ OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Disabling OS Thread creation\n",
+ timestamp());
+ }
+ OSThread::DisableOSThreadCreation();
- // Shutdown the thread pool. On return, all thread pool threads have exited.
- if (FLAG_trace_shutdown) {
- OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Deleting thread pool\n",
- timestamp());
- }
- delete thread_pool_;
- thread_pool_ = NULL;
+ // Set the VM isolate as current isolate.
+ if (FLAG_trace_shutdown) {
+ OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Cleaning up vm isolate\n",
+ timestamp());
+ }
+ bool result = Thread::EnterIsolate(vm_isolate_);
+ ASSERT(result);
- // Disable creation of any new OSThread structures which means no more new
- // threads can do an EnterIsolate. This must come after isolate shutdown
- // because new threads may need to be spawned to shutdown the isolates.
- // This must come after deletion of the thread pool to avoid a race in which
- // a thread spawned by the thread pool does not exit through the thread
- // pool, messing up its bookkeeping.
- if (FLAG_trace_shutdown) {
- OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Disabling OS Thread creation\n",
- timestamp());
- }
- OSThread::DisableOSThreadCreation();
+ ShutdownIsolate();
+ vm_isolate_ = NULL;
+ ASSERT(Isolate::IsolateListLength() == 0);
- // Set the VM isolate as current isolate.
- if (FLAG_trace_shutdown) {
- OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Cleaning up vm isolate\n",
- timestamp());
- }
- bool result = Thread::EnterIsolate(vm_isolate_);
- ASSERT(result);
+ TargetCPUFeatures::Cleanup();
+ StoreBuffer::ShutDown();
- ShutdownIsolate();
- vm_isolate_ = NULL;
- ASSERT(Isolate::IsolateListLength() == 0);
-
- TargetCPUFeatures::Cleanup();
- StoreBuffer::ShutDown();
-
- // Delete the current thread's TLS and set it's TLS to null.
- // If it is the last thread then the destructor would call
- // OSThread::Cleanup.
- OSThread* os_thread = OSThread::Current();
- OSThread::SetCurrent(NULL);
- delete os_thread;
- if (FLAG_trace_shutdown) {
- OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Deleted os_thread\n",
- timestamp());
- }
- } else {
- // Shutdown the service isolate.
- if (FLAG_trace_shutdown) {
- OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Shutting down service isolate\n",
- timestamp());
- }
- ServiceIsolate::Shutdown();
-
- // Disable thread creation.
- if (FLAG_trace_shutdown) {
- OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Disabling OS Thread creation\n",
- timestamp());
- }
- OSThread::DisableOSThreadCreation();
+ // Delete the current thread's TLS and set it's TLS to null.
+ // If it is the last thread then the destructor would call
+ // OSThread::Cleanup.
+ OSThread* os_thread = OSThread::Current();
+ OSThread::SetCurrent(NULL);
+ delete os_thread;
+ if (FLAG_trace_shutdown) {
+ OS::PrintErr("[+%" Pd64 "ms] SHUTDOWN: Deleted os_thread\n",
+ timestamp());
}
if (FLAG_trace_shutdown) {
@@ -674,12 +660,6 @@
#elif defined(TARGET_ARCH_DBC64)
buffer.AddString(" dbc64");
#endif
- } else if (Snapshot::IsFull(kind)) {
-#if defined(ARCH_IS_32BIT)
- buffer.AddString(" 32");
-#else
- buffer.AddString(" 64");
-#endif
}
return buffer.Steal();
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index c9942da..34a8d33 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -1325,10 +1325,9 @@
DART_EXPORT void* Dart_IsolateData(Dart_Isolate isolate) {
if (isolate == NULL) {
- FATAL1("%s expects argument 'isolate' to be non-null.", CURRENT_FUNC);
+ FATAL1("%s expects argument 'isolate' to be non-null.", CURRENT_FUNC);
}
// TODO(16615): Validate isolate parameter.
- NoSafepointScope no_safepoint_scope;
Isolate* iso = reinterpret_cast<Isolate*>(isolate);
return iso->init_callback_data();
}
@@ -5808,6 +5807,71 @@
}
+DART_EXPORT int64_t Dart_TimelineGetMicros() {
+ return OS::GetCurrentMonotonicMicros();
+}
+
+
+#if defined(PRODUCT)
+DART_EXPORT void Dart_RegisterIsolateServiceRequestCallback(
+ const char* name,
+ Dart_ServiceRequestCallback callback,
+ void* user_data) {
+ return;
+}
+
+
+DART_EXPORT void Dart_RegisterRootServiceRequestCallback(
+ const char* name,
+ Dart_ServiceRequestCallback callback,
+ void* user_data) {
+ return;
+}
+
+
+DART_EXPORT Dart_Handle Dart_SetServiceStreamCallbacks(
+ Dart_ServiceStreamListenCallback listen_callback,
+ Dart_ServiceStreamCancelCallback cancel_callback) {
+ return Api::Success();
+}
+
+
+DART_EXPORT Dart_Handle Dart_ServiceSendDataEvent(const char* stream_id,
+ const char* event_kind,
+ const uint8_t* bytes,
+ intptr_t bytes_length) {
+ return Api::Success();
+}
+
+
+DART_EXPORT void Dart_GlobalTimelineSetRecordedStreams(int64_t stream_mask) {
+ return;
+}
+
+
+DART_EXPORT void Dart_SetEmbedderTimelineCallbacks(
+ Dart_EmbedderTimelineStartRecording start_recording,
+ Dart_EmbedderTimelineStopRecording stop_recording) {
+ return;
+}
+
+
+DART_EXPORT bool Dart_GlobalTimelineGetTrace(Dart_StreamConsumer consumer,
+ void* user_data) {
+ return false;
+}
+
+
+DART_EXPORT void Dart_TimelineEvent(const char* label,
+ int64_t timestamp0,
+ int64_t timestamp1_or_async_id,
+ Dart_Timeline_Event_Type type,
+ intptr_t argument_count,
+ const char** argument_names,
+ const char** argument_values) {
+ return;
+}
+#else // defined(PRODUCT)
DART_EXPORT void Dart_RegisterIsolateServiceRequestCallback(
const char* name,
Dart_ServiceRequestCallback callback,
@@ -5871,9 +5935,6 @@
const char* event_kind,
const uint8_t* bytes,
intptr_t bytes_length) {
-#if defined(PRODUCT)
- return Api::Success();
-#else // defined(PRODUCT)
DARTSCOPE(Thread::Current());
Isolate* I = T->isolate();
if (stream_id == NULL) {
@@ -5892,12 +5953,6 @@
Service::SendEmbedderEvent(I, stream_id, event_kind,
bytes, bytes_length);
return Api::Success();
-#endif // defined(PRODUCT)
-}
-
-
-DART_EXPORT int64_t Dart_TimelineGetMicros() {
- return OS::GetCurrentMonotonicMicros();
}
@@ -6125,6 +6180,7 @@
}
event->Complete();
}
+#endif // defined(PRODUCT)
DART_EXPORT void Dart_SetThreadName(const char* name) {
diff --git a/runtime/vm/dart_api_message.cc b/runtime/vm/dart_api_message.cc
index 2d4e759..ed04af0 100644
--- a/runtime/vm/dart_api_message.cc
+++ b/runtime/vm/dart_api_message.cc
@@ -642,8 +642,6 @@
}
case kOneByteStringCid: {
intptr_t len = ReadSmiValue();
- intptr_t hash = ReadSmiValue();
- USE(hash);
uint8_t *latin1 =
reinterpret_cast<uint8_t*>(allocator(len * sizeof(uint8_t)));
intptr_t utf8_len = 0;
@@ -663,8 +661,6 @@
}
case kTwoByteStringCid: {
intptr_t len = ReadSmiValue();
- intptr_t hash = ReadSmiValue();
- USE(hash);
uint16_t *utf16 = reinterpret_cast<uint16_t*>(
allocator(len * sizeof(uint16_t)));
intptr_t utf8_len = 0;
@@ -1203,9 +1199,8 @@
WriteIndexedObject(type == Utf8::kLatin1 ? kOneByteStringCid
: kTwoByteStringCid);
WriteTags(0);
- // Write string length, hash and content
+ // Write string length and content.
WriteSmi(len);
- WriteSmi(0); // TODO(sgjesse): Hash - not written.
if (type == Utf8::kLatin1) {
uint8_t* latin1_str =
reinterpret_cast<uint8_t*>(::malloc(len * sizeof(uint8_t)));
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index 64476a9..a52cf4a 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -827,7 +827,7 @@
if (deopt_frame_.IsNull()) {
return GetVariableValue(LocalVarAddress(fp(), slot_index));
} else {
- return deopt_frame_.At(deopt_frame_offset_ + slot_index);
+ return deopt_frame_.At(LocalVarIndex(deopt_frame_offset_, slot_index));
}
}
diff --git a/runtime/vm/deopt_instructions.cc b/runtime/vm/deopt_instructions.cc
index f31a897..ae38a71 100644
--- a/runtime/vm/deopt_instructions.cc
+++ b/runtime/vm/deopt_instructions.cc
@@ -147,6 +147,7 @@
delete[] deferred_objects_;
deferred_objects_ = NULL;
deferred_objects_count_ = 0;
+#ifndef PRODUCT
if (FLAG_support_timeline && (deopt_start_micros_ != 0)) {
TimelineStream* compiler_stream = Timeline::GetCompilerStream();
ASSERT(compiler_stream != NULL);
@@ -172,6 +173,7 @@
}
}
}
+#endif // !PRODUCT
}
@@ -1045,6 +1047,10 @@
Location::Kind stack_slot_kind) {
if (loc.IsFpuRegister()) {
return FpuRegisterSource(FpuRegisterSource::kRegister, loc.fpu_reg());
+#if defined(TARGET_ARCH_DBC)
+ } else if (loc.IsRegister()) {
+ return FpuRegisterSource(FpuRegisterSource::kRegister, loc.reg());
+#endif
} else {
ASSERT((stack_slot_kind == Location::kQuadStackSlot) ||
(stack_slot_kind == Location::kDoubleStackSlot));
diff --git a/runtime/vm/deopt_instructions.h b/runtime/vm/deopt_instructions.h
index 79a2c50..09e01b4 100644
--- a/runtime/vm/deopt_instructions.h
+++ b/runtime/vm/deopt_instructions.h
@@ -86,8 +86,14 @@
ASSERT(FlowGraphCompiler::SupportsUnboxedDoubles());
ASSERT(fpu_registers_ != NULL);
ASSERT(reg >= 0);
+#if !defined(TARGET_ARCH_DBC)
ASSERT(reg < kNumberOfFpuRegisters);
return *reinterpret_cast<double*>(&fpu_registers_[reg]);
+#else
+ // On DBC registers and stack slots are the same.
+ const intptr_t stack_index = num_args_ + kDartFrameFixedSize + reg;
+ return *reinterpret_cast<double*>(GetSourceFrameAddressAt(stack_index));
+#endif
}
simd128_value_t FpuRegisterValueAsSimd128(FpuRegister reg) const {
diff --git a/runtime/vm/disassembler.cc b/runtime/vm/disassembler.cc
index eef90c3..a735289 100644
--- a/runtime/vm/disassembler.cc
+++ b/runtime/vm/disassembler.cc
@@ -26,6 +26,7 @@
intptr_t hex_size,
char* human_buffer,
intptr_t human_size,
+ Object* object,
uword pc) {
static const int kHexColumnWidth = 23;
uint8_t* pc_ptr = reinterpret_cast<uint8_t*>(pc);
@@ -37,6 +38,9 @@
}
}
THR_Print("%s", human_buffer);
+ if (object != NULL) {
+ THR_Print(" %s", object->ToCString());
+ }
THR_Print("\n");
}
@@ -54,6 +58,7 @@
intptr_t hex_size,
char* human_buffer,
intptr_t human_size,
+ Object* object,
uword pc) {
// Instructions are represented as four consecutive values in a JSON array.
// The first is the address of the instruction, the second is the hex string,
@@ -63,9 +68,8 @@
jsarr_.AddValue(hex_buffer);
jsarr_.AddValue(human_buffer);
- Object& object = Object::Handle();
- if (DecodeLoadObjectFromPoolOrThread(pc, code, &object)) {
- jsarr_.AddValue(object);
+ if (object != NULL) {
+ jsarr_.AddValue(*object);
} else {
jsarr_.AddValueNull(); // Not a reference to null.
}
@@ -97,33 +101,6 @@
}
-class FindAddrVisitor : public FindObjectVisitor {
- public:
- explicit FindAddrVisitor(uword addr) : addr_(addr) { }
- virtual ~FindAddrVisitor() { }
-
- virtual uword filter_addr() const { return addr_; }
-
- // Check if object matches find condition.
- virtual bool FindObject(RawObject* obj) const {
- return obj == reinterpret_cast<RawObject*>(addr_);
- }
-
- private:
- const uword addr_;
-
- DISALLOW_COPY_AND_ASSIGN(FindAddrVisitor);
-};
-
-
-bool Disassembler::CanFindOldObject(uword addr) {
- FindAddrVisitor visitor(addr);
- NoSafepointScope no_safepoint;
- return Dart::vm_isolate()->heap()->FindOldObject(&visitor) != Object::null()
- || Isolate::Current()->heap()->FindOldObject(&visitor) != Object::null();
-}
-
-
void Disassembler::Disassemble(uword start,
uword end,
DisassemblyFormatter* formatter,
@@ -168,16 +145,18 @@
}
}
int instruction_length;
+ Object* object;
DecodeInstruction(hex_buffer,
sizeof(hex_buffer),
human_buffer,
sizeof(human_buffer),
- &instruction_length, pc);
+ &instruction_length, code, &object, pc);
formatter->ConsumeInstruction(code,
hex_buffer,
sizeof(hex_buffer),
human_buffer,
sizeof(human_buffer),
+ object,
pc);
pc += instruction_length;
}
@@ -250,37 +229,39 @@
}
THR_Print("}\n");
- THR_Print("Variable Descriptors for function '%s' {\n",
- function_fullname);
- const LocalVarDescriptors& var_descriptors =
- LocalVarDescriptors::Handle(code.GetLocalVarDescriptors());
- intptr_t var_desc_length =
- var_descriptors.IsNull() ? 0 : var_descriptors.Length();
- String& var_name = String::Handle();
- for (intptr_t i = 0; i < var_desc_length; i++) {
- var_name = var_descriptors.GetName(i);
- RawLocalVarDescriptors::VarInfo var_info;
- var_descriptors.GetInfo(i, &var_info);
- const int8_t kind = var_info.kind();
- if (kind == RawLocalVarDescriptors::kSavedCurrentContext) {
- THR_Print(" saved current CTX reg offset %d\n", var_info.index());
- } else {
- if (kind == RawLocalVarDescriptors::kContextLevel) {
- THR_Print(" context level %d scope %d", var_info.index(),
- var_info.scope_id);
- } else if (kind == RawLocalVarDescriptors::kStackVar) {
- THR_Print(" stack var '%s' offset %d",
- var_name.ToCString(), var_info.index());
+ if (FLAG_print_variable_descriptors) {
+ THR_Print("Variable Descriptors for function '%s' {\n",
+ function_fullname);
+ const LocalVarDescriptors& var_descriptors =
+ LocalVarDescriptors::Handle(code.GetLocalVarDescriptors());
+ intptr_t var_desc_length =
+ var_descriptors.IsNull() ? 0 : var_descriptors.Length();
+ String& var_name = String::Handle();
+ for (intptr_t i = 0; i < var_desc_length; i++) {
+ var_name = var_descriptors.GetName(i);
+ RawLocalVarDescriptors::VarInfo var_info;
+ var_descriptors.GetInfo(i, &var_info);
+ const int8_t kind = var_info.kind();
+ if (kind == RawLocalVarDescriptors::kSavedCurrentContext) {
+ THR_Print(" saved current CTX reg offset %d\n", var_info.index());
} else {
- ASSERT(kind == RawLocalVarDescriptors::kContextVar);
- THR_Print(" context var '%s' level %d offset %d",
- var_name.ToCString(), var_info.scope_id, var_info.index());
+ if (kind == RawLocalVarDescriptors::kContextLevel) {
+ THR_Print(" context level %d scope %d", var_info.index(),
+ var_info.scope_id);
+ } else if (kind == RawLocalVarDescriptors::kStackVar) {
+ THR_Print(" stack var '%s' offset %d",
+ var_name.ToCString(), var_info.index());
+ } else {
+ ASSERT(kind == RawLocalVarDescriptors::kContextVar);
+ THR_Print(" context var '%s' level %d offset %d",
+ var_name.ToCString(), var_info.scope_id, var_info.index());
+ }
+ THR_Print(" (valid %s-%s)\n", var_info.begin_pos.ToCString(),
+ var_info.end_pos.ToCString());
}
- THR_Print(" (valid %s-%s)\n", var_info.begin_pos.ToCString(),
- var_info.end_pos.ToCString());
}
+ THR_Print("}\n");
}
- THR_Print("}\n");
THR_Print("Exception Handlers for function '%s' {\n", function_fullname);
const ExceptionHandlers& handlers =
diff --git a/runtime/vm/disassembler.h b/runtime/vm/disassembler.h
index fc3649a..7adb12a 100644
--- a/runtime/vm/disassembler.h
+++ b/runtime/vm/disassembler.h
@@ -29,6 +29,7 @@
intptr_t hex_size,
char* human_buffer,
intptr_t human_size,
+ Object* object,
uword pc) = 0;
// Print a formatted message.
@@ -48,6 +49,7 @@
intptr_t hex_size,
char* human_buffer,
intptr_t human_size,
+ Object* object,
uword pc);
virtual void Print(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
@@ -70,6 +72,7 @@
intptr_t hex_size,
char* human_buffer,
intptr_t human_size,
+ Object* object,
uword pc);
virtual void Print(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
@@ -112,29 +115,14 @@
Disassemble(start, end, &stdout_formatter);
}
- // Disassemble instructions in a memory region.
- static void DisassembleMemoryRegion(const MemoryRegion& instructions,
- DisassemblyFormatter* formatter) {
- uword start = instructions.start();
- uword end = instructions.end();
- Disassemble(start, end, formatter);
- }
-
- static void DisassembleMemoryRegion(const MemoryRegion& instructions) {
- uword start = instructions.start();
- uword end = instructions.end();
- Disassemble(start, end);
- }
-
// Decodes one instruction.
// Writes a hexadecimal representation into the hex_buffer and a
// human-readable representation into the human_buffer.
// Writes the length of the decoded instruction in bytes in out_instr_len.
static void DecodeInstruction(char* hex_buffer, intptr_t hex_size,
char* human_buffer, intptr_t human_size,
- int* out_instr_len, uword pc);
-
- static bool CanFindOldObject(uword addr);
+ int* out_instr_len, const Code& code,
+ Object** object, uword pc);
static void DisassembleCode(const Function& function, bool optimized);
static void DisassembleCodeUnoptimized(
diff --git a/runtime/vm/disassembler_arm.cc b/runtime/vm/disassembler_arm.cc
index 2b0c103..67c0afb 100644
--- a/runtime/vm/disassembler_arm.cc
+++ b/runtime/vm/disassembler_arm.cc
@@ -6,9 +6,9 @@
#include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM.
#if defined(TARGET_ARCH_ARM)
-
#include "platform/assert.h"
#include "vm/cpu.h"
+#include "vm/instructions.h"
namespace dart {
@@ -1534,7 +1534,8 @@
void Disassembler::DecodeInstruction(char* hex_buffer, intptr_t hex_size,
char* human_buffer, intptr_t human_size,
- int* out_instr_size, uword pc) {
+ int* out_instr_size, const Code& code,
+ Object** object, uword pc) {
ARMDecoder decoder(human_buffer, human_size);
decoder.InstructionDecode(pc);
int32_t instruction_bits = Instr::At(pc)->InstructionBits();
@@ -1542,6 +1543,14 @@
if (out_instr_size) {
*out_instr_size = Instr::kInstrSize;
}
+
+ *object = NULL;
+ if (!code.IsNull()) {
+ *object = &Object::Handle();
+ if (!DecodeLoadObjectFromPoolOrThread(pc, code, *object)) {
+ *object = NULL;
+ }
+ }
}
#endif // !PRODUCT
diff --git a/runtime/vm/disassembler_arm64.cc b/runtime/vm/disassembler_arm64.cc
index a238641..dd7d00c 100644
--- a/runtime/vm/disassembler_arm64.cc
+++ b/runtime/vm/disassembler_arm64.cc
@@ -7,6 +7,7 @@
#include "vm/globals.h" // Needed here to get TARGET_ARCH_ARM64.
#if defined(TARGET_ARCH_ARM64)
#include "platform/assert.h"
+#include "vm/instructions.h"
namespace dart {
@@ -1488,7 +1489,8 @@
void Disassembler::DecodeInstruction(char* hex_buffer, intptr_t hex_size,
char* human_buffer, intptr_t human_size,
- int* out_instr_size, uword pc) {
+ int* out_instr_size, const Code& code,
+ Object** object, uword pc) {
ARM64Decoder decoder(human_buffer, human_size);
decoder.InstructionDecode(pc);
int32_t instruction_bits = Instr::At(pc)->InstructionBits();
@@ -1496,6 +1498,14 @@
if (out_instr_size) {
*out_instr_size = Instr::kInstrSize;
}
+
+ *object = NULL;
+ if (!code.IsNull()) {
+ *object = &Object::Handle();
+ if (!DecodeLoadObjectFromPoolOrThread(pc, code, *object)) {
+ *object = NULL;
+ }
+ }
}
#endif // !PRODUCT
diff --git a/runtime/vm/disassembler_dbc.cc b/runtime/vm/disassembler_dbc.cc
index 5c8b3a0..a2095a0 100644
--- a/runtime/vm/disassembler_dbc.cc
+++ b/runtime/vm/disassembler_dbc.cc
@@ -10,6 +10,7 @@
#include "platform/assert.h"
#include "vm/constants_dbc.h"
#include "vm/cpu.h"
+#include "vm/instructions.h"
namespace dart {
@@ -214,6 +215,8 @@
char* human_buffer,
intptr_t human_size,
int* out_instr_size,
+ const Code& code,
+ Object** object,
uword pc) {
const uint32_t instr = *reinterpret_cast<uint32_t*>(pc);
const uint8_t opcode = instr & 0xFF;
@@ -229,6 +232,14 @@
if (out_instr_size) {
*out_instr_size = sizeof(uint32_t);
}
+
+ *object = NULL;
+ if (!code.IsNull()) {
+ *object = &Object::Handle();
+ if (!DecodeLoadObjectFromPoolOrThread(pc, code, *object)) {
+ *object = NULL;
+ }
+ }
}
diff --git a/runtime/vm/disassembler_ia32.cc b/runtime/vm/disassembler_ia32.cc
index 31e4fdba..8f3d7f6 100644
--- a/runtime/vm/disassembler_ia32.cc
+++ b/runtime/vm/disassembler_ia32.cc
@@ -465,69 +465,17 @@
}
-static const char* ObjectToCStringNoGC(const Object& obj) {
- if (obj.IsSmi() ||
- obj.IsMint() ||
- obj.IsDouble() ||
- obj.IsString() ||
- obj.IsNull() ||
- obj.IsBool() ||
- obj.IsClass() ||
- obj.IsFunction() ||
- obj.IsICData() ||
- obj.IsField() ||
- obj.IsCode()) {
- return obj.ToCString();
- }
-
- const Class& clazz = Class::Handle(obj.clazz());
- const char* full_class_name = clazz.ToCString();
- return OS::SCreate(Thread::Current()->zone(),
- "instance of %s", full_class_name);
-}
-
-
void X86Decoder::PrintAddress(uword addr) {
char addr_buffer[32];
OS::SNPrint(addr_buffer, sizeof(addr_buffer), "%#" Px "", addr);
Print(addr_buffer);
- // Try to print as heap object or stub name
- if (((addr & kSmiTagMask) == kHeapObjectTag) &&
- reinterpret_cast<RawObject*>(addr)->IsWellFormed() &&
- reinterpret_cast<RawObject*>(addr)->IsOldObject() &&
- !Isolate::Current()->heap()->CodeContains(addr) &&
- !Dart::vm_isolate()->heap()->CodeContains(addr) &&
- Disassembler::CanFindOldObject(addr)) {
- NoSafepointScope no_safepoint;
- const Object& obj = Object::Handle(reinterpret_cast<RawObject*>(addr));
- if (obj.IsArray()) {
- const Array& arr = Array::Cast(obj);
- intptr_t len = arr.Length();
- if (len > 5) len = 5; // Print a max of 5 elements.
- Print(" Array[");
- int i = 0;
- Object& element = Object::Handle();
- while (i < len) {
- element = arr.At(i);
- if (i > 0) Print(", ");
- Print(ObjectToCStringNoGC(element));
- i++;
- }
- if (i < arr.Length()) Print(", ...");
- Print("]");
- return;
- }
- Print(" '");
- Print(ObjectToCStringNoGC(obj));
- Print("'");
- } else {
- // 'addr' is not an object, but probably a code address.
- const char* name_of_stub = StubCode::NameOfStub(addr);
- if (name_of_stub != NULL) {
- Print(" [stub: ");
- Print(name_of_stub);
- Print("]");
- }
+
+ // Try to print as stub name.
+ const char* name_of_stub = StubCode::NameOfStub(addr);
+ if (name_of_stub != NULL) {
+ Print(" [stub: ");
+ Print(name_of_stub);
+ Print("]");
}
}
@@ -1845,7 +1793,8 @@
void Disassembler::DecodeInstruction(char* hex_buffer, intptr_t hex_size,
char* human_buffer, intptr_t human_size,
- int* out_instr_len, uword pc) {
+ int* out_instr_len, const Code& code,
+ Object** object, uword pc) {
ASSERT(hex_size > 0);
ASSERT(human_size > 0);
X86Decoder decoder(human_buffer, human_size);
@@ -1862,6 +1811,18 @@
if (out_instr_len) {
*out_instr_len = instruction_length;
}
+
+ *object = NULL;
+ if (!code.IsNull() && code.is_alive()) {
+ intptr_t offsets_length = code.pointer_offsets_length();
+ for (intptr_t i = 0; i < offsets_length; i++) {
+ uword addr = code.GetPointerOffsetAt(i) + code.EntryPoint();
+ if ((pc <= addr) && (addr < (pc + instruction_length))) {
+ *object = &Object::Handle(*reinterpret_cast<RawObject**>(addr));
+ break;
+ }
+ }
+ }
}
#endif // !PRODUCT
diff --git a/runtime/vm/disassembler_mips.cc b/runtime/vm/disassembler_mips.cc
index 22fe462..78831a7 100644
--- a/runtime/vm/disassembler_mips.cc
+++ b/runtime/vm/disassembler_mips.cc
@@ -7,6 +7,7 @@
#include "vm/globals.h" // Needed here to get TARGET_ARCH_MIPS.
#if defined(TARGET_ARCH_MIPS)
#include "platform/assert.h"
+#include "vm/instructions.h"
namespace dart {
@@ -778,7 +779,8 @@
void Disassembler::DecodeInstruction(char* hex_buffer, intptr_t hex_size,
char* human_buffer, intptr_t human_size,
- int* out_instr_len, uword pc) {
+ int* out_instr_len, const Code& code,
+ Object** object, uword pc) {
MIPSDecoder decoder(human_buffer, human_size);
Instr* instr = Instr::At(pc);
decoder.InstructionDecode(instr);
@@ -786,6 +788,14 @@
if (out_instr_len) {
*out_instr_len = Instr::kInstrSize;
}
+
+ *object = NULL;
+ if (!code.IsNull()) {
+ *object = &Object::Handle();
+ if (!DecodeLoadObjectFromPoolOrThread(pc, code, *object)) {
+ *object = NULL;
+ }
+ }
}
#endif // !PRODUCT
diff --git a/runtime/vm/disassembler_x64.cc b/runtime/vm/disassembler_x64.cc
index 60118f1..f389415 100644
--- a/runtime/vm/disassembler_x64.cc
+++ b/runtime/vm/disassembler_x64.cc
@@ -9,6 +9,7 @@
#include "platform/utils.h"
#include "vm/allocation.h"
#include "vm/heap.h"
+#include "vm/instructions.h"
#include "vm/os.h"
#include "vm/stack_frame.h"
#include "vm/stub_code.h"
@@ -785,65 +786,9 @@
}
-static const char* ObjectToCStringNoGC(const Object& obj) {
- if (obj.IsSmi() ||
- obj.IsMint() ||
- obj.IsDouble() ||
- obj.IsString() ||
- obj.IsNull() ||
- obj.IsBool() ||
- obj.IsClass() ||
- obj.IsFunction() ||
- obj.IsICData() ||
- obj.IsField() ||
- obj.IsCode()) {
- return obj.ToCString();
- }
-
- const Class& clazz = Class::Handle(obj.clazz());
- const char* full_class_name = clazz.ToCString();
- return OS::SCreate(Thread::Current()->zone(),
- "instance of %s", full_class_name);
-}
-
-
void DisassemblerX64::PrintAddress(uint8_t* addr_byte_ptr) {
uword addr = reinterpret_cast<uword>(addr_byte_ptr);
Print("%#" Px "", addr);
- // Try to print as heap object or stub name
- if (((addr & kSmiTagMask) == kHeapObjectTag) &&
- reinterpret_cast<RawObject*>(addr)->IsWellFormed() &&
- reinterpret_cast<RawObject*>(addr)->IsOldObject() &&
- !Dart::vm_isolate()->heap()->CodeContains(addr) &&
- !Isolate::Current()->heap()->CodeContains(addr) &&
- Disassembler::CanFindOldObject(addr)) {
- NoSafepointScope no_safepoint;
- const Object& obj = Object::Handle(reinterpret_cast<RawObject*>(addr));
- if (obj.IsArray()) {
- const Array& arr = Array::Cast(obj);
- intptr_t len = arr.Length();
- if (len > 5) len = 5; // Print a max of 5 elements.
- Print(" Array[");
- int i = 0;
- Object& element = Object::Handle();
- while (i < len) {
- element = arr.At(i);
- if (i > 0) Print(", ");
- Print("%s", ObjectToCStringNoGC(element));
- i++;
- }
- if (i < arr.Length()) Print(", ...");
- Print("]");
- return;
- }
- Print(" '%s'", ObjectToCStringNoGC(obj));
- } else {
- // 'addr' is not an object, but probably a code address.
- const char* name_of_stub = StubCode::NameOfStub(addr);
- if (name_of_stub != NULL) {
- Print(" [stub: %s]", name_of_stub);
- }
- }
}
@@ -1935,7 +1880,8 @@
void Disassembler::DecodeInstruction(char* hex_buffer, intptr_t hex_size,
char* human_buffer, intptr_t human_size,
- int* out_instr_len, uword pc) {
+ int* out_instr_len, const Code& code,
+ Object** object, uword pc) {
ASSERT(hex_size > 0);
ASSERT(human_size > 0);
DisassemblerX64 decoder(human_buffer, human_size);
@@ -1952,6 +1898,14 @@
if (out_instr_len) {
*out_instr_len = instruction_length;
}
+
+ *object = NULL;
+ if (!code.IsNull()) {
+ *object = &Object::Handle();
+ if (!DecodeLoadObjectFromPoolOrThread(pc, code, *object)) {
+ *object = NULL;
+ }
+ }
}
#endif // !PRODUCT
diff --git a/runtime/vm/flag_list.h b/runtime/vm/flag_list.h
index c22e43c..7daddd9 100644
--- a/runtime/vm/flag_list.h
+++ b/runtime/vm/flag_list.h
@@ -12,6 +12,12 @@
#define USING_DBC false
#endif
+#if defined(TARGET_OS_FUCHSIA)
+#define USING_FUCHSIA true
+#else
+#define USING_FUCHSIA false
+#endif
+
// Don't use USING_MULTICORE outside of this file.
#if defined(ARCH_IS_MULTI_CORE)
#define USING_MULTICORE true
@@ -35,8 +41,6 @@
// D(name, type, default_value, comment)
// C(name, precompiled_value, product_value, type, default_value, comment)
#define FLAG_LIST(P, R, D, C) \
-P(always_megamorphic_calls, bool, false, \
- "Instance call always as megamorphic.") \
P(background_compilation, bool, USING_MULTICORE, \
"Run optimizing compilation in background") \
R(background_compilation_stop_alot, false, bool, false, \
@@ -90,8 +94,6 @@
"Ratio of getter/setter usage used for double field unboxing heuristics") \
P(guess_icdata_cid, bool, true, \
"Artificially create type feedback for arithmetic etc. operations") \
-P(ic_range_profiling, bool, !USING_DBC, \
- "Generate special IC stubs collecting range information ") \
P(interpret_irregexp, bool, USING_DBC, \
"Use irregexp bytecode interpreter") \
P(lazy_dispatchers, bool, true, \
@@ -108,7 +110,7 @@
P(max_polymorphic_checks, int, 4, \
"Maximum number of polymorphic check, otherwise it is megamorphic.") \
P(max_equality_polymorphic_checks, int, 32, \
- "Maximum number of polymorphic checks in equality operator,") \
+ "Maximum number of polymorphic checks in equality operator,") \
P(merge_sin_cos, bool, false, \
"Merge sin/cos into sincos") \
P(new_gen_ext_limit, int, 64, \
@@ -138,7 +140,9 @@
"Print live ranges after allocation.") \
C(print_stop_message, false, false, bool, false, \
"Print stop message.") \
-R(profiler, false, bool, !USING_DBC, \
+D(print_variable_descriptors, bool, false, \
+ "Print variable descriptors in disassembly.") \
+R(profiler, false, bool, !USING_DBC && !USING_FUCHSIA, \
"Enable the profiler.") \
P(reorder_basic_blocks, bool, true, \
"Reorder basic blocks") \
@@ -146,13 +150,13 @@
"Support the AST printer.") \
R(support_compiler_stats, false, bool, true, \
"Support compiler stats.") \
-R(support_debugger, false, bool, true, \
+C(support_debugger, false, false, bool, true, \
"Support the debugger.") \
R(support_disassembler, false, bool, true, \
"Support the disassembler.") \
R(support_il_printer, false, bool, true, \
"Support the IL printer.") \
-R(support_reload, false, bool, true, \
+C(support_reload, false, false, bool, true, \
"Support isolate reload.") \
R(support_service, false, bool, true, \
"Support the service protocol.") \
@@ -184,8 +188,6 @@
"Use field guards and track field types") \
C(use_osr, false, true, bool, true, \
"Use OSR") \
-R(verbose_dev, false, bool, false, \
- "Enables verbose messages during development.") \
P(verbose_gc, bool, false, \
"Enables verbose GC.") \
P(verbose_gc_hdr, int, 40, \
diff --git a/runtime/vm/flags.cc b/runtime/vm/flags.cc
index cb76c91..8c5a9d8 100644
--- a/runtime/vm/flags.cc
+++ b/runtime/vm/flags.cc
@@ -487,6 +487,7 @@
}
+#ifndef PRODUCT
void Flags::PrintFlagToJSONArray(JSONArray* jsarr, const Flag* flag) {
if (!FLAG_support_service) {
return;
@@ -542,5 +543,6 @@
PrintFlagToJSONArray(&jsarr, flags_[i]);
}
}
+#endif // !PRODUCT
} // namespace dart
diff --git a/runtime/vm/flags.h b/runtime/vm/flags.h
index 81f594e..b30299c 100644
--- a/runtime/vm/flags.h
+++ b/runtime/vm/flags.h
@@ -1,4 +1,4 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// Copyright (c) 2012, the Dart project authors[. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
@@ -67,7 +67,9 @@
static bool Initialized() { return initialized_; }
+#ifndef PRODUCT
static void PrintJSON(JSONStream* js);
+#endif // !PRODUCT
static bool SetFlag(const char* name,
const char* value,
@@ -90,7 +92,9 @@
static void PrintFlags();
+#ifndef PRODUCT
static void PrintFlagToJSONArray(JSONArray* jsarr, const Flag* flag);
+#endif // !PRODUCT
// Testing needs direct access to private methods.
friend void Dart_TestParseFlags();
diff --git a/runtime/vm/flow_graph_allocator.cc b/runtime/vm/flow_graph_allocator.cc
index 009e500..558e6f7 100644
--- a/runtime/vm/flow_graph_allocator.cc
+++ b/runtime/vm/flow_graph_allocator.cc
@@ -749,15 +749,22 @@
static Location::Kind RegisterKindForResult(Instruction* instr) {
- if ((instr->representation() == kUnboxedDouble) ||
- (instr->representation() == kUnboxedFloat32x4) ||
- (instr->representation() == kUnboxedInt32x4) ||
- (instr->representation() == kUnboxedFloat64x2) ||
- (instr->representation() == kPairOfUnboxedDouble)) {
+ const Representation rep = instr->representation();
+#if !defined(TARGET_ARCH_DBC)
+ if ((rep == kUnboxedDouble) || (rep == kUnboxedFloat32x4) ||
+ (rep == kUnboxedInt32x4) || (rep == kUnboxedFloat64x2) ||
+ (rep == kPairOfUnboxedDouble)) {
return Location::kFpuRegister;
} else {
return Location::kRegister;
}
+#else
+ // DBC supports only unboxed doubles and does not have distinguished FPU
+ // registers.
+ ASSERT((rep != kUnboxedFloat32x4) && (rep != kUnboxedInt32x4) &&
+ (rep != kUnboxedFloat64x2) && (rep != kPairOfUnboxedDouble));
+ return Location::kRegister;
+#endif
}
@@ -3055,6 +3062,11 @@
unallocated_xmm_,
fpu_regs_,
blocked_fpu_registers_);
+#if defined(TARGET_ARCH_DBC)
+ // For DBC all registers should have been allocated in the first pass.
+ ASSERT(unallocated_.is_empty());
+#endif
+
AllocateUnallocatedRanges();
#if defined(TARGET_ARCH_DBC)
const intptr_t last_used_fpu_register = last_used_register_;
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index aeea819..0bcf854 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -899,10 +899,13 @@
context, Context::parent_offset(), Type::ZoneHandle(Z, Type::null()),
token_pos));
}
- return new(Z) LoadFieldInstr(context,
- Context::variable_offset(local.index()),
- local.type(),
- token_pos);
+ LoadFieldInstr* load = new(Z) LoadFieldInstr(
+ context,
+ Context::variable_offset(local.index()),
+ local.type(),
+ token_pos);
+ load->set_is_immutable(local.is_final());
+ return load;
} else {
return new(Z) LoadLocalInstr(local, token_pos);
}
@@ -1543,6 +1546,22 @@
return Bind(BuildAssertAssignable(token_pos, value, dst_type, dst_name));
}
+static bool simpleInstanceOfType(const AbstractType& type) {
+ // Bail if the type is still uninstantiated at compile time.
+ if (!type.IsInstantiated()) return false;
+
+ // Bail if the type is a function or a Dart Function type.
+ if (type.IsFunctionType() || type.IsDartFunctionType()) return false;
+
+ ASSERT(type.HasResolvedTypeClass());
+ const Class& type_class = Class::Handle(type.type_class());
+ // Bail if the type has any type parameters.
+ if (type_class.IsGeneric()) return false;
+
+ // Finally a simple class for instance of checking.
+ return true;
+}
+
void EffectGraphVisitor::BuildTypeTest(ComparisonNode* node) {
ASSERT(Token::IsTypeTestOperator(node->kind()));
@@ -1599,7 +1618,32 @@
return;
}
+ // We now know type is a real class (!num, !int, !smi, !string)
+ // and the type check could NOT be removed at compile time.
PushArgumentInstr* push_left = PushArgument(for_left_value.value());
+ if (simpleInstanceOfType(type)) {
+ ASSERT(!node->right()->AsTypeNode()->type().IsNull());
+ ZoneGrowableArray<PushArgumentInstr*>* arguments =
+ new(Z) ZoneGrowableArray<PushArgumentInstr*>(2);
+ arguments->Add(push_left);
+ Value* type_const = Bind(new(Z) ConstantInstr(type));
+ arguments->Add(PushArgument(type_const));
+ const intptr_t kNumArgsChecked = 2;
+ Definition* result = new(Z) InstanceCallInstr(
+ node->token_pos(),
+ Library::PrivateCoreLibName(Symbols::_simpleInstanceOf()),
+ node->kind(),
+ arguments,
+ Object::null_array(), // No argument names.
+ kNumArgsChecked,
+ owner()->ic_data_array());
+ if (negate_result) {
+ result = new(Z) BooleanNegateInstr(Bind(result));
+ }
+ ReturnDefinition(result);
+ return;
+ }
+
PushArgumentInstr* push_type_args = NULL;
if (type.IsInstantiated()) {
push_type_args = PushArgument(BuildNullValue(node->token_pos()));
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index 13159ba..b98a3fc 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -43,7 +43,6 @@
DEFINE_FLAG(bool, source_lines, false, "Emit source line as assembly comment.");
DEFINE_FLAG(bool, trace_inlining_intervals, false,
"Inlining interval diagnostics");
-DEFINE_FLAG(bool, use_megamorphic_stub, true, "Out of line megamorphic lookup");
DECLARE_FLAG(bool, code_comments);
DECLARE_FLAG(charp, deoptimize_filter);
@@ -85,9 +84,7 @@
FLAG_inlining_constant_arguments_min_size_threshold = 30;
FLAG_background_compilation = false;
- FLAG_always_megamorphic_calls = true;
FLAG_fields_may_be_reset = true;
- FLAG_ic_range_profiling = false;
FLAG_interpret_irregexp = true;
FLAG_lazy_dispatchers = false;
FLAG_link_natives_lazily = true;
@@ -356,7 +353,7 @@
bool FlowGraphCompiler::ForceSlowPathForStackOverflow() const {
if ((FLAG_stacktrace_every > 0) ||
(FLAG_deoptimize_every > 0) ||
- (FLAG_reload_every > 0)) {
+ (isolate()->reload_every_n_stack_overflow_checks() > 0)) {
return true;
}
if (FLAG_stacktrace_filter != NULL &&
@@ -1198,12 +1195,6 @@
deopt_id, token_pos, locs);
return;
}
- if (FLAG_always_megamorphic_calls) {
- EmitMegamorphicInstanceCall(ic_data_in, argument_count,
- deopt_id, token_pos, locs,
- CatchClauseNode::kInvalidTryIndex);
- return;
- }
ASSERT(!ic_data.IsNull());
if (is_optimizing() && (ic_data_in.NumberOfUsedChecks() == 0)) {
// Emit IC call that will count and thus may need reoptimization at
diff --git a/runtime/vm/flow_graph_compiler.h b/runtime/vm/flow_graph_compiler.h
index 0a30dc9..7541f1b 100644
--- a/runtime/vm/flow_graph_compiler.h
+++ b/runtime/vm/flow_graph_compiler.h
@@ -199,7 +199,6 @@
Label* exit_label() { return &exit_label_; }
void GenerateCode(FlowGraphCompiler* compiler) {
- ASSERT(exit_label_.IsBound());
EmitNativeCode(compiler);
ASSERT(entry_label_.IsBound());
}
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index 4162943..8d8626c 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -27,7 +27,6 @@
DEFINE_FLAG(bool, unbox_mints, true, "Optimize 64-bit integer arithmetic.");
DEFINE_FLAG(bool, unbox_doubles, true, "Optimize double arithmetic.");
DECLARE_FLAG(bool, enable_simd_inline);
-DECLARE_FLAG(bool, use_megamorphic_stub);
void MegamorphicSlowPath::EmitNativeCode(FlowGraphCompiler* compiler) {
@@ -1056,13 +1055,8 @@
// No such checking code is generated if only fixed parameters are declared,
// unless we are in debug mode or unless we are compiling a closure.
if (num_copied_params == 0) {
-#ifdef DEBUG
- ASSERT(!parsed_function().function().HasOptionalParameters());
- const bool check_arguments = !flow_graph().IsCompiledForOsr();
-#else
const bool check_arguments =
function.IsClosureFunction() && !flow_graph().IsCompiledForOsr();
-#endif
if (check_arguments) {
__ Comment("Check argument count");
// Check that exactly num_fixed arguments are passed in.
@@ -1075,14 +1069,10 @@
__ cmp(R0, Operand(R1));
__ b(&correct_num_arguments, EQ);
__ Bind(&wrong_num_arguments);
- if (function.IsClosureFunction()) {
- ASSERT(assembler()->constant_pool_allowed());
- __ LeaveDartFrame(kKeepCalleePP); // Arguments are still on the stack.
- __ Branch(*StubCode::CallClosureNoSuchMethod_entry());
- // The noSuchMethod call may return to the caller, but not here.
- } else {
- __ Stop("Wrong number of arguments");
- }
+ ASSERT(assembler()->constant_pool_allowed());
+ __ LeaveDartFrame(kKeepCalleePP); // Arguments are still on the stack.
+ __ Branch(*StubCode::CallClosureNoSuchMethod_entry());
+ // The noSuchMethod call may return to the caller, but not here.
__ Bind(&correct_num_arguments);
}
} else if (!flow_graph().IsCompiledForOsr()) {
@@ -1342,11 +1332,8 @@
__ Comment("Slow case: megamorphic call");
}
__ LoadObject(R9, cache);
- if (FLAG_use_megamorphic_stub) {
- __ BranchLink(*StubCode::MegamorphicLookup_entry());
- } else {
- StubCode::EmitMegamorphicLookup(assembler());
- }
+ __ ldr(LR, Address(THR, Thread::megamorphic_lookup_entry_point_offset()));
+ __ blx(LR);
__ blx(R1);
__ Bind(&done);
@@ -1432,7 +1419,12 @@
intptr_t deopt_id,
TokenPosition token_pos,
LocationSummary* locs) {
- __ LoadObject(R4, arguments_descriptor);
+ ASSERT(!function.IsClosureFunction());
+ if (function.HasOptionalParameters()) {
+ __ LoadObject(R4, arguments_descriptor);
+ } else {
+ __ LoadImmediate(R4, 0); // GC safe smi zero because of stub.
+ }
// 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.
GenerateStaticDartCall(deopt_id,
diff --git a/runtime/vm/flow_graph_compiler_arm64.cc b/runtime/vm/flow_graph_compiler_arm64.cc
index d0c066e..178482a 100644
--- a/runtime/vm/flow_graph_compiler_arm64.cc
+++ b/runtime/vm/flow_graph_compiler_arm64.cc
@@ -25,7 +25,6 @@
DEFINE_FLAG(bool, trap_on_deoptimization, false, "Trap on deoptimization.");
DECLARE_FLAG(bool, enable_simd_inline);
-DECLARE_FLAG(bool, use_megamorphic_stub);
void MegamorphicSlowPath::EmitNativeCode(FlowGraphCompiler* compiler) {
@@ -1051,13 +1050,8 @@
// No such checking code is generated if only fixed parameters are declared,
// unless we are in debug mode or unless we are compiling a closure.
if (num_copied_params == 0) {
-#ifdef DEBUG
- ASSERT(!parsed_function().function().HasOptionalParameters());
- const bool check_arguments = !flow_graph().IsCompiledForOsr();
-#else
const bool check_arguments =
function.IsClosureFunction() && !flow_graph().IsCompiledForOsr();
-#endif
if (check_arguments) {
__ Comment("Check argument count");
// Check that exactly num_fixed arguments are passed in.
@@ -1070,13 +1064,9 @@
__ CompareRegisters(R0, R1);
__ b(&correct_num_arguments, EQ);
__ Bind(&wrong_num_arguments);
- if (function.IsClosureFunction()) {
- __ LeaveDartFrame(kKeepCalleePP); // Arguments are still on the stack.
- __ BranchPatchable(*StubCode::CallClosureNoSuchMethod_entry());
- // The noSuchMethod call may return to the caller, but not here.
- } else {
- __ Stop("Wrong number of arguments");
- }
+ __ LeaveDartFrame(kKeepCalleePP); // Arguments are still on the stack.
+ __ BranchPatchable(*StubCode::CallClosureNoSuchMethod_entry());
+ // The noSuchMethod call may return to the caller, but not here.
__ Bind(&correct_num_arguments);
}
} else if (!flow_graph().IsCompiledForOsr()) {
@@ -1324,11 +1314,8 @@
}
__ LoadObject(R5, cache);
- if (FLAG_use_megamorphic_stub) {
- __ BranchLink(*StubCode::MegamorphicLookup_entry());
- } else {
- StubCode::EmitMegamorphicLookup(assembler());
- }
+ __ ldr(LR, Address(THR, Thread::megamorphic_lookup_entry_point_offset()));
+ __ blr(LR);
__ blr(R1);
__ Bind(&done);
@@ -1413,7 +1400,12 @@
intptr_t deopt_id,
TokenPosition token_pos,
LocationSummary* locs) {
- __ LoadObject(R4, arguments_descriptor);
+ ASSERT(!function.IsClosureFunction());
+ if (function.HasOptionalParameters()) {
+ __ LoadObject(R4, arguments_descriptor);
+ } else {
+ __ LoadImmediate(R4, 0); // GC safe smi zero because of stub.
+ }
// 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.
GenerateStaticDartCall(deopt_id,
diff --git a/runtime/vm/flow_graph_compiler_dbc.cc b/runtime/vm/flow_graph_compiler_dbc.cc
index 8fb0b4c..fc1534d 100644
--- a/runtime/vm/flow_graph_compiler_dbc.cc
+++ b/runtime/vm/flow_graph_compiler_dbc.cc
@@ -27,7 +27,6 @@
DEFINE_FLAG(bool, unbox_mints, true, "Optimize 64-bit integer arithmetic.");
DEFINE_FLAG(bool, unbox_doubles, true, "Optimize double arithmetic.");
DECLARE_FLAG(bool, enable_simd_inline);
-DECLARE_FLAG(bool, use_megamorphic_stub);
DECLARE_FLAG(charp, optimization_filter);
void MegamorphicSlowPath::EmitNativeCode(FlowGraphCompiler* compiler) {
@@ -45,7 +44,12 @@
bool FlowGraphCompiler::SupportsUnboxedDoubles() {
+#if defined(ARCH_IS_64_BIT)
+ return true;
+#else
+ // We use 64-bit wide stack slots to unbox doubles.
return false;
+#endif
}
@@ -423,7 +427,18 @@
} else if (source.IsRegister() && destination.IsRegister()) {
__ Move(destination.reg(), source.reg());
} else if (source.IsConstant() && destination.IsRegister()) {
- __ LoadConstant(destination.reg(), source.constant());
+ if (source.constant_instruction()->representation() == kUnboxedDouble) {
+ const Register result = destination.reg();
+ const Object& constant = source.constant();
+ if (Utils::DoublesBitEqual(Double::Cast(constant).value(), 0.0)) {
+ __ BitXor(result, result, result);
+ } else {
+ __ LoadConstant(result, constant);
+ __ UnboxDouble(result, result);
+ }
+ } else {
+ __ LoadConstant(destination.reg(), source.constant());
+ }
} else {
compiler_->Bailout("Unsupported move");
UNREACHABLE();
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index 4a036e2..4fc5628 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -29,7 +29,6 @@
DEFINE_FLAG(bool, unbox_mints, true, "Optimize 64-bit integer arithmetic.");
DECLARE_FLAG(bool, enable_simd_inline);
-DECLARE_FLAG(bool, use_megamorphic_stub);
void MegamorphicSlowPath::EmitNativeCode(FlowGraphCompiler* compiler) {
@@ -1055,13 +1054,8 @@
// No such checking code is generated if only fixed parameters are declared,
// unless we are in debug mode or unless we are compiling a closure.
if (num_copied_params == 0) {
-#ifdef DEBUG
- ASSERT(!parsed_function().function().HasOptionalParameters());
- const bool check_arguments = !flow_graph().IsCompiledForOsr();
-#else
const bool check_arguments =
function.IsClosureFunction() && !flow_graph().IsCompiledForOsr();
-#endif
if (check_arguments) {
__ Comment("Check argument count");
// Check that exactly num_fixed arguments are passed in.
@@ -1075,13 +1069,9 @@
__ j(EQUAL, &correct_num_arguments, Assembler::kNearJump);
__ Bind(&wrong_num_arguments);
- if (function.IsClosureFunction()) {
- __ LeaveFrame(); // The arguments are still on the stack.
- __ Jmp(*StubCode::CallClosureNoSuchMethod_entry());
- // The noSuchMethod call may return to the caller, but not here.
- } else {
- __ Stop("Wrong number of arguments");
- }
+ __ LeaveFrame(); // The arguments are still on the stack.
+ __ Jmp(*StubCode::CallClosureNoSuchMethod_entry());
+ // The noSuchMethod call may return to the caller, but not here.
__ Bind(&correct_num_arguments);
}
} else if (!flow_graph().IsCompiledForOsr()) {
@@ -1319,11 +1309,7 @@
__ Comment("Slow case: megamorphic call");
}
__ LoadObject(ECX, cache);
- if (FLAG_use_megamorphic_stub) {
- __ Call(*StubCode::MegamorphicLookup_entry());
- } else {
- StubCode::EmitMegamorphicLookup(assembler());
- }
+ __ call(Address(THR, Thread::megamorphic_lookup_entry_point_offset()));
__ call(EBX);
__ Bind(&done);
@@ -1362,7 +1348,11 @@
intptr_t deopt_id,
TokenPosition token_pos,
LocationSummary* locs) {
- __ LoadObject(EDX, arguments_descriptor);
+ if (function.HasOptionalParameters()) {
+ __ LoadObject(EDX, arguments_descriptor);
+ } else {
+ __ xorl(EDX, EDX); // GC safe smi zero because of stub.
+ }
// 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,
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index 2376554..a6f3f14 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -23,7 +23,6 @@
namespace dart {
DEFINE_FLAG(bool, trap_on_deoptimization, false, "Trap on deoptimization.");
-DECLARE_FLAG(bool, use_megamorphic_stub);
void MegamorphicSlowPath::EmitNativeCode(FlowGraphCompiler* compiler) {
@@ -1073,13 +1072,8 @@
// No such checking code is generated if only fixed parameters are declared,
// unless we are in debug mode or unless we are compiling a closure.
if (num_copied_params == 0) {
-#ifdef DEBUG
- ASSERT(!parsed_function().function().HasOptionalParameters());
- const bool check_arguments = !flow_graph().IsCompiledForOsr();
-#else
const bool check_arguments =
function.IsClosureFunction() && !flow_graph().IsCompiledForOsr();
-#endif
if (check_arguments) {
__ Comment("Check argument count");
// Check that exactly num_fixed arguments are passed in.
@@ -1092,13 +1086,9 @@
ArgumentsDescriptor::positional_count_offset()));
__ beq(T0, T1, &correct_num_arguments);
__ Bind(&wrong_num_arguments);
- if (function.IsClosureFunction()) {
- __ LeaveDartFrame(kKeepCalleePP); // Arguments are still on the stack.
- __ Branch(*StubCode::CallClosureNoSuchMethod_entry());
- // The noSuchMethod call may return to the caller, but not here.
- } else {
- __ Stop("Wrong number of arguments");
- }
+ __ LeaveDartFrame(kKeepCalleePP); // Arguments are still on the stack.
+ __ Branch(*StubCode::CallClosureNoSuchMethod_entry());
+ // The noSuchMethod call may return to the caller, but not here.
__ Bind(&correct_num_arguments);
}
} else if (!flow_graph().IsCompiledForOsr()) {
@@ -1349,11 +1339,8 @@
__ Comment("Slow case: megamorphic call");
}
__ LoadObject(S5, cache);
- if (FLAG_use_megamorphic_stub) {
- __ BranchLink(*StubCode::MegamorphicLookup_entry());
- } else {
- StubCode::EmitMegamorphicLookup(assembler());
- }
+ __ lw(T9, Address(THR, Thread::megamorphic_lookup_entry_point_offset()));
+ __ jalr(T9);
__ jalr(T1);
__ Bind(&done);
@@ -1439,7 +1426,12 @@
TokenPosition token_pos,
LocationSummary* locs) {
__ Comment("StaticCall");
- __ LoadObject(S4, arguments_descriptor);
+ ASSERT(!function.IsClosureFunction());
+ if (function.HasOptionalParameters()) {
+ __ LoadObject(S4, arguments_descriptor);
+ } else {
+ __ LoadImmediate(S4, 0); // GC safe smi zero because of stub.
+ }
// 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.
GenerateStaticDartCall(deopt_id,
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index 5cc5c93..4c60d20 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -25,7 +25,7 @@
DEFINE_FLAG(bool, trap_on_deoptimization, false, "Trap on deoptimization.");
DEFINE_FLAG(bool, unbox_mints, true, "Optimize 64-bit integer arithmetic.");
DECLARE_FLAG(bool, enable_simd_inline);
-DECLARE_FLAG(bool, use_megamorphic_stub);
+
void MegamorphicSlowPath::EmitNativeCode(FlowGraphCompiler* compiler) {
Assembler* assembler = compiler->assembler();
@@ -1057,13 +1057,8 @@
// No such checking code is generated if only fixed parameters are declared,
// unless we are in debug mode or unless we are compiling a closure.
if (num_copied_params == 0) {
-#ifdef DEBUG
- ASSERT(!parsed_function().function().HasOptionalParameters());
- const bool check_arguments = !flow_graph().IsCompiledForOsr();
-#else
const bool check_arguments =
function.IsClosureFunction() && !flow_graph().IsCompiledForOsr();
-#endif
if (check_arguments) {
__ Comment("Check argument count");
// Check that exactly num_fixed arguments are passed in.
@@ -1077,13 +1072,9 @@
__ j(EQUAL, &correct_num_arguments, Assembler::kNearJump);
__ Bind(&wrong_num_arguments);
- if (function.IsClosureFunction()) {
- __ LeaveDartFrame(kKeepCalleePP); // Leave arguments on the stack.
- __ Jmp(*StubCode::CallClosureNoSuchMethod_entry());
- // The noSuchMethod call may return to the caller, but not here.
- } else {
- __ Stop("Wrong number of arguments");
- }
+ __ LeaveDartFrame(kKeepCalleePP); // Leave arguments on the stack.
+ __ Jmp(*StubCode::CallClosureNoSuchMethod_entry());
+ // The noSuchMethod call may return to the caller, but not here.
__ Bind(&correct_num_arguments);
}
} else if (!flow_graph().IsCompiledForOsr()) {
@@ -1348,11 +1339,7 @@
__ Comment("Slow case: megamorphic call");
}
__ LoadObject(RBX, cache);
- if (FLAG_use_megamorphic_stub) {
- __ Call(*StubCode::MegamorphicLookup_entry());
- } else {
- StubCode::EmitMegamorphicLookup(assembler());
- }
+ __ call(Address(THR, Thread::megamorphic_lookup_entry_point_offset()));
__ call(RCX);
__ Bind(&done);
@@ -1419,7 +1406,12 @@
intptr_t deopt_id,
TokenPosition token_pos,
LocationSummary* locs) {
- __ LoadObject(R10, arguments_descriptor);
+ ASSERT(!function.IsClosureFunction());
+ if (function.HasOptionalParameters()) {
+ __ LoadObject(R10, arguments_descriptor);
+ } else {
+ __ xorq(R10, R10); // GC safe smi zero because of stub.
+ }
// 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.
GenerateStaticDartCall(deopt_id,
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index f93b1d1..a8e27c0 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -634,7 +634,9 @@
// Don't inline any intrinsified functions in precompiled mode
// to reduce code size and make sure we use the intrinsic code.
- if (FLAG_precompiled_mode && function.is_intrinsic()) {
+ if (FLAG_precompiled_mode &&
+ function.is_intrinsic() &&
+ !inliner_->AlwaysInline(function)) {
TRACE_INLINING(THR_Print(" Bailout: intrinisic\n"));
PRINT_INLINING_TREE("intrinsic",
&call_data->caller, &function, call_data->call);
@@ -2045,15 +2047,6 @@
Definition** array,
Definition* index,
Instruction** cursor) {
- // Insert index smi check.
- *cursor = flow_graph->AppendTo(
- *cursor,
- new(Z) CheckSmiInstr(new(Z) Value(index),
- call->deopt_id(),
- call->token_pos()),
- call->env(),
- FlowGraph::kEffect);
-
// Insert array length load and bounds check.
LoadFieldInstr* length =
new(Z) LoadFieldInstr(
@@ -2460,6 +2453,29 @@
}
+static bool InlineSmiBitAndFromSmi(FlowGraph* flow_graph,
+ Instruction* call,
+ TargetEntryInstr** entry,
+ Definition** last) {
+ Definition* left = call->ArgumentAt(0);
+ Definition* right = call->ArgumentAt(1);
+
+ *entry = new(Z) TargetEntryInstr(flow_graph->allocate_block_id(),
+ call->GetBlock()->try_index());
+ (*entry)->InheritDeoptTarget(Z, call);
+ // Right arguments is known to be smi: other._bitAndFromSmi(this);
+ BinarySmiOpInstr* smi_op =
+ new(Z) BinarySmiOpInstr(Token::kBIT_AND,
+ new(Z) Value(left),
+ new(Z) Value(right),
+ call->deopt_id());
+ flow_graph->AppendTo(*entry, smi_op, call->env(), FlowGraph::kValue);
+ *last = smi_op;
+
+ return true;
+}
+
+
static bool InlineGrowableArraySetter(FlowGraph* flow_graph,
intptr_t offset,
StoreBarrierType store_barrier_type,
@@ -2495,15 +2511,6 @@
Definition** array,
Definition* byte_index,
Instruction** cursor) {
- // Insert byte_index smi check.
- *cursor = flow_graph->AppendTo(*cursor,
- new(Z) CheckSmiInstr(
- new(Z) Value(byte_index),
- call->deopt_id(),
- call->token_pos()),
- call->env(),
- FlowGraph::kEffect);
-
LoadFieldInstr* length =
new(Z) LoadFieldInstr(
new(Z) Value(*array),
@@ -2804,15 +2811,6 @@
Definition* str,
Definition* index,
Instruction* cursor) {
-
- cursor = flow_graph->AppendTo(cursor,
- new(Z) CheckSmiInstr(
- new(Z) Value(index),
- call->deopt_id(),
- call->token_pos()),
- call->env(),
- FlowGraph::kEffect);
-
// Load the length of the string.
// Treat length loads as mutable (i.e. affected by side effects) to avoid
// hoisting them since we can't hoist the preceding class-check. This
@@ -3227,6 +3225,8 @@
return InlineGrowableArraySetter(
flow_graph, GrowableObjectArray::length_offset(), kNoStoreBarrier,
call, entry, last);
+ case MethodRecognizer::kSmi_bitAndFromSmi:
+ return InlineSmiBitAndFromSmi(flow_graph, call, entry, last);
default:
return false;
}
diff --git a/runtime/vm/flow_graph_range_analysis.cc b/runtime/vm/flow_graph_range_analysis.cc
index 70a9dc5..1e7afbd 100644
--- a/runtime/vm/flow_graph_range_analysis.cc
+++ b/runtime/vm/flow_graph_range_analysis.cc
@@ -693,6 +693,7 @@
}
if (!range.Equals(defn->range())) {
+#ifndef PRODUCT
if (FLAG_support_il_printer && FLAG_trace_range_analysis) {
THR_Print("%c [%" Pd "] %s: %s => %s\n",
OpPrefix(op),
@@ -701,6 +702,7 @@
Range::ToCString(defn->range()),
Range::ToCString(&range));
}
+#endif // !PRODUCT
defn->set_range(range);
return true;
}
@@ -1022,12 +1024,14 @@
// range give up on generalization for simplicity.
GrowableArray<Definition*> non_positive_symbols;
if (!FindNonPositiveSymbols(&non_positive_symbols, upper_bound)) {
+#ifndef PRODUCT
if (FLAG_support_il_printer && FLAG_trace_range_analysis) {
THR_Print("Failed to generalize %s index to %s"
" (can't ensure positivity)\n",
check->ToCString(),
IndexBoundToCString(upper_bound));
}
+#endif // !PRODUCT
return;
}
@@ -1056,21 +1060,25 @@
if (!RangeUtils::IsPositive(lower_bound->range())) {
// Can't prove that lower bound is positive even with additional checks
// against potentially non-positive symbols. Give up.
+#ifndef PRODUCT
if (FLAG_support_il_printer && FLAG_trace_range_analysis) {
THR_Print("Failed to generalize %s index to %s"
" (lower bound is not positive)\n",
check->ToCString(),
IndexBoundToCString(upper_bound));
}
+#endif // !PRODUCT
return;
}
+#ifndef PRODUCT
if (FLAG_support_il_printer && FLAG_trace_range_analysis) {
THR_Print("For %s computed index bounds [%s, %s]\n",
check->ToCString(),
IndexBoundToCString(lower_bound),
IndexBoundToCString(upper_bound));
}
+#endif // !PRODUCT
// At this point we know that 0 <= index < UpperBound(index) under
// certain preconditions. Start by emitting this preconditions.
@@ -1493,6 +1501,7 @@
return defn;
}
+#ifndef PRODUCT
static void PrettyPrintIndexBoundRecursively(BufferFormatter* f,
Definition* index_bound) {
BinarySmiOpInstr* binary_op = index_bound->AsBinarySmiOp();
@@ -1518,6 +1527,7 @@
PrettyPrintIndexBoundRecursively(&f, index_bound);
return Thread::Current()->zone()->MakeCopyOfString(buffer);
}
+#endif // !PRODUCT
RangeAnalysis* range_analysis_;
FlowGraph* flow_graph_;
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
index 2ee8ed1..2162cfe 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -237,6 +237,13 @@
}
+void FlowGraphTypePropagator::VisitCheckArrayBound(
+ CheckArrayBoundInstr* check) {
+ // Array bounds checks also test index for smi.
+ SetCid(check->index()->definition(), kSmiCid);
+}
+
+
void FlowGraphTypePropagator::VisitCheckClass(CheckClassInstr* check) {
if ((check->unary_checks().NumberOfChecks() != 1) ||
!check->Dependencies().IsNone()) {
diff --git a/runtime/vm/flow_graph_type_propagator.h b/runtime/vm/flow_graph_type_propagator.h
index 3c10917..7a5e87e 100644
--- a/runtime/vm/flow_graph_type_propagator.h
+++ b/runtime/vm/flow_graph_type_propagator.h
@@ -27,6 +27,7 @@
virtual void VisitJoinEntry(JoinEntryInstr* instr);
virtual void VisitCheckSmi(CheckSmiInstr* instr);
+ virtual void VisitCheckArrayBound(CheckArrayBoundInstr* instr);
virtual void VisitCheckClass(CheckClassInstr* instr);
virtual void VisitCheckClassId(CheckClassIdInstr* instr);
virtual void VisitGuardFieldClass(GuardFieldClassInstr* instr);
diff --git a/runtime/vm/gc_marker.cc b/runtime/vm/gc_marker.cc
index ae0e205..319716e 100644
--- a/runtime/vm/gc_marker.cc
+++ b/runtime/vm/gc_marker.cc
@@ -534,6 +534,7 @@
void GCMarker::ProcessObjectIdTable(Isolate* isolate) {
+#ifndef PRODUCT
if (!FLAG_support_service) {
return;
}
@@ -541,6 +542,7 @@
ObjectIdRing* ring = isolate->object_id_ring();
ASSERT(ring != NULL);
ring->VisitPointers(&visitor);
+#endif // !PRODUCT
}
@@ -666,6 +668,7 @@
template<class MarkingVisitorType>
void GCMarker::FinalizeResultsFrom(MarkingVisitorType* visitor) {
+#ifndef PRODUCT
{
MutexLocker ml(&stats_mutex_);
marked_bytes_ += visitor->marked_bytes();
@@ -680,6 +683,7 @@
}
}
}
+#endif // !PRODUCT
visitor->Finalize();
}
diff --git a/runtime/vm/gc_sweeper.cc b/runtime/vm/gc_sweeper.cc
index 5b7949b..e37f1db 100644
--- a/runtime/vm/gc_sweeper.cc
+++ b/runtime/vm/gc_sweeper.cc
@@ -152,7 +152,7 @@
{
MonitorLocker ml(old_space_->tasks_lock());
old_space_->set_tasks(old_space_->tasks() - 1);
- ml.Notify();
+ ml.NotifyAll();
}
}
diff --git a/runtime/vm/heap.cc b/runtime/vm/heap.cc
index 21a4b46..83bacb1 100644
--- a/runtime/vm/heap.cc
+++ b/runtime/vm/heap.cc
@@ -236,7 +236,7 @@
#endif
ASSERT(old_space_->tasks() == 1);
old_space_->set_tasks(0);
- ml.Notify();
+ ml.NotifyAll();
}
@@ -350,6 +350,7 @@
}
+#ifndef PRODUCT
void Heap::UpdateClassHeapStatsBeforeGC(Heap::Space space) {
ClassTable* class_table = isolate()->class_table();
if (space == kNew) {
@@ -358,6 +359,7 @@
class_table->ResetCountersOld();
}
}
+#endif
void Heap::CollectNewSpaceGarbage(Thread* thread,
@@ -369,9 +371,9 @@
RecordBeforeGC(kNew, reason);
VMTagScope tagScope(thread, VMTag::kGCNewSpaceTagId);
TIMELINE_FUNCTION_GC_DURATION(thread, "CollectNewGeneration");
- UpdateClassHeapStatsBeforeGC(kNew);
+ NOT_IN_PRODUCT(UpdateClassHeapStatsBeforeGC(kNew));
new_space_.Scavenge(invoke_api_callbacks);
- isolate()->class_table()->UpdatePromoted();
+ NOT_IN_PRODUCT(isolate()->class_table()->UpdatePromoted());
RecordAfterGC(kNew);
PrintStats();
NOT_IN_PRODUCT(PrintStatsToTimeline(&tds));
@@ -393,7 +395,7 @@
RecordBeforeGC(kOld, reason);
VMTagScope tagScope(thread, VMTag::kGCOldSpaceTagId);
TIMELINE_FUNCTION_GC_DURATION(thread, "CollectOldGeneration");
- UpdateClassHeapStatsBeforeGC(kOld);
+ NOT_IN_PRODUCT(UpdateClassHeapStatsBeforeGC(kOld));
old_space_.MarkSweep(invoke_api_callbacks);
RecordAfterGC(kOld);
PrintStats();
@@ -729,11 +731,13 @@
stats_.after_.old_ = old_space_.GetCurrentUsage();
ASSERT((space == kNew && gc_new_space_in_progress_) ||
(space == kOld && gc_old_space_in_progress_));
+#ifndef PRODUCT
if (FLAG_support_service && Service::gc_stream.enabled()) {
ServiceEvent event(Isolate::Current(), ServiceEvent::kGC);
event.set_gc_stats(&stats_);
Service::HandleEvent(&event);
}
+#endif // !PRODUCT
}
diff --git a/runtime/vm/heap_test.cc b/runtime/vm/heap_test.cc
index 1d55a13..7454cf4 100644
--- a/runtime/vm/heap_test.cc
+++ b/runtime/vm/heap_test.cc
@@ -74,6 +74,7 @@
}
+#ifndef PRODUCT
class ClassHeapStatsTestHelper {
public:
static ClassHeapStats* GetHeapStatsForCid(ClassTable* class_table,
@@ -231,6 +232,7 @@
EXPECT_GT(expected_size + kTolerance, after - before);
Dart_ExitScope();
}
+#endif // !PRODUCT
class FindOnly : public FindObjectVisitor {
diff --git a/runtime/vm/il_printer.cc b/runtime/vm/il_printer.cc
index 5104545..d8d18f3 100644
--- a/runtime/vm/il_printer.cc
+++ b/runtime/vm/il_printer.cc
@@ -197,16 +197,6 @@
const ICData& ic_data,
intptr_t num_checks_to_print) {
f->Print(" IC[");
- if (ic_data.HasRangeFeedback()) {
- f->Print("{%s",
- ICData::RangeFeedbackToString(ic_data.DecodeRangeFeedbackAt(0)));
- if (ic_data.NumArgsTested() == 2) {
- f->Print(" x %s",
- ICData::RangeFeedbackToString(ic_data.DecodeRangeFeedbackAt(1)));
- }
- f->Print("->%s} ",
- ICData::RangeFeedbackToString(ic_data.DecodeRangeFeedbackAt(2)));
- }
f->Print("%" Pd ": ", ic_data.NumberOfChecks());
Function& target = Function::Handle();
if ((num_checks_to_print == FlowGraphPrinter::kPrintAll) ||
diff --git a/runtime/vm/instructions_dbc.cc b/runtime/vm/instructions_dbc.cc
index 4dc73be..d648d511 100644
--- a/runtime/vm/instructions_dbc.cc
+++ b/runtime/vm/instructions_dbc.cc
@@ -20,6 +20,7 @@
case Bytecode::kLoadConstant:
case Bytecode::kPushConstant:
case Bytecode::kStaticCall:
+ case Bytecode::kIndirectStaticCall:
case Bytecode::kInstanceCall1:
case Bytecode::kInstanceCall2:
case Bytecode::kInstanceCall1Opt:
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index 689d535..d1f8f92 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -3177,18 +3177,6 @@
ASSERT(ArgumentCount() == 2);
compiler->EmitInstanceCall(*stub_entry, *call_ic_data, ArgumentCount(),
deopt_id(), token_pos(), locs());
- } else if (FLAG_ic_range_profiling &&
- (Token::IsBinaryArithmeticOperator(token_kind()) ||
- Token::IsUnaryArithmeticOperator(token_kind()))) {
- ASSERT(Token::IsUnaryArithmeticOperator(token_kind()) ==
- (ArgumentCount() == 1));
- ASSERT(Token::IsBinaryArithmeticOperator(token_kind()) ==
- (ArgumentCount() == 2));
- 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(),
token_pos(),
@@ -3198,14 +3186,17 @@
}
}
#else
- ICData* ic_data = &ICData::ZoneHandle(call_ic_data->Original());
+ ICData* original_ic_data = &ICData::ZoneHandle(call_ic_data->Original());
// Emit smi fast path instruction. If fast-path succeeds it skips the next
- // instruction otherwise it falls through.
- TryFastPathSmiOp(compiler, ic_data, function_name());
+ // instruction otherwise it falls through. Only attempt in unoptimized code
+ // because TryFastPathSmiOp will update original_ic_data.
+ if (!compiler->is_optimizing()) {
+ TryFastPathSmiOp(compiler, original_ic_data, function_name());
+ }
- const intptr_t call_ic_data_kidx = __ AddConstant(*call_ic_data);
- switch (ic_data->NumArgsTested()) {
+ const intptr_t call_ic_data_kidx = __ AddConstant(*original_ic_data);
+ switch (original_ic_data->NumArgsTested()) {
case 1:
if (compiler->is_optimizing()) {
__ InstanceCall1Opt(ArgumentCount(), call_ic_data_kidx);
@@ -3292,7 +3283,6 @@
void StaticCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
-#if !defined(TARGET_ARCH_DBC)
const ICData* call_ic_data = NULL;
if (!FLAG_propagate_ic_data || !compiler->is_optimizing() ||
(ic_data() == NULL)) {
@@ -3318,6 +3308,8 @@
} else {
call_ic_data = &ICData::ZoneHandle(ic_data()->raw());
}
+
+#if !defined(TARGET_ARCH_DBC)
compiler->GenerateStaticCall(deopt_id(),
token_pos(),
function(),
@@ -3333,17 +3325,20 @@
Array::Handle(ic_data()->arguments_descriptor());
const intptr_t argdesc_kidx = __ AddConstant(arguments_descriptor);
- __ PushConstant(function());
- __ StaticCall(ArgumentCount(), argdesc_kidx);
- RawPcDescriptors::Kind kind = (compiler->is_optimizing())
- ? RawPcDescriptors::kOther
- : RawPcDescriptors::kUnoptStaticCall;
- compiler->AddCurrentDescriptor(kind, deopt_id(), token_pos());
-
- compiler->RecordAfterCall(this);
-
if (compiler->is_optimizing()) {
+ __ PushConstant(function());
+ __ StaticCall(ArgumentCount(), argdesc_kidx);
+ compiler->AddCurrentDescriptor(RawPcDescriptors::kOther,
+ deopt_id(), token_pos());
+ compiler->RecordAfterCall(this);
__ PopLocal(locs()->out(0).reg());
+ } else {
+ const intptr_t ic_data_kidx = __ AddConstant(*call_ic_data);
+ __ PushConstant(ic_data_kidx);
+ __ IndirectStaticCall(ArgumentCount(), argdesc_kidx);
+ compiler->AddCurrentDescriptor(RawPcDescriptors::kUnoptStaticCall,
+ deopt_id(), token_pos());
+ compiler->RecordAfterCall(this);
}
#endif // !defined(TARGET_ARCH_DBC)
}
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index 7307344..bfcb8a7 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -512,6 +512,7 @@
M(ShiftMintOp) \
M(UnaryMintOp) \
M(CheckArrayBound) \
+ M(GenericCheckBound) \
M(Constraint) \
M(StringToCharCode) \
M(OneByteStringFromCharCode) \
@@ -7928,6 +7929,35 @@
};
+class GenericCheckBoundInstr : public TemplateInstruction<2, Throws, NoCSE> {
+ public:
+ GenericCheckBoundInstr(Value* length, Value* index, intptr_t deopt_id)
+ : TemplateInstruction(deopt_id) {
+ SetInputAt(kLengthPos, length);
+ SetInputAt(kIndexPos, index);
+ }
+
+ Value* length() const { return inputs_[kLengthPos]; }
+ Value* index() const { return inputs_[kIndexPos]; }
+
+ virtual EffectSet Effects() const { return EffectSet::None(); }
+ virtual EffectSet Dependencies() const { return EffectSet::None(); }
+
+ DECLARE_INSTRUCTION(GenericCheckBound)
+
+ virtual bool CanDeoptimize() const { return true; }
+
+ // Give a name to the location/input indices.
+ enum {
+ kLengthPos = 0,
+ kIndexPos = 1
+ };
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GenericCheckBoundInstr);
+};
+
+
class UnboxedIntConverterInstr : public TemplateDefinition<1, NoThrow> {
public:
UnboxedIntConverterInstr(Representation from,
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index 1750418..aac4891 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -6111,8 +6111,7 @@
Label* deopt = compiler->AddDeoptStub(deopt_id(),
ICData::kDeoptCheckSmi,
licm_hoisted_ ? ICData::kHoisted : 0);
- __ tst(value, Operand(kSmiTagMask));
- __ b(deopt, NE);
+ __ BranchIfNotSmi(value, deopt);
}
@@ -6135,6 +6134,66 @@
}
+LocationSummary* GenericCheckBoundInstr::MakeLocationSummary(Zone* zone,
+ bool opt) const {
+ const intptr_t kNumInputs = 2;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* locs = new(zone) LocationSummary(
+ zone, kNumInputs, kNumTemps, LocationSummary::kCallOnSlowPath);
+ locs->set_in(kLengthPos, Location::RequiresRegister());
+ locs->set_in(kIndexPos, Location::RequiresRegister());
+ return locs;
+}
+
+
+class RangeErrorSlowPath : public SlowPathCode {
+ public:
+ RangeErrorSlowPath(GenericCheckBoundInstr* instruction, intptr_t try_index)
+ : instruction_(instruction), try_index_(try_index) { }
+
+ virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
+ if (Assembler::EmittingComments()) {
+ __ Comment("slow path check bound operation");
+ }
+ __ Bind(entry_label());
+ LocationSummary* locs = instruction_->locs();
+ __ Push(locs->in(0).reg());
+ __ Push(locs->in(1).reg());
+ __ CallRuntime(kRangeErrorRuntimeEntry, 2);
+ compiler->pc_descriptors_list()->AddDescriptor(
+ RawPcDescriptors::kOther,
+ compiler->assembler()->CodeSize(),
+ instruction_->deopt_id(),
+ instruction_->token_pos(),
+ try_index_);
+ compiler->RecordSafepoint(locs, 2);
+ __ bkpt(0);
+ }
+
+ private:
+ GenericCheckBoundInstr* instruction_;
+ intptr_t try_index_;
+};
+
+
+void GenericCheckBoundInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ RangeErrorSlowPath* slow_path =
+ new RangeErrorSlowPath(this, compiler->CurrentTryIndex());
+ compiler->AddSlowPathCode(slow_path);
+
+ Location length_loc = locs()->in(kLengthPos);
+ Location index_loc = locs()->in(kIndexPos);
+ Register length = length_loc.reg();
+ Register index = index_loc.reg();
+ const intptr_t index_cid = this->index()->Type()->ToCid();
+ if (index_cid != kSmiCid) {
+ __ BranchIfNotSmi(index, slow_path->entry_label());
+ }
+ __ cmp(index, Operand(length));
+ __ b(slow_path->entry_label(), CS);
+}
+
+
LocationSummary* CheckArrayBoundInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
const intptr_t kNumInputs = 2;
@@ -6168,6 +6227,7 @@
return;
}
+ const intptr_t index_cid = index()->Type()->ToCid();
if (index_loc.IsConstant()) {
const Register length = length_loc.reg();
const Smi& index = Smi::Cast(index_loc.constant());
@@ -6176,6 +6236,9 @@
} else if (length_loc.IsConstant()) {
const Smi& length = Smi::Cast(length_loc.constant());
const Register index = index_loc.reg();
+ if (index_cid != kSmiCid) {
+ __ BranchIfNotSmi(index, deopt);
+ }
if (length.Value() == Smi::kMaxValue) {
__ tst(index, Operand(index));
__ b(deopt, MI);
@@ -6186,6 +6249,9 @@
} else {
const Register length = length_loc.reg();
const Register index = index_loc.reg();
+ if (index_cid != kSmiCid) {
+ __ BranchIfNotSmi(index, deopt);
+ }
__ cmp(index, Operand(length));
__ b(deopt, CS);
}
diff --git a/runtime/vm/intermediate_language_arm64.cc b/runtime/vm/intermediate_language_arm64.cc
index 642bc9e..c4f0fdc 100644
--- a/runtime/vm/intermediate_language_arm64.cc
+++ b/runtime/vm/intermediate_language_arm64.cc
@@ -5254,8 +5254,68 @@
Label* deopt = compiler->AddDeoptStub(deopt_id(),
ICData::kDeoptCheckSmi,
licm_hoisted_ ? ICData::kHoisted : 0);
- __ tsti(value, Immediate(kSmiTagMask));
- __ b(deopt, NE);
+ __ BranchIfNotSmi(value, deopt);
+}
+
+
+
+LocationSummary* GenericCheckBoundInstr::MakeLocationSummary(Zone* zone,
+ bool opt) const {
+ const intptr_t kNumInputs = 2;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* locs = new(zone) LocationSummary(
+ zone, kNumInputs, kNumTemps, LocationSummary::kCallOnSlowPath);
+ locs->set_in(kLengthPos, Location::RequiresRegister());
+ locs->set_in(kIndexPos, Location::RequiresRegister());
+ return locs;
+}
+
+
+class RangeErrorSlowPath : public SlowPathCode {
+ public:
+ RangeErrorSlowPath(GenericCheckBoundInstr* instruction, intptr_t try_index)
+ : instruction_(instruction), try_index_(try_index) { }
+
+ virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
+ if (Assembler::EmittingComments()) {
+ __ Comment("slow path check bound operation");
+ }
+ __ Bind(entry_label());
+ LocationSummary* locs = instruction_->locs();
+ __ Push(locs->in(0).reg());
+ __ Push(locs->in(1).reg());
+ __ CallRuntime(kRangeErrorRuntimeEntry, 2);
+ compiler->pc_descriptors_list()->AddDescriptor(
+ RawPcDescriptors::kOther,
+ compiler->assembler()->CodeSize(),
+ instruction_->deopt_id(),
+ instruction_->token_pos(),
+ try_index_);
+ compiler->RecordSafepoint(locs, 2);
+ __ brk(0);
+ }
+
+ private:
+ GenericCheckBoundInstr* instruction_;
+ intptr_t try_index_;
+};
+
+
+void GenericCheckBoundInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ RangeErrorSlowPath* slow_path =
+ new RangeErrorSlowPath(this, compiler->CurrentTryIndex());
+ compiler->AddSlowPathCode(slow_path);
+
+ Location length_loc = locs()->in(kLengthPos);
+ Location index_loc = locs()->in(kIndexPos);
+ Register length = length_loc.reg();
+ Register index = index_loc.reg();
+ const intptr_t index_cid = this->index()->Type()->ToCid();
+ if (index_cid != kSmiCid) {
+ __ BranchIfNotSmi(index, slow_path->entry_label());
+ }
+ __ cmp(index, Operand(length));
+ __ b(slow_path->entry_label(), CS);
}
@@ -5282,6 +5342,7 @@
Location length_loc = locs()->in(kLengthPos);
Location index_loc = locs()->in(kIndexPos);
+ const intptr_t index_cid = index()->Type()->ToCid();
if (length_loc.IsConstant() && index_loc.IsConstant()) {
// TODO(srdjan): remove this code once failures are fixed.
if ((Smi::Cast(length_loc.constant()).Value() >
@@ -5307,6 +5368,9 @@
} else if (length_loc.IsConstant()) {
const Smi& length = Smi::Cast(length_loc.constant());
const Register index = index_loc.reg();
+ if (index_cid != kSmiCid) {
+ __ BranchIfNotSmi(index, deopt);
+ }
if (length.Value() == Smi::kMaxValue) {
__ tst(index, Operand(index));
__ b(deopt, MI);
@@ -5317,6 +5381,9 @@
} else {
const Register length = length_loc.reg();
const Register index = index_loc.reg();
+ if (index_cid != kSmiCid) {
+ __ BranchIfNotSmi(index, deopt);
+ }
__ CompareRegisters(index, length);
__ b(deopt, CS);
}
diff --git a/runtime/vm/intermediate_language_dbc.cc b/runtime/vm/intermediate_language_dbc.cc
index 8c954b6..0dda8e1 100644
--- a/runtime/vm/intermediate_language_dbc.cc
+++ b/runtime/vm/intermediate_language_dbc.cc
@@ -30,36 +30,43 @@
// List of instructions that are still unimplemented by DBC backend.
#define FOR_EACH_UNIMPLEMENTED_INSTRUCTION(M) \
- M(IndirectGoto) \
M(LoadCodeUnits) \
M(LoadUntagged) \
M(AllocateUninitializedContext) \
M(BinaryInt32Op) \
- M(UnaryDoubleOp) \
- M(SmiToDouble) \
M(Int32ToDouble) \
- M(MintToDouble) \
M(DoubleToInteger) \
- M(DoubleToSmi) \
M(DoubleToDouble) \
M(DoubleToFloat) \
M(FloatToDouble) \
- M(UnboxedConstant) \
- M(BinaryDoubleOp) \
- M(MathUnary) \
- M(MathMinMax) \
- M(Box) \
- M(Unbox) \
M(BoxInt64) \
- M(CaseInsensitiveCompareUC16) \
- M(BinaryMintOp) \
- M(ShiftMintOp) \
- M(UnaryMintOp) \
- M(InvokeMathCFunction) \
M(MergedMath) \
M(GuardFieldClass) \
M(GuardFieldLength) \
M(IfThenElse) \
+ M(ExtractNthOutput) \
+ M(BinaryUint32Op) \
+ M(ShiftUint32Op) \
+ M(UnaryUint32Op) \
+ M(UnboxedIntConverter) \
+ M(BoxInteger32) \
+ M(UnboxInteger32) \
+
+// List of instructions that are not used by DBC.
+// Things we aren't planning to implement for DBC:
+// - Unboxed SIMD,
+// - Unboxed Mint,
+// - Optimized RegExps,
+// - Precompilation.
+#define FOR_EACH_UNREACHABLE_INSTRUCTION(M) \
+ M(CaseInsensitiveCompareUC16) \
+ M(GenericCheckBound) \
+ M(GrowRegExpStack) \
+ M(IndirectGoto) \
+ M(MintToDouble) \
+ M(BinaryMintOp) \
+ M(ShiftMintOp) \
+ M(UnaryMintOp) \
M(BinaryFloat32x4Op) \
M(Simd32x4Shuffle) \
M(Simd32x4ShuffleMix) \
@@ -82,7 +89,6 @@
M(Int32x4SetFlag) \
M(Int32x4ToFloat32x4) \
M(BinaryInt32x4Op) \
- M(TestCids) \
M(BinaryFloat64x2Op) \
M(Float64x2Zero) \
M(Float64x2Constructor) \
@@ -92,19 +98,7 @@
M(Simd64x2Shuffle) \
M(Float64x2ZeroArg) \
M(Float64x2OneArg) \
- M(ExtractNthOutput) \
- M(BinaryUint32Op) \
- M(ShiftUint32Op) \
- M(UnaryUint32Op) \
- M(UnboxedIntConverter) \
- M(GrowRegExpStack) \
- M(BoxInteger32) \
- M(UnboxInteger32) \
M(CheckedSmiOp) \
- M(CheckArrayBound) \
- M(RelationalOp) \
- M(EqualityCompare) \
- M(LoadIndexed)
// Location summaries actually are not used by the unoptimizing DBC compiler
// because we don't allocate any registers.
@@ -112,14 +106,17 @@
Zone* zone,
intptr_t num_inputs,
Location output = Location::NoLocation(),
- LocationSummary::ContainsCall contains_call = LocationSummary::kNoCall) {
- const intptr_t kNumTemps = 0;
+ LocationSummary::ContainsCall contains_call = LocationSummary::kNoCall,
+ intptr_t num_temps = 0) {
LocationSummary* locs = new(zone) LocationSummary(
- zone, num_inputs, kNumTemps, contains_call);
+ zone, num_inputs, num_temps, contains_call);
for (intptr_t i = 0; i < num_inputs; i++) {
locs->set_in(i, (contains_call == LocationSummary::kNoCall) ?
Location::RequiresRegister() : Location::RegisterLocation(i));
}
+ for (intptr_t i = 0; i < num_temps; i++) {
+ locs->set_temp(i, Location::RequiresRegister());
+ }
if (!output.IsInvalid()) {
// For instructions that call we default to returning result in R0.
locs->set_out(0, output);
@@ -145,11 +142,23 @@
return NULL; \
} \
+#define DEFINE_UNREACHABLE_MAKE_LOCATION_SUMMARY(Name) \
+ LocationSummary* Name##Instr::MakeLocationSummary(Zone* zone, bool opt) \
+ const { \
+ UNREACHABLE(); \
+ return NULL; \
+ } \
+
#define DEFINE_UNIMPLEMENTED_EMIT_NATIVE_CODE(Name) \
void Name##Instr::EmitNativeCode(FlowGraphCompiler* compiler) { \
UNIMPLEMENTED(); \
}
+#define DEFINE_UNREACHABLE_EMIT_NATIVE_CODE(Name) \
+ void Name##Instr::EmitNativeCode(FlowGraphCompiler* compiler) { \
+ UNREACHABLE(); \
+ }
+
#define DEFINE_UNIMPLEMENTED_EMIT_BRANCH_CODE(Name) \
void Name##Instr::EmitBranchCode(FlowGraphCompiler*, BranchInstr*) { \
UNIMPLEMENTED(); \
@@ -168,9 +177,13 @@
#undef DEFINE_UNIMPLEMENTED
-DEFINE_UNIMPLEMENTED_EMIT_BRANCH_CODE(TestCids)
-DEFINE_UNIMPLEMENTED_EMIT_BRANCH_CODE(RelationalOp)
-DEFINE_UNIMPLEMENTED_EMIT_BRANCH_CODE(EqualityCompare)
+#define DEFINE_UNREACHABLE(Name) \
+ DEFINE_UNREACHABLE_MAKE_LOCATION_SUMMARY(Name) \
+ DEFINE_UNREACHABLE_EMIT_NATIVE_CODE(Name) \
+
+FOR_EACH_UNREACHABLE_INSTRUCTION(DEFINE_UNREACHABLE)
+
+#undef DEFINE_UNREACHABLE
EMIT_NATIVE_CODE(InstanceOf, 2, Location::SameAsFirstInput(),
@@ -228,6 +241,24 @@
void PolymorphicInstanceCallInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ ASSERT(ic_data().NumArgsTested() == 1);
+ if (!with_checks()) {
+ ASSERT(ic_data().HasOneTarget());
+ const Function& target = Function::ZoneHandle(ic_data().GetTargetAt(0));
+ const Array& arguments_descriptor =
+ Array::Handle(ArgumentsDescriptor::New(
+ instance_call()->ArgumentCount(),
+ instance_call()->argument_names()));
+ const intptr_t argdesc_kidx = __ AddConstant(arguments_descriptor);
+
+ __ PushConstant(target);
+ __ StaticCall(instance_call()->ArgumentCount(), argdesc_kidx);
+ compiler->AddCurrentDescriptor(RawPcDescriptors::kOther,
+ deopt_id(), instance_call()->token_pos());
+ compiler->RecordAfterCall(this);
+ __ PopLocal(locs()->out(0).reg());
+ return;
+ }
Unsupported(compiler);
UNREACHABLE();
}
@@ -294,6 +325,25 @@
}
+EMIT_NATIVE_CODE(UnboxedConstant, 0, Location::RequiresRegister()) {
+ // The register allocator drops constant definitions that have no uses.
+ if (locs()->out(0).IsInvalid()) {
+ return;
+ }
+ if (representation_ != kUnboxedDouble) {
+ Unsupported(compiler);
+ UNREACHABLE();
+ }
+ const Register result = locs()->out(0).reg();
+ if (Utils::DoublesBitEqual(Double::Cast(value()).value(), 0.0)) {
+ __ BitXor(result, result, result);
+ } else {
+ __ LoadConstant(result, value());
+ __ UnboxDouble(result, result);
+ }
+}
+
+
EMIT_NATIVE_CODE(Return, 1) {
if (compiler->is_optimizing()) {
__ Return(locs()->in(0).reg());
@@ -367,7 +417,6 @@
compiler->assembler()->AddConstant(arguments_descriptor);
__ StaticCall(argument_count, argdesc_kidx);
compiler->RecordAfterCall(this);
-
if (compiler->is_optimizing()) {
__ PopLocal(locs()->out(0).reg());
}
@@ -378,14 +427,25 @@
Condition true_condition,
BranchLabels labels) {
if (true_condition == NEXT_IS_TRUE) {
+ // NEXT_IS_TRUE indicates that the preceeding test expects the true case
+ // to be in the subsequent instruction, which it skips if the test fails.
__ Jump(labels.true_label);
if (labels.fall_through != labels.false_label) {
+ // The preceeding Jump instruction will be skipped if the test fails.
+ // If we aren't falling through to the false case, then we have to do
+ // a Jump to it here.
__ Jump(labels.false_label);
}
} else {
ASSERT(true_condition == NEXT_IS_FALSE);
+ // NEXT_IS_FALSE indicates that the preceeing test has been flipped and
+ // expects the false case to be in the subsequent instruction, which it
+ // skips if the test succeeds.
__ Jump(labels.false_label);
if (labels.fall_through != labels.true_label) {
+ // The preceeding Jump instruction will be skipped if the test succeeds.
+ // If we aren't falling through to the true case, then we have to do
+ // a Jump to it here.
__ Jump(labels.true_label);
}
}
@@ -544,6 +604,62 @@
}
+Condition TestCidsInstr::EmitComparisonCode(FlowGraphCompiler* compiler,
+ BranchLabels labels) {
+ ASSERT((kind() == Token::kIS) || (kind() == Token::kISNOT));
+ const Register value = locs()->in(0).reg();
+ const intptr_t true_result = (kind() == Token::kIS) ? 1 : 0;
+
+ const ZoneGrowableArray<intptr_t>& data = cid_results();
+ const intptr_t num_cases = data.length() / 2;
+ ASSERT(num_cases <= 255);
+ __ TestCids(value, num_cases);
+
+ bool result = false;
+ for (intptr_t i = 0; i < data.length(); i += 2) {
+ const intptr_t test_cid = data[i];
+ result = data[i + 1] == true_result;
+ __ Nop(result ? 1 : 0, compiler->ToEmbeddableCid(test_cid, this));
+ }
+
+ // No match found, deoptimize or false.
+ if (CanDeoptimize()) {
+ compiler->EmitDeopt(deopt_id(),
+ ICData::kDeoptTestCids,
+ licm_hoisted_ ? ICData::kHoisted : 0);
+ } else {
+ Label* target = result ? labels.false_label : labels.true_label;
+ __ Jump(target);
+ }
+
+ return NEXT_IS_TRUE;
+}
+
+
+void TestCidsInstr::EmitBranchCode(FlowGraphCompiler* compiler,
+ BranchInstr* branch) {
+ BranchLabels labels = compiler->CreateBranchLabels(branch);
+ Condition true_condition = EmitComparisonCode(compiler, labels);
+ EmitBranchOnCondition(compiler, true_condition, labels);
+}
+
+
+EMIT_NATIVE_CODE(TestCids, 1, Location::RequiresRegister(),
+ LocationSummary::kNoCall) {
+ Register result_reg = locs()->out(0).reg();
+ Label is_true, is_false, done;
+ BranchLabels labels = { &is_true, &is_false, &is_false };
+ EmitComparisonCode(compiler, labels);
+ __ Jump(&is_true);
+ __ Bind(&is_false);
+ __ LoadConstant(result_reg, Bool::False());
+ __ Jump(&done);
+ __ Bind(&is_true);
+ __ LoadConstant(result_reg, Bool::True());
+ __ Bind(&done);
+}
+
+
EMIT_NATIVE_CODE(CreateArray,
2, Location::RequiresRegister(),
LocationSummary::kCall) {
@@ -559,15 +675,38 @@
}
-EMIT_NATIVE_CODE(StoreIndexed, 3) {
+EMIT_NATIVE_CODE(StoreIndexed, 3, Location::NoLocation(),
+ LocationSummary::kNoCall, 1) {
if (compiler->is_optimizing()) {
- if (class_id() != kArrayCid) {
+ if (IsExternal()) {
Unsupported(compiler);
UNREACHABLE();
}
- __ StoreIndexed(locs()->in(kArrayPos).reg(),
- locs()->in(kIndexPos).reg(),
- locs()->in(kValuePos).reg());
+ const Register array = locs()->in(kArrayPos).reg();
+ const Register index = locs()->in(kIndexPos).reg();
+ const Register value = locs()->in(kValuePos).reg();
+ const Register temp = locs()->temp(0).reg();
+ switch (class_id()) {
+ case kArrayCid:
+ __ StoreIndexed(array, index, value);
+ break;
+ case kTypedDataFloat64ArrayCid:
+ if ((index_scale() != 8) && (index_scale() != 1)) {
+ Unsupported(compiler);
+ UNREACHABLE();
+ }
+ if (index_scale() == 1) {
+ __ ShrImm(temp, index, 3);
+ } else {
+ __ Move(temp, index);
+ }
+ __ StoreFloat64Indexed(array, temp, value);
+ break;
+ default:
+ Unsupported(compiler);
+ UNREACHABLE();
+ break;
+ }
} else {
ASSERT(class_id() == kArrayCid);
__ StoreIndexedTOS();
@@ -575,6 +714,49 @@
}
+EMIT_NATIVE_CODE(LoadIndexed, 2, Location::RequiresRegister()) {
+ ASSERT(compiler->is_optimizing());
+ if (IsExternal()) {
+ Unsupported(compiler);
+ UNREACHABLE();
+ }
+ const Register array = locs()->in(0).reg();
+ const Register index = locs()->in(1).reg();
+ const Register result = locs()->out(0).reg();
+ switch (class_id()) {
+ case kArrayCid:
+ __ LoadIndexed(result, array, index);
+ break;
+ case kTypedDataFloat64ArrayCid:
+ if ((index_scale() != 8) && (index_scale() != 1)) {
+ Unsupported(compiler);
+ UNREACHABLE();
+ }
+ if (index_scale() == 1) {
+ __ ShrImm(index, index, 3);
+ }
+ __ LoadFloat64Indexed(result, array, index);
+ break;
+ case kOneByteStringCid:
+ ASSERT(index_scale() == 1);
+ __ LoadOneByteStringIndexed(result, array, index);
+ break;
+ case kTwoByteStringCid:
+ if (index_scale() != 2) {
+ // TODO(zra): Fix-up index.
+ Unsupported(compiler);
+ UNREACHABLE();
+ }
+ __ LoadTwoByteStringIndexed(result, array, index);
+ break;
+ default:
+ Unsupported(compiler);
+ UNREACHABLE();
+ break;
+ }
+}
+
+
EMIT_NATIVE_CODE(StringInterpolate,
1, Location::RegisterLocation(0),
LocationSummary::kCall) {
@@ -588,7 +770,6 @@
const intptr_t argdesc_kidx = __ AddConstant(arguments_descriptor);
__ StaticCall(kArgumentCount, argdesc_kidx);
compiler->RecordAfterCall(this);
-
if (compiler->is_optimizing()) {
__ PopLocal(locs()->out(0).reg());
}
@@ -642,7 +823,6 @@
}
-
EMIT_NATIVE_CODE(AllocateObject,
0, Location::RequiresRegister(),
LocationSummary::kCall) {
@@ -741,10 +921,10 @@
EMIT_NATIVE_CODE(Throw, 0, Location::NoLocation(), LocationSummary::kCall) {
__ Throw(0);
- compiler->RecordSafepoint(locs());
compiler->AddCurrentDescriptor(RawPcDescriptors::kOther,
deopt_id(),
token_pos());
+ compiler->RecordAfterCall(this);
__ Trap();
}
@@ -752,10 +932,10 @@
EMIT_NATIVE_CODE(ReThrow, 0, Location::NoLocation(), LocationSummary::kCall) {
compiler->SetNeedsStacktrace(catch_try_index());
__ Throw(1);
- compiler->RecordSafepoint(locs());
compiler->AddCurrentDescriptor(RawPcDescriptors::kOther,
deopt_id(),
token_pos());
+ compiler->RecordAfterCall(this);
__ Trap();
}
@@ -986,22 +1166,9 @@
EMIT_NATIVE_CODE(CheckEitherNonSmi, 2) {
- intptr_t left_cid = left()->Type()->ToCid();
- intptr_t right_cid = right()->Type()->ToCid();
const Register left = locs()->in(0).reg();
const Register right = locs()->in(1).reg();
- if (this->left()->definition() == this->right()->definition()) {
- __ CheckSmi(left);
- } else if (left_cid == kSmiCid) {
- __ CheckSmi(right);
- } else if (right_cid == kSmiCid) {
- __ CheckSmi(left);
- } else {
- __ CheckSmi(left);
- compiler->EmitDeopt(deopt_id(), ICData::kDeoptBinaryDoubleOp,
- licm_hoisted_ ? ICData::kHoisted : 0);
- __ CheckSmi(right);
- }
+ __ CheckEitherNonSmi(left, right);
compiler->EmitDeopt(deopt_id(), ICData::kDeoptBinaryDoubleOp,
licm_hoisted_ ? ICData::kHoisted : 0);
}
@@ -1127,9 +1294,314 @@
break;
default:
UNREACHABLE();
+ break;
}
}
+
+EMIT_NATIVE_CODE(Box, 1, Location::RequiresRegister(), LocationSummary::kCall) {
+ ASSERT(from_representation() == kUnboxedDouble);
+ const Register value = locs()->in(0).reg();
+ const Register out = locs()->out(0).reg();
+ const intptr_t kidx = __ AddConstant(compiler->double_class());
+ __ Allocate(kidx);
+ compiler->AddCurrentDescriptor(RawPcDescriptors::kOther,
+ Thread::kNoDeoptId,
+ token_pos());
+ compiler->RecordSafepoint(locs());
+ // __ Allocate puts the box at the top of the stack.
+ __ WriteIntoDouble(out, value);
+}
+
+
+EMIT_NATIVE_CODE(Unbox, 1, Location::RequiresRegister()) {
+ ASSERT(representation() == kUnboxedDouble);
+ const intptr_t value_cid = value()->Type()->ToCid();
+ const intptr_t box_cid = BoxCid();
+ const Register box = locs()->in(0).reg();
+ const Register result = locs()->out(0).reg();
+ if (value_cid == box_cid) {
+ __ UnboxDouble(result, box);
+ } else if (CanConvertSmi() && (value_cid == kSmiCid)) {
+ __ SmiToDouble(result, box);
+ } else if ((value()->Type()->ToNullableCid() == box_cid) &&
+ value()->Type()->is_nullable()) {
+ __ IfEqNull(box);
+ compiler->EmitDeopt(GetDeoptId(), ICData::kDeoptCheckClass);
+ __ UnboxDouble(result, box);
+ } else {
+ __ CheckedUnboxDouble(result, box);
+ compiler->EmitDeopt(GetDeoptId(), ICData::kDeoptCheckClass);
+ }
+}
+
+
+EMIT_NATIVE_CODE(DoubleToSmi, 1, Location::RequiresRegister()) {
+ const Register value = locs()->in(0).reg();
+ const Register result = locs()->out(0).reg();
+ __ DoubleToSmi(result, value);
+ compiler->EmitDeopt(deopt_id(), ICData::kDeoptDoubleToSmi);
+}
+
+
+EMIT_NATIVE_CODE(SmiToDouble, 1, Location::RequiresRegister()) {
+ const Register value = locs()->in(0).reg();
+ const Register result = locs()->out(0).reg();
+ __ SmiToDouble(result, value);
+}
+
+
+EMIT_NATIVE_CODE(BinaryDoubleOp, 2, Location::RequiresRegister()) {
+ const Register left = locs()->in(0).reg();
+ const Register right = locs()->in(1).reg();
+ const Register result = locs()->out(0).reg();
+ switch (op_kind()) {
+ case Token::kADD: __ DAdd(result, left, right); break;
+ case Token::kSUB: __ DSub(result, left, right); break;
+ case Token::kMUL: __ DMul(result, left, right); break;
+ case Token::kDIV: __ DDiv(result, left, right); break;
+ default: UNREACHABLE();
+ }
+}
+
+
+EMIT_NATIVE_CODE(UnaryDoubleOp, 1, Location::RequiresRegister()) {
+ const Register value = locs()->in(0).reg();
+ const Register result = locs()->out(0).reg();
+ __ DNeg(result, value);
+}
+
+
+EMIT_NATIVE_CODE(MathUnary, 1, Location::RequiresRegister()) {
+ const Register value = locs()->in(0).reg();
+ const Register result = locs()->out(0).reg();
+ if (kind() == MathUnaryInstr::kSqrt) {
+ __ DSqrt(result, value);
+ } else if (kind() == MathUnaryInstr::kDoubleSquare) {
+ __ DMul(result, value, value);
+ } else if (kind() == MathUnaryInstr::kSin) {
+ __ DSin(result, value);
+ } else if (kind() == MathUnaryInstr::kCos) {
+ __ DCos(result, value);
+ } else {
+ Unsupported(compiler);
+ UNREACHABLE();
+ }
+}
+
+
+EMIT_NATIVE_CODE(InvokeMathCFunction,
+ InputCount(), Location::RequiresRegister()) {
+ const Register left = locs()->in(0).reg();
+ const Register result = locs()->out(0).reg();
+ if (recognized_kind() == MethodRecognizer::kMathDoublePow) {
+ const Register right = locs()->in(1).reg();
+ __ DPow(result, left, right);
+ } else if (recognized_kind() == MethodRecognizer::kDoubleMod) {
+ const Register right = locs()->in(1).reg();
+ __ DMod(result, left, right);
+ } else {
+ Unsupported(compiler);
+ UNREACHABLE();
+ }
+}
+
+
+EMIT_NATIVE_CODE(MathMinMax, 2, Location::RequiresRegister()) {
+ ASSERT((op_kind() == MethodRecognizer::kMathMin) ||
+ (op_kind() == MethodRecognizer::kMathMax));
+ const Register left = locs()->in(0).reg();
+ const Register right = locs()->in(1).reg();
+ const Register result = locs()->out(0).reg();
+ if (result_cid() == kDoubleCid) {
+ if (op_kind() == MethodRecognizer::kMathMin) {
+ __ DMin(result, left, right);
+ } else {
+ __ DMax(result, left, right);
+ }
+ } else {
+ ASSERT(result_cid() == kSmiCid);
+ if (op_kind() == MethodRecognizer::kMathMin) {
+ __ Min(result, left, right);
+ } else {
+ __ Max(result, left, right);
+ }
+ }
+}
+
+
+static Token::Kind FlipCondition(Token::Kind kind) {
+ switch (kind) {
+ case Token::kEQ: return Token::kNE;
+ case Token::kNE: return Token::kEQ;
+ case Token::kLT: return Token::kGTE;
+ case Token::kGT: return Token::kLTE;
+ case Token::kLTE: return Token::kGT;
+ case Token::kGTE: return Token::kLT;
+ default:
+ UNREACHABLE();
+ return Token::kNE;
+ }
+}
+
+
+static Bytecode::Opcode OpcodeForSmiCondition(Token::Kind kind) {
+ switch (kind) {
+ case Token::kEQ: return Bytecode::kIfEqStrict;
+ case Token::kNE: return Bytecode::kIfNeStrict;
+ case Token::kLT: return Bytecode::kIfLt;
+ case Token::kGT: return Bytecode::kIfGt;
+ case Token::kLTE: return Bytecode::kIfLe;
+ case Token::kGTE: return Bytecode::kIfGe;
+ default:
+ UNREACHABLE();
+ return Bytecode::kTrap;
+ }
+}
+
+
+static Bytecode::Opcode OpcodeForDoubleCondition(Token::Kind kind) {
+ switch (kind) {
+ case Token::kEQ: return Bytecode::kIfDEq;
+ case Token::kNE: return Bytecode::kIfDNe;
+ case Token::kLT: return Bytecode::kIfDLt;
+ case Token::kGT: return Bytecode::kIfDGt;
+ case Token::kLTE: return Bytecode::kIfDLe;
+ case Token::kGTE: return Bytecode::kIfDGe;
+ default:
+ UNREACHABLE();
+ return Bytecode::kTrap;
+ }
+}
+
+
+static Condition EmitSmiComparisonOp(FlowGraphCompiler* compiler,
+ LocationSummary* locs,
+ Token::Kind kind,
+ BranchLabels labels) {
+ const Register left = locs->in(0).reg();
+ const Register right = locs->in(1).reg();
+ Token::Kind comparison = kind;
+ Condition condition = NEXT_IS_TRUE;
+ if (labels.fall_through != labels.false_label) {
+ // If we aren't falling through to the false label, we can save a Jump
+ // instruction in the case that the true case is the fall through by
+ // flipping the sense of the test such that the instruction following the
+ // test is the Jump to the false label.
+ condition = NEXT_IS_FALSE;
+ comparison = FlipCondition(kind);
+ }
+ __ Emit(Bytecode::Encode(OpcodeForSmiCondition(comparison), left, right));
+ return condition;
+}
+
+
+static Condition EmitDoubleComparisonOp(FlowGraphCompiler* compiler,
+ LocationSummary* locs,
+ Token::Kind kind,
+ BranchLabels labels) {
+ const Register left = locs->in(0).reg();
+ const Register right = locs->in(1).reg();
+ Token::Kind comparison = kind;
+ Condition condition = NEXT_IS_TRUE;
+ if (labels.fall_through != labels.false_label) {
+ // If we aren't falling through to the false label, we can save a Jump
+ // instruction in the case that the true case is the fall through by
+ // flipping the sense of the test such that the instruction following the
+ // test is the Jump to the false label.
+ condition = NEXT_IS_FALSE;
+ comparison = FlipCondition(kind);
+ }
+ __ Emit(Bytecode::Encode(OpcodeForDoubleCondition(comparison), left, right));
+ return condition;
+}
+
+
+Condition EqualityCompareInstr::EmitComparisonCode(FlowGraphCompiler* compiler,
+ BranchLabels labels) {
+ if (operation_cid() == kSmiCid) {
+ return EmitSmiComparisonOp(compiler, locs(), kind(), labels);
+ } else {
+ ASSERT(operation_cid() == kDoubleCid);
+ return EmitDoubleComparisonOp(compiler, locs(), kind(), labels);
+ }
+}
+
+
+EMIT_NATIVE_CODE(EqualityCompare, 2, Location::RequiresRegister()) {
+ ASSERT(compiler->is_optimizing());
+ ASSERT((kind() == Token::kEQ) || (kind() == Token::kNE));
+ Label is_true, is_false;
+ // These labels are not used. They are arranged so that EmitComparisonCode
+ // emits a test that executes the following instruction when the test
+ // succeeds.
+ BranchLabels labels = { &is_true, &is_false, &is_false };
+ const Register result = locs()->out(0).reg();
+ __ LoadConstant(result, Bool::False());
+ Condition true_condition = EmitComparisonCode(compiler, labels);
+ ASSERT(true_condition == NEXT_IS_TRUE);
+ __ LoadConstant(result, Bool::True());
+}
+
+
+void EqualityCompareInstr::EmitBranchCode(FlowGraphCompiler* compiler,
+ BranchInstr* branch) {
+ ASSERT((kind() == Token::kNE) || (kind() == Token::kEQ));
+ BranchLabels labels = compiler->CreateBranchLabels(branch);
+ Condition true_condition = EmitComparisonCode(compiler, labels);
+ EmitBranchOnCondition(compiler, true_condition, labels);
+}
+
+
+Condition RelationalOpInstr::EmitComparisonCode(FlowGraphCompiler* compiler,
+ BranchLabels labels) {
+ if (operation_cid() == kSmiCid) {
+ return EmitSmiComparisonOp(compiler, locs(), kind(), labels);
+ } else {
+ ASSERT(operation_cid() == kDoubleCid);
+ return EmitDoubleComparisonOp(compiler, locs(), kind(), labels);
+ }
+}
+
+
+EMIT_NATIVE_CODE(RelationalOp, 2, Location::RequiresRegister()) {
+ ASSERT(compiler->is_optimizing());
+ Label is_true, is_false;
+ BranchLabels labels = { &is_true, &is_false, &is_false };
+ const Register result = locs()->out(0).reg();
+ __ LoadConstant(result, Bool::False());
+ Condition true_condition = EmitComparisonCode(compiler, labels);
+ ASSERT(true_condition == NEXT_IS_TRUE);
+ __ LoadConstant(result, Bool::True());
+}
+
+
+void RelationalOpInstr::EmitBranchCode(FlowGraphCompiler* compiler,
+ BranchInstr* branch) {
+ BranchLabels labels = compiler->CreateBranchLabels(branch);
+ Condition true_condition = EmitComparisonCode(compiler, labels);
+ EmitBranchOnCondition(compiler, true_condition, labels);
+}
+
+
+EMIT_NATIVE_CODE(CheckArrayBound, 2) {
+ const Register length = locs()->in(kLengthPos).reg();
+ const Register index = locs()->in(kIndexPos).reg();
+ const intptr_t index_cid = this->index()->Type()->ToCid();
+ if (index_cid != kSmiCid) {
+ __ CheckSmi(index);
+ compiler->EmitDeopt(deopt_id(),
+ ICData::kDeoptCheckArrayBound,
+ (generalized_ ? ICData::kGeneralized : 0) |
+ (licm_hoisted_ ? ICData::kHoisted : 0));
+ }
+ __ IfULe(length, index);
+ compiler->EmitDeopt(deopt_id(),
+ ICData::kDeoptCheckArrayBound,
+ (generalized_ ? ICData::kGeneralized : 0) |
+ (licm_hoisted_ ? ICData::kHoisted : 0));
+}
+
} // namespace dart
#endif // defined TARGET_ARCH_DBC
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index 34555dc..3ccb078 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -5847,8 +5847,7 @@
Label* deopt = compiler->AddDeoptStub(deopt_id(),
ICData::kDeoptCheckSmi,
licm_hoisted_ ? ICData::kHoisted : 0);
- __ testl(value, Immediate(kSmiTagMask));
- __ j(NOT_ZERO, deopt);
+ __ BranchIfNotSmi(value, deopt);
}
@@ -5871,6 +5870,20 @@
}
+LocationSummary* GenericCheckBoundInstr::MakeLocationSummary(Zone* zone,
+ bool opt) const {
+ // Only needed for AOT.
+ UNIMPLEMENTED();
+ return NULL;
+}
+
+
+void GenericCheckBoundInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ // Only needed for AOT.
+ UNIMPLEMENTED();
+}
+
+
// Length: register or constant.
// Index: register, constant or stack slot.
LocationSummary* CheckArrayBoundInstr::MakeLocationSummary(Zone* zone,
@@ -5910,8 +5923,12 @@
return;
}
+ const intptr_t index_cid = index()->Type()->ToCid();
if (length_loc.IsConstant()) {
Register index = index_loc.reg();
+ if (index_cid != kSmiCid) {
+ __ BranchIfNotSmi(index, deopt);
+ }
const Smi& length = Smi::Cast(length_loc.constant());
if (length.Value() == Smi::kMaxValue) {
__ testl(index, index);
@@ -5933,11 +5950,17 @@
} else if (length_loc.IsStackSlot()) {
Register index = index_loc.reg();
const Address& length = length_loc.ToStackSlotAddress();
+ if (index_cid != kSmiCid) {
+ __ BranchIfNotSmi(index, deopt);
+ }
__ cmpl(index, length);
__ j(ABOVE_EQUAL, deopt);
} else {
Register index = index_loc.reg();
Register length = length_loc.reg();
+ if (index_cid != kSmiCid) {
+ __ BranchIfNotSmi(index, deopt);
+ }
__ cmpl(length, index);
__ j(BELOW_EQUAL, deopt);
}
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index 342e267..645273f 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -4836,8 +4836,7 @@
Label* deopt = compiler->AddDeoptStub(deopt_id(),
ICData::kDeoptCheckSmi,
licm_hoisted_ ? ICData::kHoisted : 0);
- __ andi(CMPRES1, value, Immediate(kSmiTagMask));
- __ bne(CMPRES1, ZR, deopt);
+ __ BranchIfNotSmi(value, deopt);
}
@@ -4859,6 +4858,64 @@
}
+LocationSummary* GenericCheckBoundInstr::MakeLocationSummary(Zone* zone,
+ bool opt) const {
+ const intptr_t kNumInputs = 2;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* locs = new(zone) LocationSummary(
+ zone, kNumInputs, kNumTemps, LocationSummary::kCallOnSlowPath);
+ locs->set_in(kLengthPos, Location::RequiresRegister());
+ locs->set_in(kIndexPos, Location::RequiresRegister());
+ return locs;
+}
+
+
+class RangeErrorSlowPath : public SlowPathCode {
+ public:
+ RangeErrorSlowPath(GenericCheckBoundInstr* instruction, intptr_t try_index)
+ : instruction_(instruction), try_index_(try_index) { }
+
+ virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
+ if (Assembler::EmittingComments()) {
+ __ Comment("slow path check bound operation");
+ }
+ __ Bind(entry_label());
+ LocationSummary* locs = instruction_->locs();
+ __ Push(locs->in(0).reg());
+ __ Push(locs->in(1).reg());
+ __ CallRuntime(kRangeErrorRuntimeEntry, 2);
+ compiler->pc_descriptors_list()->AddDescriptor(
+ RawPcDescriptors::kOther,
+ compiler->assembler()->CodeSize(),
+ instruction_->deopt_id(),
+ instruction_->token_pos(),
+ try_index_);
+ __ break_(0);
+ }
+
+ private:
+ GenericCheckBoundInstr* instruction_;
+ intptr_t try_index_;
+};
+
+
+void GenericCheckBoundInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ RangeErrorSlowPath* slow_path =
+ new RangeErrorSlowPath(this, compiler->CurrentTryIndex());
+ compiler->AddSlowPathCode(slow_path);
+
+ Location length_loc = locs()->in(kLengthPos);
+ Location index_loc = locs()->in(kIndexPos);
+ Register length = length_loc.reg();
+ Register index = index_loc.reg();
+ const intptr_t index_cid = this->index()->Type()->ToCid();
+ if (index_cid != kSmiCid) {
+ __ BranchIfNotSmi(index, slow_path->entry_label());
+ }
+ __ BranchUnsignedGreaterEqual(index, length, slow_path->entry_label());
+}
+
+
LocationSummary* CheckArrayBoundInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
const intptr_t kNumInputs = 2;
@@ -4892,6 +4949,7 @@
return;
}
+ const intptr_t index_cid = index()->Type()->ToCid();
if (index_loc.IsConstant()) {
Register length = length_loc.reg();
const Smi& index = Smi::Cast(index_loc.constant());
@@ -4900,6 +4958,9 @@
} else if (length_loc.IsConstant()) {
const Smi& length = Smi::Cast(length_loc.constant());
Register index = index_loc.reg();
+ if (index_cid != kSmiCid) {
+ __ BranchIfNotSmi(index, deopt);
+ }
if (length.Value() == Smi::kMaxValue) {
__ BranchSignedLess(index, Immediate(0), deopt);
} else {
@@ -4909,6 +4970,9 @@
} else {
Register length = length_loc.reg();
Register index = index_loc.reg();
+ if (index_cid != kSmiCid) {
+ __ BranchIfNotSmi(index, deopt);
+ }
__ BranchUnsignedGreaterEqual(index, length, deopt);
}
}
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index da4b4c2..c908d1e 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -5697,8 +5697,7 @@
Label* deopt = compiler->AddDeoptStub(deopt_id(),
ICData::kDeoptCheckSmi,
licm_hoisted_ ? ICData::kHoisted : 0);
- __ testq(value, Immediate(kSmiTagMask));
- __ j(NOT_ZERO, deopt);
+ __ BranchIfNotSmi(value, deopt);
}
@@ -5721,6 +5720,66 @@
}
+LocationSummary* GenericCheckBoundInstr::MakeLocationSummary(Zone* zone,
+ bool opt) const {
+ const intptr_t kNumInputs = 2;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* locs = new(zone) LocationSummary(
+ zone, kNumInputs, kNumTemps, LocationSummary::kCallOnSlowPath);
+ locs->set_in(kLengthPos, Location::RequiresRegister());
+ locs->set_in(kIndexPos, Location::RequiresRegister());
+ return locs;
+}
+
+
+class RangeErrorSlowPath : public SlowPathCode {
+ public:
+ RangeErrorSlowPath(GenericCheckBoundInstr* instruction, intptr_t try_index)
+ : instruction_(instruction), try_index_(try_index) { }
+
+ virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
+ if (Assembler::EmittingComments()) {
+ __ Comment("slow path check bound operation");
+ }
+ __ Bind(entry_label());
+ LocationSummary* locs = instruction_->locs();
+ __ pushq(locs->in(0).reg());
+ __ pushq(locs->in(1).reg());
+ __ CallRuntime(kRangeErrorRuntimeEntry, 2);
+ compiler->pc_descriptors_list()->AddDescriptor(
+ RawPcDescriptors::kOther,
+ compiler->assembler()->CodeSize(),
+ instruction_->deopt_id(),
+ instruction_->token_pos(),
+ try_index_);
+ compiler->RecordSafepoint(locs, 2);
+ __ int3();
+ }
+
+ private:
+ GenericCheckBoundInstr* instruction_;
+ intptr_t try_index_;
+};
+
+
+void GenericCheckBoundInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ RangeErrorSlowPath* slow_path =
+ new RangeErrorSlowPath(this, compiler->CurrentTryIndex());
+ compiler->AddSlowPathCode(slow_path);
+
+ Location length_loc = locs()->in(kLengthPos);
+ Location index_loc = locs()->in(kIndexPos);
+ Register length = length_loc.reg();
+ Register index = index_loc.reg();
+ const intptr_t index_cid = this->index()->Type()->ToCid();
+ if (index_cid != kSmiCid) {
+ __ BranchIfNotSmi(index, slow_path->entry_label());
+ }
+ __ cmpq(index, length);
+ __ j(ABOVE_EQUAL, slow_path->entry_label());
+}
+
+
LocationSummary* CheckArrayBoundInstr::MakeLocationSummary(Zone* zone,
bool opt) const {
const intptr_t kNumInputs = 2;
@@ -5754,6 +5813,7 @@
return;
}
+ const intptr_t index_cid = index()->Type()->ToCid();
if (index_loc.IsConstant()) {
Register length = length_loc.reg();
const Smi& index = Smi::Cast(index_loc.constant());
@@ -5763,6 +5823,9 @@
} else if (length_loc.IsConstant()) {
const Smi& length = Smi::Cast(length_loc.constant());
Register index = index_loc.reg();
+ if (index_cid != kSmiCid) {
+ __ BranchIfNotSmi(index, deopt);
+ }
if (length.Value() == Smi::kMaxValue) {
__ testq(index, index);
__ j(NEGATIVE, deopt);
@@ -5774,6 +5837,9 @@
} else {
Register length = length_loc.reg();
Register index = index_loc.reg();
+ if (index_cid != kSmiCid) {
+ __ BranchIfNotSmi(index, deopt);
+ }
__ cmpq(index, length);
__ j(ABOVE_EQUAL, deopt);
}
diff --git a/runtime/vm/intrinsifier.cc b/runtime/vm/intrinsifier.cc
index 9e049d0..15a0fa9 100644
--- a/runtime/vm/intrinsifier.cc
+++ b/runtime/vm/intrinsifier.cc
@@ -373,12 +373,6 @@
Definition* array,
Definition* index,
intptr_t length_offset) {
- TokenPosition token_pos = builder->TokenPos();
- builder->AddInstruction(
- new CheckSmiInstr(new Value(index),
- Thread::kNoDeoptId,
- token_pos));
-
Definition* length = builder->AddDefinition(
new LoadFieldInstr(new Value(array),
length_offset,
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index eee6d04..697aef8 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -45,6 +45,7 @@
#include "vm/timeline.h"
#include "vm/timeline_analysis.h"
#include "vm/timer.h"
+#include "vm/verifier.h"
#include "vm/visitor.h"
@@ -53,9 +54,14 @@
DECLARE_FLAG(bool, print_metrics);
DECLARE_FLAG(bool, timing);
DECLARE_FLAG(bool, trace_service);
-DECLARE_FLAG(bool, trace_reload);
DECLARE_FLAG(bool, warn_on_pause_with_no_debugger);
+
+// Reload flags.
DECLARE_FLAG(bool, check_reloaded);
+DECLARE_FLAG(int, reload_every);
+DECLARE_FLAG(bool, reload_every_back_off);
+DECLARE_FLAG(bool, trace_reload);
+
NOT_IN_PRODUCT(
static void CheckedModeHandler(bool value) {
@@ -202,8 +208,10 @@
const char* name() const;
void MessageNotify(Message::Priority priority);
MessageStatus HandleMessage(Message* message);
+#ifndef PRODUCT
void NotifyPauseOnStart();
void NotifyPauseOnExit();
+#endif // !PRODUCT
#if defined(DEBUG)
// Check that it is safe to access this handler.
@@ -570,6 +578,7 @@
}
}
delete message;
+#ifndef PRODUCT
if (status == kOK) {
const Object& result =
Object::Handle(zone, I->InvokePendingServiceExtensionCalls());
@@ -579,10 +588,12 @@
ASSERT(result.IsNull());
}
}
+#endif // !PRODUCT
return status;
}
+#ifndef PRODUCT
void IsolateMessageHandler::NotifyPauseOnStart() {
if (!FLAG_support_service) {
return;
@@ -615,6 +626,7 @@
I->name());
}
}
+#endif // !PRODUCT
#if defined(DEBUG)
@@ -833,6 +845,7 @@
spawn_count_(0),
has_attempted_reload_(false),
no_reload_scope_depth_(0),
+ reload_every_n_stack_overflow_checks_(FLAG_reload_every),
reload_context_(NULL) {
NOT_IN_PRODUCT(FlagsCopyFrom(api_flags));
// TODO(asiva): A Thread is not available here, need to figure out
@@ -851,9 +864,11 @@
delete heap_;
delete object_store_;
delete api_state_;
+#ifndef PRODUCT
if (FLAG_support_debugger) {
delete debugger_;
}
+#endif // !PRODUCT
#if defined(USING_SIMULATOR)
delete simulator_;
#endif
@@ -871,9 +886,11 @@
message_handler_ = NULL; // Fail fast if we send messages to a dead isolate.
ASSERT(deopt_context_ == NULL); // No deopt in progress when isolate deleted.
delete spawn_state_;
+#ifndef PRODUCT
if (FLAG_support_service) {
delete object_id_ring_;
}
+#endif // !PRODUCT
object_id_ring_ = NULL;
delete pause_loop_monitor_;
pause_loop_monitor_ = NULL;
@@ -954,9 +971,11 @@
}
}
+#ifndef PRODUCT
if (FLAG_support_service) {
ObjectIdRing::Init(result);
}
+#endif // !PRODUCT
// Add to isolate list. Shutdown and delete the isolate on failure.
if (!AddIsolateToList(result)) {
@@ -1054,8 +1073,9 @@
bool Isolate::CanReload() const {
#ifndef PRODUCT
- return (!ServiceIsolate::IsServiceIsolateDescendant(this) &&
- is_runnable() && !IsReloading() && no_reload_scope_depth_ == 0);
+ return !ServiceIsolate::IsServiceIsolateDescendant(this) &&
+ is_runnable() && !IsReloading() && (no_reload_scope_depth_ == 0) &&
+ IsolateCreationEnabled();
#else
return false;
#endif
@@ -1066,39 +1086,42 @@
void Isolate::ReportReloadError(const Error& error) {
ASSERT(IsReloading());
reload_context_->AbortReload(error);
+}
+
+
+void Isolate::ReloadSources(bool dont_delete_reload_context) {
+ // TODO(asiva): Add verification of canonical objects.
+ ASSERT(!IsReloading());
+ has_attempted_reload_ = true;
+ reload_context_ = new IsolateReloadContext(this);
+ reload_context_->StartReload();
+ // TODO(asiva): Add verification of canonical objects.
+ if (dont_delete_reload_context) {
+ // Unit tests use the reload context later. Caller is responsible
+ // for deleting the context.
+ return;
+ }
+ DeleteReloadContext();
+}
+
+
+void Isolate::DeleteReloadContext() {
delete reload_context_;
reload_context_ = NULL;
}
-
-
-void Isolate::ReloadSources(bool test_mode) {
- ASSERT(!IsReloading());
- has_attempted_reload_ = true;
- reload_context_ = new IsolateReloadContext(this, test_mode);
- reload_context_->StartReload();
-}
-
-#endif
+#endif // !PRODUCT
void Isolate::DoneFinalizing() {
NOT_IN_PRODUCT(
if (IsReloading()) {
reload_context_->FinishReload();
- if (reload_context_->has_error() && reload_context_->test_mode()) {
- // If the reload has an error and we are in test mode keep the reload
- // context on the isolate so that it can be used by unit tests.
- return;
- }
if (reload_context_->has_error()) {
// Remember the reload error.
sticky_reload_error_ = reload_context_->error();
- }
- if (!reload_context_->has_error()) {
+ } else {
reload_context_->ReportSuccess();
}
- delete reload_context_;
- reload_context_ = NULL;
}
)
}
@@ -1117,11 +1140,13 @@
// isolate on thread pool for execution.
ASSERT(object_store()->root_library() != Library::null());
set_is_runnable(true);
+#ifndef PRODUCT
if (FLAG_support_debugger && !ServiceIsolate::IsServiceIsolate(this)) {
if (FLAG_pause_isolates_on_unhandled_exceptions) {
debugger()->SetExceptionPauseInfo(kPauseOnUnhandledExceptions);
}
}
+#endif // !PRODUCT
IsolateSpawnState* state = spawn_state();
if (state != NULL) {
ASSERT(this == state->isolate());
@@ -1137,11 +1162,11 @@
event->Complete();
}
}
-#endif // !PRODUCT
if (FLAG_support_service && Service::isolate_stream.enabled()) {
ServiceEvent runnableEvent(this, ServiceEvent::kIsolateRunnable);
Service::HandleEvent(&runnableEvent);
}
+#endif // !PRODUCT
return true;
}
@@ -1472,6 +1497,13 @@
ASSERT(thread->isolate() == isolate);
StackZone zone(thread);
HandleScope handle_scope(thread);
+#if defined(DEBUG)
+ if (!isolate->HasAttemptedReload()) {
+ isolate->heap()->CollectAllGarbage();
+ VerifyCanonicalVisitor check_canonical(thread);
+ isolate->heap()->IterateObjects(&check_canonical);
+ }
+#endif // DEBUG
const Error& error = Error::Handle(thread->sticky_error());
if (!error.IsNull() && !error.IsUnwindError()) {
OS::PrintErr("in ShutdownIsolate: %s\n", error.ToErrorCString());
@@ -1624,13 +1656,13 @@
}
if (FLAG_print_metrics) {
LogBlock lb;
- THR_Print("Printing metrics for %s\n", name());
+ OS::PrintErr("Printing metrics for %s\n", name());
#define ISOLATE_METRIC_PRINT(type, variable, name, unit) \
- THR_Print("%s\n", metric_##variable##_.ToString());
+ OS::PrintErr("%s\n", metric_##variable##_.ToString());
ISOLATE_METRIC_LIST(ISOLATE_METRIC_PRINT);
#undef ISOLATE_METRIC_PRINT
- THR_Print("\n");
+ OS::PrintErr("\n");
}
}
@@ -1643,6 +1675,21 @@
}
+void Isolate::MaybeIncreaseReloadEveryNStackOverflowChecks() {
+ if (FLAG_reload_every_back_off) {
+ if (reload_every_n_stack_overflow_checks_ < 5000) {
+ reload_every_n_stack_overflow_checks_ += 99;
+ } else {
+ reload_every_n_stack_overflow_checks_ *= 2;
+ }
+ // Cap the value.
+ if (reload_every_n_stack_overflow_checks_ > 1000000) {
+ reload_every_n_stack_overflow_checks_ = 1000000;
+ }
+ }
+}
+
+
void Isolate::Shutdown() {
ASSERT(this == Isolate::Current());
StopBackgroundCompiler();
@@ -1697,7 +1744,7 @@
}
}
- if (FLAG_check_reloaded &&
+ if (FLAG_check_reloaded && is_runnable() &&
(this != Dart::vm_isolate()) &&
!ServiceIsolate::IsServiceIsolateDescendant(this)) {
if (!HasAttemptedReload()) {
@@ -1893,36 +1940,35 @@
jsobj.AddProperty("pauseOnExit", message_handler()->should_pause_on_exit());
jsobj.AddProperty("_isReloading", IsReloading());
- if (debugger() != NULL) {
- if (!is_runnable()) {
- // Isolate is not yet runnable.
- ASSERT(debugger()->PauseEvent() == NULL);
- ServiceEvent pause_event(this, ServiceEvent::kNone);
- jsobj.AddProperty("pauseEvent", &pause_event);
- } else if (message_handler()->is_paused_on_start() ||
- message_handler()->should_pause_on_start()) {
- ASSERT(debugger()->PauseEvent() == NULL);
- ServiceEvent pause_event(this, ServiceEvent::kPauseStart);
- jsobj.AddProperty("pauseEvent", &pause_event);
- } else if (message_handler()->is_paused_on_exit()) {
- ASSERT(debugger()->PauseEvent() == NULL);
- ServiceEvent pause_event(this, ServiceEvent::kPauseExit);
- jsobj.AddProperty("pauseEvent", &pause_event);
- } else if (debugger()->PauseEvent() != NULL && !resume_request_) {
- jsobj.AddProperty("pauseEvent", debugger()->PauseEvent());
- } else {
- ServiceEvent pause_event(this, ServiceEvent::kResume);
+ if (!is_runnable()) {
+ // Isolate is not yet runnable.
+ ASSERT((debugger() == NULL) || (debugger()->PauseEvent() == NULL));
+ ServiceEvent pause_event(this, ServiceEvent::kNone);
+ jsobj.AddProperty("pauseEvent", &pause_event);
+ } else if (message_handler()->is_paused_on_start() ||
+ message_handler()->should_pause_on_start()) {
+ ASSERT((debugger() == NULL) || (debugger()->PauseEvent() == NULL));
+ ServiceEvent pause_event(this, ServiceEvent::kPauseStart);
+ jsobj.AddProperty("pauseEvent", &pause_event);
+ } else if (message_handler()->is_paused_on_exit()) {
+ ASSERT((debugger() == NULL) || (debugger()->PauseEvent() == NULL));
+ ServiceEvent pause_event(this, ServiceEvent::kPauseExit);
+ jsobj.AddProperty("pauseEvent", &pause_event);
+ } else if ((debugger() != NULL) &&
+ (debugger()->PauseEvent() != NULL) &&
+ !resume_request_) {
+ jsobj.AddProperty("pauseEvent", debugger()->PauseEvent());
+ } else {
+ ServiceEvent pause_event(this, ServiceEvent::kResume);
+ if (debugger() != NULL) {
// TODO(turnidge): Don't compute a full stack trace.
DebuggerStackTrace* stack = debugger()->StackTrace();
if (stack->Length() > 0) {
pause_event.set_top_frame(stack->FrameAt(0));
}
- jsobj.AddProperty("pauseEvent", &pause_event);
}
-
- jsobj.AddProperty("exceptionPauseMode",
- ExceptionPauseInfoToServiceEnum(debugger()->GetExceptionPauseInfo()));
+ jsobj.AddProperty("pauseEvent", &pause_event);
}
const Library& lib =
@@ -1959,16 +2005,22 @@
}
}
- if (debugger() != NULL) {
- {
- JSONArray breakpoints(&jsobj, "breakpoints");
+ {
+ JSONArray breakpoints(&jsobj, "breakpoints");
+ if (debugger() != NULL) {
debugger()->PrintBreakpointsToJSONArray(&breakpoints);
}
+ }
- {
- JSONObject jssettings(&jsobj, "_debuggerSettings");
- debugger()->PrintSettingsToJSONObject(&jssettings);
- }
+ Dart_ExceptionPauseInfo pause_info = (debugger() != NULL)
+ ? debugger()->GetExceptionPauseInfo()
+ : kNoPauseOnExceptions;
+ jsobj.AddProperty("exceptionPauseMode",
+ ExceptionPauseInfoToServiceEnum(pause_info));
+
+ if (debugger() != NULL) {
+ JSONObject settings(&jsobj, "_debuggerSettings");
+ debugger()->PrintSettingsToJSONObject(&settings);
}
{
@@ -2081,6 +2133,7 @@
}
+#ifndef PRODUCT
RawObject* Isolate::InvokePendingServiceExtensionCalls() {
if (!FLAG_support_service) {
return Object::null();
@@ -2261,6 +2314,7 @@
}
return Instance::null();
}
+#endif // !PRODUCT
void Isolate::WakePauseEventHandler(Dart_Isolate isolate) {
@@ -2403,6 +2457,12 @@
}
+bool Isolate::IsolateCreationEnabled() {
+ MonitorLocker ml(isolates_list_monitor_);
+ return creation_enabled_;
+}
+
+
void Isolate::KillLocked(LibMsgId msg_id) {
Dart_CObject kill_msg;
Dart_CObject* list_values[4];
@@ -2527,7 +2587,7 @@
// If a safepoint operation is in progress wait for it
// to finish before scheduling this thread in.
- while (!bypass_safepoint && safepoint_handler()->safepoint_in_progress()) {
+ while (!bypass_safepoint && safepoint_handler()->SafepointInProgress()) {
ml.Wait();
}
diff --git a/runtime/vm/isolate.h b/runtime/vm/isolate.h
index 7f1df6d..b49d59b 100644
--- a/runtime/vm/isolate.h
+++ b/runtime/vm/isolate.h
@@ -255,7 +255,9 @@
void DoneLoading();
void DoneFinalizing();
- void ReloadSources(bool test_mode = false);
+ // By default the reload context is deleted. This parameter allows
+ // the caller to delete is separately if it is still needed.
+ void ReloadSources(bool dont_delete_reload_context = false);
bool MakeRunnable();
void Run();
@@ -480,6 +482,8 @@
return reload_context_;
}
+ void DeleteReloadContext();
+
bool HasAttemptedReload() const {
return has_attempted_reload_;
}
@@ -583,6 +587,7 @@
// Returns Field::null() if none available in the list.
RawField* GetDeoptimizingBoxedField();
+#ifndef PRODUCT
RawObject* InvokePendingServiceExtensionCalls();
void AppendServiceExtensionCall(const Instance& closure,
const String& method_name,
@@ -593,6 +598,7 @@
void RegisterServiceExtensionHandler(const String& name,
const Instance& closure);
RawInstance* LookupServiceExtensionHandler(const String& name);
+#endif
static void VisitIsolates(IsolateVisitor* visitor);
@@ -629,9 +635,16 @@
static void DisableIsolateCreation();
static void EnableIsolateCreation();
+ static bool IsolateCreationEnabled();
void StopBackgroundCompiler();
+ intptr_t reload_every_n_stack_overflow_checks() const {
+ return reload_every_n_stack_overflow_checks_;
+ }
+
+ void MaybeIncreaseReloadEveryNStackOverflowChecks();
+
private:
friend class Dart; // Init, InitOnce, Shutdown.
friend class IsolateKillerVisitor; // Kill().
@@ -815,6 +828,8 @@
// Has a reload ever been attempted?
bool has_attempted_reload_;
intptr_t no_reload_scope_depth_; // we can only reload when this is 0.
+ // Per-isolate copy of FLAG_reload_every.
+ intptr_t reload_every_n_stack_overflow_checks_;
IsolateReloadContext* reload_context_;
#define ISOLATE_METRIC_VARIABLE(type, variable, name, unit) \
diff --git a/runtime/vm/isolate_reload.cc b/runtime/vm/isolate_reload.cc
index 15aaf29..158f655 100644
--- a/runtime/vm/isolate_reload.cc
+++ b/runtime/vm/isolate_reload.cc
@@ -24,6 +24,8 @@
namespace dart {
DEFINE_FLAG(bool, trace_reload, false, "Trace isolate reloading");
+DEFINE_FLAG(bool, trace_reload_verbose, false,
+ "trace isolate reloading verbose");
DEFINE_FLAG(bool, identity_reload, false, "Enable checks for identity reload.");
DEFINE_FLAG(int, reload_every, 0, "Reload every N stack overflow checks.");
DEFINE_FLAG(bool, reload_every_optimized, true, "Only from optimized code.");
@@ -42,6 +44,152 @@
#name)
+InstanceMorpher::InstanceMorpher(const Class& from, const Class& to)
+ : from_(from), to_(to), mapping_() {
+ ComputeMapping();
+ before_ = new ZoneGrowableArray<const Instance*>();
+ after_ = new ZoneGrowableArray<const Instance*>();
+ ASSERT(from_.id() == to_.id());
+ cid_ = from_.id();
+}
+
+
+void InstanceMorpher::AddObject(RawObject* object) const {
+ ASSERT(object->GetClassId() == cid());
+ const Instance& instance = Instance::Cast(Object::Handle(object));
+ before_->Add(&instance);
+}
+
+
+void InstanceMorpher::ComputeMapping() {
+ if (from_.NumTypeArguments()) {
+ // Add copying of the optional type argument field.
+ intptr_t from_offset = from_.type_arguments_field_offset();
+ ASSERT(from_offset != Class::kNoTypeArguments);
+ intptr_t to_offset = to_.type_arguments_field_offset();
+ ASSERT(to_offset != Class::kNoTypeArguments);
+ mapping_.Add(from_offset);
+ mapping_.Add(to_offset);
+ }
+
+ // Add copying of the instance fields if matching by name.
+ // Note: currently the type of the fields are ignored.
+ const Array& from_fields = Array::Handle(from_.OffsetToFieldMap());
+ const Array& to_fields = Array::Handle(to_.OffsetToFieldMap());
+ Field& from_field = Field::Handle();
+ Field& to_field = Field::Handle();
+ String& from_name = String::Handle();
+ String& to_name = String::Handle();
+ for (intptr_t i = 0; i < from_fields.Length(); i++) {
+ if (from_fields.At(i) == Field::null()) continue; // Ignore non-fields.
+ from_field = Field::RawCast(from_fields.At(i));
+ ASSERT(from_field.is_instance());
+ from_name = from_field.name();
+ // We now have to find where this field is in the to class.
+ for (intptr_t j = 0; j < to_fields.Length(); j++) {
+ if (to_fields.At(j) == Field::null()) continue; // Ignore non-fields.
+ to_field = Field::RawCast(to_fields.At(j));
+ ASSERT(to_field.is_instance());
+ to_name = to_field.name();
+ if (from_name.Equals(to_name)) {
+ // Success
+ mapping_.Add(from_field.Offset());
+ mapping_.Add(to_field.Offset());
+ }
+ }
+ }
+}
+
+
+RawInstance* InstanceMorpher::Morph(const Instance& instance) const {
+ const Instance& result = Instance::Handle(Instance::New(to_));
+ // Morph the context from instance to result using mapping_.
+ for (intptr_t i = 0; i < mapping_.length(); i +=2) {
+ intptr_t from_offset = mapping_.At(i);
+ intptr_t to_offset = mapping_.At(i+1);
+ const Object& value =
+ Object::Handle(instance.RawGetFieldAtOffset(from_offset));
+ result.RawSetFieldAtOffset(to_offset, value);
+ }
+ // Convert the instance into a filler object.
+ Become::MakeDummyObject(instance);
+ return result.raw();
+}
+
+
+void InstanceMorpher::CreateMorphedCopies() const {
+ for (intptr_t i = 0; i < before()->length(); i++) {
+ const Instance& copy = Instance::Handle(Morph(*before()->At(i)));
+ after()->Add(©);
+ }
+}
+
+
+void InstanceMorpher::DumpFormatFor(const Class& cls) const {
+ THR_Print("%s\n", cls.ToCString());
+ if (cls.NumTypeArguments()) {
+ intptr_t field_offset = cls.type_arguments_field_offset();
+ ASSERT(field_offset != Class::kNoTypeArguments);
+ THR_Print(" - @%" Pd " <type arguments>\n", field_offset);
+ }
+ const Array& fields = Array::Handle(cls.OffsetToFieldMap());
+ Field& field = Field::Handle();
+ String& name = String::Handle();
+ for (intptr_t i = 0; i < fields.Length(); i++) {
+ if (fields.At(i) != Field::null()) {
+ field = Field::RawCast(fields.At(i));
+ ASSERT(field.is_instance());
+ name = field.name();
+ THR_Print(" - @%" Pd " %s\n", field.Offset(), name.ToCString());
+ }
+ }
+
+ THR_Print("Mapping: ");
+ for (int i = 0; i < mapping_.length(); i +=2) {
+ THR_Print(" %" Pd "->%" Pd, mapping_.At(i), mapping_.At(i+1));
+ }
+ THR_Print("\n");
+}
+
+
+void InstanceMorpher::Dump() const {
+ LogBlock blocker;
+ THR_Print("Morphing from ");
+ DumpFormatFor(from_);
+ THR_Print("To ");
+ DumpFormatFor(to_);
+ THR_Print("\n");
+}
+
+
+void ReasonForCancelling::Report(IsolateReloadContext* context) {
+ const Error& error = Error::Handle(ToError());
+ context->ReportError(error);
+}
+
+
+RawError* ReasonForCancelling::ToError() {
+ // By default create the error returned from ToString.
+ const String& message = String::Handle(ToString());
+ return LanguageError::New(message);
+}
+
+
+RawString* ReasonForCancelling::ToString() {
+ UNREACHABLE();
+ return NULL;
+}
+
+
+RawError* IsolateReloadContext::error() const {
+ ASSERT(has_error());
+ // Report the first error to the surroundings.
+ const Error& error =
+ Error::Handle(reasons_to_cancel_reload_.At(0)->ToError());
+ OS::Print("[[%s]]\n", error.ToCString());
+ return error.raw();
+}
+
class ScriptUrlSetTraits {
public:
static bool ReportStats() { return false; }
@@ -117,6 +265,8 @@
return String::HashRawSymbol(Class::Cast(obj).Name());
} else if (obj.IsField()) {
return String::HashRawSymbol(Field::Cast(obj).name());
+ } else if (obj.IsInstance()) {
+ return Smi::Handle(Smi::RawCast(Instance::Cast(obj).HashCode())).Value();
}
return 0;
}
@@ -173,28 +323,77 @@
}
-IsolateReloadContext::IsolateReloadContext(Isolate* isolate, bool test_mode)
+IsolateReloadContext::IsolateReloadContext(Isolate* isolate)
: start_time_micros_(OS::GetCurrentMonotonicMicros()),
isolate_(isolate),
- test_mode_(test_mode),
- has_error_(false),
saved_num_cids_(-1),
saved_class_table_(NULL),
num_saved_libs_(-1),
+ instance_morphers_(),
+ reasons_to_cancel_reload_(),
+ cid_mapper_(),
script_uri_(String::null()),
error_(Error::null()),
- clean_scripts_set_storage_(Array::null()),
- compile_time_constants_(Array::null()),
old_classes_set_storage_(Array::null()),
class_map_storage_(Array::null()),
old_libraries_set_storage_(Array::null()),
library_map_storage_(Array::null()),
become_map_storage_(Array::null()),
+ become_enum_mappings_(GrowableObjectArray::null()),
saved_root_library_(Library::null()),
saved_libraries_(GrowableObjectArray::null()) {
+ // NOTE: DO NOT ALLOCATE ANY RAW OBJECTS HERE. The IsolateReloadContext is not
+ // associated with the isolate yet and if a GC is triggered here the raw
+ // objects will not be properly accounted for.
+}
+
+
+IsolateReloadContext::~IsolateReloadContext() {
+}
+
+
+void IsolateReloadContext::ReportError(const Error& error) {
+ if (FLAG_trace_reload) {
+ THR_Print("ISO-RELOAD: Error: %s\n", error.ToErrorCString());
+ }
+ ServiceEvent service_event(I, ServiceEvent::kIsolateReload);
+ service_event.set_reload_error(&error);
+ Service::HandleEvent(&service_event);
+}
+
+
+void IsolateReloadContext::ReportSuccess() {
+ ServiceEvent service_event(I, ServiceEvent::kIsolateReload);
+ Service::HandleEvent(&service_event);
+}
+
+
+class Aborted : public ReasonForCancelling {
+ public:
+ explicit Aborted(const Error& error)
+ : ReasonForCancelling(), error_(error) { }
+
+ private:
+ const Error& error_;
+
+ RawError* ToError() { return error_.raw(); }
+ RawString* ToString() {
+ return String::NewFormatted("%s", error_.ToErrorCString());
+ }
+};
+
+
+void IsolateReloadContext::StartReload() {
+ TIMELINE_SCOPE(Reload);
+ Thread* thread = Thread::Current();
+ ASSERT(isolate() == thread->isolate());
+
+ // Grab root library before calling CheckpointBeforeReload.
+ const Library& root_lib = Library::Handle(object_store()->root_library());
+ ASSERT(!root_lib.IsNull());
+ const String& root_lib_url = String::Handle(root_lib.url());
+
// Preallocate storage for maps.
- clean_scripts_set_storage_ =
- HashTables::New<UnorderedHashSet<ScriptUrlSetTraits> >(4);
old_classes_set_storage_ =
HashTables::New<UnorderedHashSet<ClassMapTraits> >(4);
class_map_storage_ =
@@ -205,44 +404,9 @@
HashTables::New<UnorderedHashMap<LibraryMapTraits> >(4);
become_map_storage_ =
HashTables::New<UnorderedHashMap<BecomeMapTraits> >(4);
-}
-
-
-IsolateReloadContext::~IsolateReloadContext() {
-}
-
-
-void IsolateReloadContext::ReportError(const Error& error) {
- has_error_ = true;
- error_ = error.raw();
- if (FLAG_trace_reload) {
- THR_Print("ISO-RELOAD: Error: %s\n", error.ToErrorCString());
- }
- ServiceEvent service_event(I, ServiceEvent::kIsolateReload);
- service_event.set_reload_error(&error);
- Service::HandleEvent(&service_event);
-}
-
-
-void IsolateReloadContext::ReportError(const String& error_msg) {
- ReportError(LanguageError::Handle(LanguageError::New(error_msg)));
-}
-
-
-void IsolateReloadContext::ReportSuccess() {
- ServiceEvent service_event(I, ServiceEvent::kIsolateReload);
- Service::HandleEvent(&service_event);
-}
-
-
-void IsolateReloadContext::StartReload() {
- TIMELINE_SCOPE(Reload);
- Thread* thread = Thread::Current();
-
- // Grab root library before calling CheckpointBeforeReload.
- const Library& root_lib = Library::Handle(object_store()->root_library());
- ASSERT(!root_lib.IsNull());
- const String& root_lib_url = String::Handle(root_lib.url());
+ // Keep a separate array for enum mappings to avoid having to invoke
+ // hashCode on the instances.
+ become_enum_mappings_ = GrowableObjectArray::New(Heap::kOld);
// Disable the background compiler while we are performing the reload.
BackgroundCompiler::Disable();
@@ -273,7 +437,8 @@
result = Api::UnwrapHandle(retval);
}
if (result.IsError()) {
- ReportError(Error::Cast(result));
+ const Error& error = Error::Cast(result);
+ AddReasonForCancelling(new Aborted(error));
}
}
@@ -311,6 +476,7 @@
Commit();
PostCommit();
} else {
+ ReportReasonsForCancelling();
Rollback();
}
// ValidateReload mutates the direct subclass information and does
@@ -328,7 +494,8 @@
void IsolateReloadContext::AbortReload(const Error& error) {
- ReportError(error);
+ AddReasonForCancelling(new Aborted(error));
+ ReportReasonsForCancelling();
Rollback();
}
@@ -476,86 +643,6 @@
}
-void IsolateReloadContext::BuildCleanScriptSet() {
- const GrowableObjectArray& libs =
- GrowableObjectArray::Handle(object_store()->libraries());
-
- UnorderedHashSet<ScriptUrlSetTraits>
- clean_scripts_set(clean_scripts_set_storage_);
-
- Library& lib = Library::Handle();
- Array& scripts = Array::Handle();
- Script& script = Script::Handle();
- String& script_url = String::Handle();
- for (intptr_t lib_idx = 0; lib_idx < libs.Length(); lib_idx++) {
- lib = Library::RawCast(libs.At(lib_idx));
- ASSERT(!lib.IsNull());
- ASSERT(IsCleanLibrary(lib));
- scripts = lib.LoadedScripts();
- ASSERT(!scripts.IsNull());
- for (intptr_t script_idx = 0; script_idx < scripts.Length(); script_idx++) {
- script = Script::RawCast(scripts.At(script_idx));
- ASSERT(!script.IsNull());
- script_url = script.url();
- ASSERT(!script_url.IsNull());
- bool already_present = clean_scripts_set.Insert(script_url);
- ASSERT(!already_present);
- }
- }
-
- clean_scripts_set_storage_ = clean_scripts_set.Release().raw();
-}
-
-
-void IsolateReloadContext::FilterCompileTimeConstants() {
- // Save the compile time constants array.
- compile_time_constants_ = I->object_store()->compile_time_constants();
- // Clear the compile time constants array. This will be repopulated
- // in the loop below.
- I->object_store()->set_compile_time_constants(Array::Handle());
-
- if (compile_time_constants_ == Array::null()) {
- // Nothing to do.
- return;
- }
-
- // Iterate over the saved compile time constants map.
- ConstantsMap old_constants(compile_time_constants_);
- ConstantsMap::Iterator it(&old_constants);
-
- Array& key = Array::Handle();
- String& url = String::Handle();
- Smi& token_pos = Smi::Handle();
- Instance& value = Instance::Handle();
-
- // We filter the compile time constants map so that after it only contains
- // constants from scripts contained in this set.
- UnorderedHashSet<ScriptUrlSetTraits>
- clean_scripts_set(clean_scripts_set_storage_);
-
- while (it.MoveNext()) {
- const intptr_t entry = it.Current();
- ASSERT(entry != -1);
- key = Array::RawCast(old_constants.GetKey(entry));
- ASSERT(!key.IsNull());
- url = String::RawCast(key.At(0));
- ASSERT(!url.IsNull());
- if (clean_scripts_set.ContainsKey(url)) {
- // We've found a cached constant from a clean script, add it to the
- // compile time constants map again.
- token_pos = Smi::RawCast(key.At(1));
- TokenPosition tp(token_pos.Value());
- // Use ^= because this might be null.
- value ^= old_constants.GetPayload(entry, 0);
- Parser::InsertCachedConstantValue(url, tp, value);
- }
- }
-
- old_constants.Release();
- clean_scripts_set.Release();
-}
-
-
// While reloading everything we do must be reversible so that we can abort
// safely if the reload fails. This function stashes things to the side and
// prepares the isolate for the reload attempt.
@@ -563,8 +650,6 @@
TIMELINE_SCOPE(Checkpoint);
CheckpointClasses();
CheckpointLibraries();
- BuildCleanScriptSet();
- FilterCompileTimeConstants();
}
@@ -614,8 +699,6 @@
void IsolateReloadContext::Rollback() {
- I->object_store()->set_compile_time_constants(
- Array::Handle(compile_time_constants_));
RollbackClasses();
RollbackLibraries();
}
@@ -661,6 +744,15 @@
TIMELINE_SCOPE(Commit);
TIR_Print("---- COMMITTING REVERSE MAP\n");
+ // Note that the object heap contains before and after instances
+ // used for morphing. It is therefore important that morphing takes
+ // place prior to any heap walking.
+ // So please keep this code at the top of Commit().
+ if (HasInstanceMorphers()) {
+ // Perform shape shifting of instances if necessary.
+ MorphInstances();
+ }
+
#ifdef DEBUG
VerifyMaps();
#endif
@@ -685,8 +777,9 @@
ASSERT(new_cls.is_enum_class() == cls.is_enum_class());
if (new_cls.is_enum_class() && new_cls.is_finalized()) {
new_cls.ReplaceEnum(cls);
+ } else {
+ new_cls.CopyStaticFieldValues(cls);
}
- new_cls.CopyStaticFieldValues(cls);
cls.PatchFieldsAndFunctions();
}
}
@@ -729,7 +822,7 @@
I->object_store()->libraries());
for (intptr_t i = 0; i < libs.Length(); i++) {
lib = Library::RawCast(libs.At(i));
- TIR_Print("Lib '%s' at index %" Pd "\n", lib.ToCString(), i);
+ VTIR_Print("Lib '%s' at index %" Pd "\n", lib.ToCString(), i);
lib.set_index(i);
}
@@ -743,8 +836,11 @@
}
{
+ const GrowableObjectArray& become_enum_mappings =
+ GrowableObjectArray::Handle(become_enum_mappings_);
UnorderedHashMap<BecomeMapTraits> become_map(become_map_storage_);
- intptr_t replacement_count = become_map.NumOccupied();
+ intptr_t replacement_count = become_map.NumOccupied() +
+ become_enum_mappings.Length() / 2;
const Array& before =
Array::Handle(Array::New(replacement_count, Heap::kOld));
const Array& after =
@@ -760,6 +856,13 @@
after.SetAt(replacement_index, obj);
replacement_index++;
}
+ for (intptr_t i = 0; i < become_enum_mappings.Length(); i += 2) {
+ obj = become_enum_mappings.At(i);
+ before.SetAt(replacement_index, obj);
+ obj = become_enum_mappings.At(i + 1);
+ after.SetAt(replacement_index, obj);
+ replacement_index++;
+ }
ASSERT(replacement_index == replacement_count);
become_map.Release();
@@ -801,34 +904,150 @@
set_saved_root_library(Library::Handle());
set_saved_libraries(GrowableObjectArray::Handle());
InvalidateWorld();
+ TIR_Print("---- DONE COMMIT\n");
+}
+
+
+void IsolateReloadContext::AddReasonForCancelling(ReasonForCancelling* reason) {
+ reasons_to_cancel_reload_.Add(reason);
+}
+
+
+void IsolateReloadContext::AddInstanceMorpher(InstanceMorpher* morpher) {
+ instance_morphers_.Add(morpher);
+ cid_mapper_.Insert(morpher);
+}
+
+
+void IsolateReloadContext::ReportReasonsForCancelling() {
+ ASSERT(HasReasonsForCancelling());
+ for (int i = 0; i < reasons_to_cancel_reload_.length(); i++) {
+ reasons_to_cancel_reload_.At(i)->Report(this);
+ }
+}
+
+
+// The ObjectLocator is used for collecting instances that
+// needs to be morphed.
+class ObjectLocator : public ObjectVisitor {
+ public:
+ explicit ObjectLocator(IsolateReloadContext* context)
+ : context_(context), count_(0) {
+ }
+
+ void VisitObject(RawObject* obj) {
+ InstanceMorpher* morpher =
+ context_->cid_mapper_.LookupValue(obj->GetClassId());
+ if (morpher != NULL) {
+ morpher->AddObject(obj);
+ count_++;
+ }
+ }
+
+ // Return the number of located objects for morphing.
+ intptr_t count() { return count_; }
+
+ private:
+ IsolateReloadContext* context_;
+ intptr_t count_;
+};
+
+
+void IsolateReloadContext::MorphInstances() {
+ TIMELINE_SCOPE(MorphInstances);
+ ASSERT(HasInstanceMorphers());
+ if (FLAG_trace_reload) {
+ LogBlock blocker;
+ TIR_Print("MorphInstance: \n");
+ for (intptr_t i = 0; i < instance_morphers_.length(); i++) {
+ instance_morphers_.At(i)->Dump();
+ }
+ }
+
+ // Find all objects that need to be morphed.
+ ObjectLocator locator(this);
+ isolate()->heap()->VisitObjects(&locator);
+
+ // Return if no objects are located.
+ intptr_t count = locator.count();
+ if (count == 0) return;
+
+ TIR_Print("Found %" Pd " object%s subject to morphing.\n",
+ count, (count > 1) ? "s" : "");
+
+ Array& before = Array::Handle();
+ Array& after = Array::Handle();
+ { // Prevent GC to take place due object format confusion.
+ // Hint: More than one class share the same cid.
+ NoHeapGrowthControlScope scope;
+ for (intptr_t i = 0; i < instance_morphers_.length(); i++) {
+ instance_morphers_.At(i)->CreateMorphedCopies();
+ }
+ // Create the inputs for Become.
+ intptr_t index = 0;
+ before = Array::New(count);
+ after = Array::New(count);
+ for (intptr_t i = 0; i < instance_morphers_.length(); i++) {
+ InstanceMorpher* morpher = instance_morphers_.At(i);
+ for (intptr_t j = 0; j < morpher->before()->length(); j++) {
+ before.SetAt(index, *morpher->before()->At(j));
+ after.SetAt(index, *morpher->after()->At(j));
+ index++;
+ }
+ }
+ ASSERT(index == count);
+ }
+
+ // This is important: The saved class table (describing before objects)
+ // must be zapped to prevent the forwarding in GetClassForHeapWalkAt.
+ // Instance will from now be described by the isolate's class table.
+ free(saved_class_table_);
+ saved_class_table_ = NULL;
+ Become::ElementsForwardIdentity(before, after);
}
bool IsolateReloadContext::ValidateReload() {
TIMELINE_SCOPE(ValidateReload);
- if (has_error_) {
- return false;
- }
+ if (has_error()) return false;
- // Already built.
- ASSERT(class_map_storage_ != Array::null());
- UnorderedHashMap<ClassMapTraits> map(class_map_storage_);
- UnorderedHashMap<ClassMapTraits>::Iterator it(&map);
- Class& cls = Class::Handle();
- Class& new_cls = Class::Handle();
- while (it.MoveNext()) {
- const intptr_t entry = it.Current();
- new_cls = Class::RawCast(map.GetKey(entry));
- cls = Class::RawCast(map.GetPayload(entry, 0));
- if (new_cls.raw() != cls.raw()) {
- if (!cls.CanReload(new_cls)) {
- map.Release();
- return false;
+ // Validate libraries.
+ {
+ ASSERT(library_map_storage_ != Array::null());
+ UnorderedHashMap<LibraryMapTraits> map(library_map_storage_);
+ UnorderedHashMap<LibraryMapTraits>::Iterator it(&map);
+ Library& lib = Library::Handle();
+ Library& new_lib = Library::Handle();
+ while (it.MoveNext()) {
+ const intptr_t entry = it.Current();
+ new_lib = Library::RawCast(map.GetKey(entry));
+ lib = Library::RawCast(map.GetPayload(entry, 0));
+ if (new_lib.raw() != lib.raw()) {
+ lib.CheckReload(new_lib, this);
}
}
+ map.Release();
}
- map.Release();
- return true;
+
+ // Validate classes.
+ {
+ ASSERT(class_map_storage_ != Array::null());
+ UnorderedHashMap<ClassMapTraits> map(class_map_storage_);
+ UnorderedHashMap<ClassMapTraits>::Iterator it(&map);
+ Class& cls = Class::Handle();
+ Class& new_cls = Class::Handle();
+ while (it.MoveNext()) {
+ const intptr_t entry = it.Current();
+ new_cls = Class::RawCast(map.GetKey(entry));
+ cls = Class::RawCast(map.GetPayload(entry, 0));
+ if (new_cls.raw() != cls.raw()) {
+ cls.CheckReload(new_cls, this);
+ }
+ }
+ map.Release();
+ }
+
+ return !HasReasonsForCancelling();
}
@@ -950,6 +1169,8 @@
if (!stub_code) {
if (clear_code) {
+ VTIR_Print("Marking %s for recompilation, clearning code\n",
+ func.ToCString());
ClearAllCode(func);
} else {
PreserveUnoptimizedCode();
@@ -995,6 +1216,7 @@
void IsolateReloadContext::MarkAllFunctionsForRecompilation() {
TIMELINE_SCOPE(MarkAllFunctionsForRecompilation);
+ TIR_Print("---- MARKING ALL FUNCTIONS FOR RECOMPILATION\n");
NoSafepointScope no_safepoint;
HeapIterationScope heap_iteration_scope;
MarkFunctionsForRecompilation visitor(isolate_, this);
@@ -1003,6 +1225,7 @@
void IsolateReloadContext::InvalidateWorld() {
+ TIR_Print("---- INVALIDATING WORLD\n");
ResetMegamorphicCaches();
DeoptimizeFunctionsOnStack();
ResetUnoptimizedICsOnStack();
@@ -1129,6 +1352,16 @@
}
+void IsolateReloadContext::AddEnumBecomeMapping(const Object& old,
+ const Object& neu) {
+ const GrowableObjectArray& become_enum_mappings =
+ GrowableObjectArray::Handle(become_enum_mappings_);
+ become_enum_mappings.Add(old);
+ become_enum_mappings.Add(neu);
+ ASSERT((become_enum_mappings.Length() % 2) == 0);
+}
+
+
void IsolateReloadContext::RebuildDirectSubclasses() {
ClassTable* class_table = I->class_table();
intptr_t num_cids = class_table->NumCids();
diff --git a/runtime/vm/isolate_reload.h b/runtime/vm/isolate_reload.h
index de6ff00..ce316f6 100644
--- a/runtime/vm/isolate_reload.h
+++ b/runtime/vm/isolate_reload.h
@@ -5,11 +5,13 @@
#ifndef VM_ISOLATE_RELOAD_H_
#define VM_ISOLATE_RELOAD_H_
+#include "vm/hash_map.h"
#include "vm/globals.h"
#include "vm/growable_array.h"
#include "vm/log.h"
DECLARE_FLAG(bool, trace_reload);
+DECLARE_FLAG(bool, trace_reload_verbose);
// 'Trace Isolate Reload' TIR_Print
#if defined(_MSC_VER)
@@ -20,6 +22,15 @@
if (FLAG_trace_reload) Log::Current()->Print(format, ##__VA_ARGS__)
#endif
+// 'Verbose Trace Isolate Reload' VTIR_Print
+#if defined(_MSC_VER)
+#define VTIR_Print(format, ...) \
+ if (FLAG_trace_reload_verbose) Log::Current()->Print(format, __VA_ARGS__)
+#else
+#define VTIR_Print(format, ...) \
+ if (FLAG_trace_reload_verbose) Log::Current()->Print(format, ##__VA_ARGS__)
+#endif
+
namespace dart {
class GrowableObjectArray;
@@ -34,9 +45,80 @@
class ObjectStore;
class UpdateClassesVisitor;
+
+class InstanceMorpher : public ZoneAllocated {
+ public:
+ InstanceMorpher(const Class& from, const Class& to);
+ virtual ~InstanceMorpher() {}
+
+ // Called on each instance that needs to be morphed.
+ RawInstance* Morph(const Instance& instance) const;
+
+ // Adds an object to be morphed.
+ void AddObject(RawObject* object) const;
+
+ // Create the morphed objects based on the before() list.
+ void CreateMorphedCopies() const;
+
+ // Dump the state of the morpher.
+ void Dump() const;
+
+ // Returns the list of objects that need to be morphed.
+ ZoneGrowableArray<const Instance*>* before() const { return before_; }
+ // Returns the list of morphed objects (matches order in before()).
+ ZoneGrowableArray<const Instance*>* after() const { return after_; }
+
+ // Returns the cid associated with the from_ and to_ class.
+ intptr_t cid() const { return cid_; }
+
+ private:
+ const Class& from_;
+ const Class& to_;
+ ZoneGrowableArray<intptr_t> mapping_;
+ ZoneGrowableArray<const Instance*>* before_;
+ ZoneGrowableArray<const Instance*>* after_;
+ intptr_t cid_;
+
+ void ComputeMapping();
+ void DumpFormatFor(const Class& cls) const;
+};
+
+
+class ReasonForCancelling : public ZoneAllocated {
+ public:
+ ReasonForCancelling() {}
+ virtual ~ReasonForCancelling() {}
+
+ // Reports a reason for cancelling reload.
+ void Report(IsolateReloadContext* context);
+
+ // Conversion to a VM error object.
+ // Default implementation calls ToString.
+ virtual RawError* ToError();
+
+ // Conversion to a string object.
+ // Default implementation calls ToError.
+ virtual RawString* ToString();
+
+ // Concrete subclasses must override either ToError or ToString.
+};
+
+
+// Abstract class for also capturing the from_ and to_ class.
+class ClassReasonForCancelling : public ReasonForCancelling {
+ public:
+ ClassReasonForCancelling(const Class& from, const Class& to)
+ : from_(from), to_(to) { }
+
+ protected:
+ const Class& from_;
+ const Class& to_;
+};
+
+
class IsolateReloadContext {
public:
- explicit IsolateReloadContext(Isolate* isolate, bool test_mode = false);
+ explicit IsolateReloadContext(Isolate* isolate);
~IsolateReloadContext();
void StartReload();
@@ -47,13 +129,12 @@
RawGrowableObjectArray* saved_libraries() const;
+ // Report back through the observatory channels.
void ReportError(const Error& error);
- void ReportError(const String& error_msg);
void ReportSuccess();
- bool has_error() const { return has_error_; }
- RawError* error() const { return error_; }
- bool test_mode() const { return test_mode_; }
+ bool has_error() const { return HasReasonsForCancelling(); }
+ RawError* error() const;
static bool IsSameField(const Field& a, const Field& b);
static bool IsSameLibrary(const Library& a_lib, const Library& b_lib);
@@ -74,6 +155,25 @@
int64_t start_time_micros() const { return start_time_micros_; }
+ // Tells whether there are reasons for cancelling the reload.
+ bool HasReasonsForCancelling() const {
+ return !reasons_to_cancel_reload_.is_empty();
+ }
+
+ // Record problem for this reload.
+ void AddReasonForCancelling(ReasonForCancelling* reason);
+
+ // Report all reasons for cancelling reload.
+ void ReportReasonsForCancelling();
+
+ // Store morphing operation.
+ void AddInstanceMorpher(InstanceMorpher* morpher);
+
+ // Tells whether instance in the heap must be morphed.
+ bool HasInstanceMorphers() const {
+ return !instance_morphers_.is_empty();
+ }
+
private:
void set_saved_root_library(const Library& value);
@@ -95,6 +195,9 @@
bool IsCleanLibrary(const Library& lib);
void CheckpointLibraries();
+ // Transforms the heap based on instance_morphers_.
+ void MorphInstances();
+
bool ValidateReload();
void Rollback();
@@ -112,9 +215,6 @@
void ClearReplacedObjectBits();
- void BuildCleanScriptSet();
- void FilterCompileTimeConstants();
-
// atomic_install:
void MarkAllFunctionsForRecompilation();
void ResetUnoptimizedICsOnStack();
@@ -123,13 +223,32 @@
int64_t start_time_micros_;
Isolate* isolate_;
- bool test_mode_;
- bool has_error_;
intptr_t saved_num_cids_;
RawClass** saved_class_table_;
-
intptr_t num_saved_libs_;
+
+ // Collect the necessary instance transformation for schema changes.
+ ZoneGrowableArray<InstanceMorpher*> instance_morphers_;
+
+ // Collects the reasons for cancelling the reload.
+ ZoneGrowableArray<ReasonForCancelling*> reasons_to_cancel_reload_;
+
+ // Required trait for the cid_mapper_;
+ struct MorpherTrait {
+ typedef InstanceMorpher* Value;
+ typedef intptr_t Key;
+ typedef InstanceMorpher* Pair;
+
+ static Key KeyOf(Pair kv) { return kv->cid(); }
+ static Value ValueOf(Pair kv) { return kv; }
+ static intptr_t Hashcode(Key key) { return key; }
+ static bool IsKeyEqual(Pair kv, Key key) { return kv->cid() == key; }
+ };
+
+ // Hash map from cid to InstanceMorpher.
+ DirectChainedHashMap<MorpherTrait> cid_mapper_;
+
struct LibraryInfo {
bool dirty;
};
@@ -148,7 +267,8 @@
void AddStaticFieldMapping(const Field& old_field, const Field& new_field);
- void AddBecomeMapping(const Object& old, const Object& nue);
+ void AddBecomeMapping(const Object& old, const Object& neu);
+ void AddEnumBecomeMapping(const Object& old, const Object& neu);
void RebuildDirectSubclasses();
@@ -158,19 +278,19 @@
RawObject** from() { return reinterpret_cast<RawObject**>(&script_uri_); }
RawString* script_uri_;
RawError* error_;
- RawArray* clean_scripts_set_storage_;
- RawArray* compile_time_constants_;
RawArray* old_classes_set_storage_;
RawArray* class_map_storage_;
RawArray* old_libraries_set_storage_;
RawArray* library_map_storage_;
RawArray* become_map_storage_;
+ RawGrowableObjectArray* become_enum_mappings_;
RawLibrary* saved_root_library_;
RawGrowableObjectArray* saved_libraries_;
RawObject** to() { return reinterpret_cast<RawObject**>(&saved_libraries_); }
friend class Isolate;
- friend class Class; // AddStaticFieldMapping.
+ friend class Class; // AddStaticFieldMapping, AddEnumBecomeMapping.
+ friend class ObjectLocator;
};
} // namespace dart
diff --git a/runtime/vm/isolate_reload_test.cc b/runtime/vm/isolate_reload_test.cc
index aa8f188..d060680 100644
--- a/runtime/vm/isolate_reload_test.cc
+++ b/runtime/vm/isolate_reload_test.cc
@@ -65,7 +65,6 @@
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
-
EXPECT_EQ(10, SimpleInvoke(lib, "main"));
}
@@ -83,7 +82,6 @@
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
-
EXPECT_EQ(4, SimpleInvoke(lib, "main"));
const char* kReloadScript =
@@ -99,7 +97,6 @@
Dart_Handle result = TestCase::ReloadTestScript(kReloadScript);
EXPECT_ERROR(result, "unexpected token");
-
EXPECT_EQ(4, SimpleInvoke(lib, "main"));
}
@@ -114,7 +111,6 @@
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
-
EXPECT_STREQ("init()=old value,value=old value",
SimpleInvokeStr(lib, "main"));
@@ -128,7 +124,6 @@
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
-
EXPECT_STREQ("init()=new value,value=old value",
SimpleInvokeStr(lib, "main"));
}
@@ -149,7 +144,6 @@
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
-
EXPECT_STREQ("antediluvian!", SimpleInvokeStr(lib, "main"));
// Remove the original closure from the source code. The closure is
@@ -166,7 +160,6 @@
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
-
EXPECT_STREQ("postapocalyptic!", SimpleInvokeStr(lib, "main"));
}
@@ -180,7 +173,6 @@
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
-
EXPECT_STREQ("value1=10", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
@@ -192,9 +184,7 @@
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
-
- EXPECT_STREQ("value1=10,value2=20",
- SimpleInvokeStr(lib, "main"));
+ EXPECT_STREQ("value1=10,value2=20", SimpleInvokeStr(lib, "main"));
}
@@ -210,7 +200,6 @@
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
-
EXPECT_EQ(44, SimpleInvoke(lib, "main"));
const char* kReloadScript =
@@ -224,7 +213,8 @@
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
- EXPECT_ERROR(lib, "Number of instance fields changed");
+ EXPECT_VALID(lib);
+ EXPECT_EQ(44, SimpleInvoke(lib, "main"));
}
@@ -241,7 +231,6 @@
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
-
EXPECT_EQ(44, SimpleInvoke(lib, "main"));
const char* kReloadScript =
@@ -256,7 +245,8 @@
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
- EXPECT_ERROR(lib, "Number of instance fields changed");
+ EXPECT_VALID(lib);
+ EXPECT_EQ(44, SimpleInvoke(lib, "main"));
}
@@ -273,7 +263,6 @@
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
-
EXPECT_EQ(44, SimpleInvoke(lib, "main"));
const char* kReloadScript =
@@ -286,7 +275,8 @@
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
- EXPECT_ERROR(lib, "Number of instance fields changed");
+ EXPECT_VALID(lib);
+ EXPECT_EQ(44, SimpleInvoke(lib, "main"));
}
@@ -298,7 +288,6 @@
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
-
EXPECT_STREQ("hello", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
@@ -312,7 +301,6 @@
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
-
EXPECT_STREQ("hello from A", SimpleInvokeStr(lib, "main"));
}
@@ -325,7 +313,6 @@
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
-
EXPECT_ERROR(SimpleInvokeError(lib, "main"), "max");;
const char* kReloadScript =
@@ -336,7 +323,6 @@
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
-
EXPECT_EQ(4, SimpleInvoke(lib, "main"));
}
@@ -350,7 +336,6 @@
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
-
EXPECT_EQ(4, SimpleInvoke(lib, "main"));
const char* kReloadScript =
@@ -420,7 +405,6 @@
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
-
EXPECT_STREQ("saved:20 new:20", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
@@ -435,7 +419,6 @@
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
-
EXPECT_STREQ("saved:20 new:10", SimpleInvokeStr(lib, "main"));
}
@@ -454,7 +437,6 @@
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
-
EXPECT_STREQ("saved:20 new:20", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
@@ -471,7 +453,6 @@
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
-
EXPECT_STREQ("saved:20 new:10", SimpleInvokeStr(lib, "main"));
}
@@ -489,7 +470,6 @@
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
-
EXPECT_STREQ("(true/false, true/true)", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
@@ -505,7 +485,6 @@
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
-
EXPECT_STREQ("(true/true, false/true)", SimpleInvokeStr(lib, "main"));
}
@@ -525,7 +504,6 @@
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
-
EXPECT_STREQ("Instance of 'B<A>'", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
@@ -539,11 +517,108 @@
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
-
EXPECT_STREQ("Instance of 'B<A>'", SimpleInvokeStr(lib, "main"));
}
+TEST_CASE(IsolateReload_TypeIdentity) {
+ const char* kScript =
+ "import 'test:isolate_reload_helper';\n"
+ "class T { }\n"
+ "getType() => T;\n"
+ "main() {\n"
+ " var oldType = getType();\n"
+ " reloadTest();\n"
+ " var newType = getType();\n"
+ " return identical(oldType, newType).toString();\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ const char* kReloadScript =
+ "import 'test:isolate_reload_helper';\n"
+ "class T extends Stopwatch { }\n"
+ "getType() => T;\n"
+ "main() {\n"
+ " var oldType = getType();\n"
+ " reloadTest();\n"
+ " var newType = getType();\n"
+ " return identical(oldType, newType).toString();\n"
+ "}\n";
+
+ TestCase::SetReloadTestScript(kReloadScript);
+
+ EXPECT_STREQ("true", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_TypeIdentityGeneric) {
+ const char* kScript =
+ "import 'test:isolate_reload_helper';\n"
+ "class T<G> { }\n"
+ "getType() => new T<int>().runtimeType;\n"
+ "main() {\n"
+ " var oldType = getType();\n"
+ " reloadTest();\n"
+ " var newType = getType();\n"
+ " return identical(oldType, newType).toString();\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ const char* kReloadScript =
+ "import 'test:isolate_reload_helper';\n"
+ "class T<G> extends Stopwatch { }\n"
+ "getType() => new T<int>().runtimeType;\n"
+ "main() {\n"
+ " var oldType = getType();\n"
+ " reloadTest();\n"
+ " var newType = getType();\n"
+ " return identical(oldType, newType).toString();\n"
+ "}\n";
+
+ TestCase::SetReloadTestScript(kReloadScript);
+
+ EXPECT_STREQ("true", SimpleInvokeStr(lib, "main"));
+}
+
+
+TEST_CASE(IsolateReload_TypeIdentityParameter) {
+ const char* kScript =
+ "import 'dart:mirrors';\n"
+ "import 'test:isolate_reload_helper';\n"
+ "class T<G> { }\n"
+ "getTypeVar() => reflectType(T).typeVariables[0];\n"
+ "main() {\n"
+ " var oldType = getTypeVar();\n"
+ " reloadTest();\n"
+ " var newType = getTypeVar();\n"
+ " return (oldType == newType).toString();\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ const char* kReloadScript =
+ "import 'dart:mirrors';\n"
+ "import 'test:isolate_reload_helper';\n"
+ "class T<G> extends Stopwatch { }\n"
+ "getTypeVar() => reflectType(T).typeVariables[0];\n"
+ "main() {\n"
+ " var oldType = getTypeVar();\n"
+ " reloadTest();\n"
+ " var newType = getTypeVar();\n"
+ " return (oldType == newType).toString();\n"
+ "}\n";
+
+ TestCase::SetReloadTestScript(kReloadScript);
+
+ EXPECT_STREQ("true", SimpleInvokeStr(lib, "main"));
+}
+
+
TEST_CASE(IsolateReload_MixinChanged) {
const char* kScript =
"class Mixin1 {\n"
@@ -559,7 +634,6 @@
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
-
EXPECT_STREQ("saved:field=mixin1,func=mixin1",
SimpleInvokeStr(lib, "main"));
@@ -609,7 +683,6 @@
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
-
EXPECT_STREQ("(a is A(true)/ B(false)/ C(false),"
" b is A(true)/ B(true)/ C(false),"
" c is A(true)/ B(true)/ C(true))",
@@ -636,7 +709,6 @@
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
-
EXPECT_STREQ("(a is A(true)/ C(true)/ X(true),"
" b is A(true)/ C(true)/ X(true)," // still extends A...
" c is A(false)/ C(true)/ X(false),"
@@ -669,7 +741,6 @@
lib = TestCase::ReloadTestScript(kReloadScript2);
EXPECT_VALID(lib);
-
EXPECT_STREQ("(a is A(true)/ B(false)/ C(false)/ X(true),"
" b is A(false)/ B(true)/ C(false)/ X(true),"
" c is A(true)/ B(false)/ C(true)/ X(true),"
@@ -708,7 +779,6 @@
lib = TestCase::GetReloadErrorOrRootLibrary();
EXPECT_VALID(lib);
-
EXPECT_EQ(105, SimpleInvoke(lib, "main"));
}
@@ -723,7 +793,6 @@
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
-
EXPECT_ERROR(SimpleInvokeError(lib, "main"), "importedFunc");
// Fail to find 'test:importable_lib' in the isolate.
@@ -739,7 +808,6 @@
// Reload and add 'test:importable_lib' to isolate.
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
-
EXPECT_STREQ("a", SimpleInvokeStr(lib, "main"));
// Find 'test:importable_lib' in the isolate.
@@ -769,7 +837,6 @@
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
-
EXPECT_ERROR(SimpleInvokeError(lib, "main"), "importedFunc");
// Import 'test:importable_lib'.
@@ -781,7 +848,6 @@
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
-
EXPECT_STREQ("a", SimpleInvokeStr(lib, "main"));
}
@@ -880,7 +946,6 @@
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
-
EXPECT_STREQ("mixin", SimpleInvokeStr(lib, "main"));
}
@@ -893,7 +958,6 @@
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
-
EXPECT_EQ(4, SimpleInvoke(lib, "main"));
const char* kReloadScript =
@@ -943,7 +1007,6 @@
lib = TestCase::GetReloadErrorOrRootLibrary();
EXPECT_VALID(lib);
-
EXPECT_EQ("instance", SimpleInvokeStr(lib, "main"));
}
@@ -984,7 +1047,6 @@
lib = TestCase::GetReloadErrorOrRootLibrary();
EXPECT_VALID(lib);
-
EXPECT_EQ("static", SimpleInvokeStr(lib, "main"));
}
@@ -1035,7 +1097,6 @@
lib = TestCase::GetReloadErrorOrRootLibrary();
EXPECT_VALID(lib);
-
EXPECT_EQ("okay", SimpleInvokeStr(lib, "main"));
}
@@ -1086,7 +1147,6 @@
lib = TestCase::GetReloadErrorOrRootLibrary();
EXPECT_VALID(lib);
-
EXPECT_EQ("exception", SimpleInvokeStr(lib, "main"));
}
@@ -1134,7 +1194,6 @@
lib = TestCase::GetReloadErrorOrRootLibrary();
EXPECT_VALID(lib);
-
EXPECT_EQ("exception", SimpleInvokeStr(lib, "main"));
}
@@ -1182,11 +1241,54 @@
lib = TestCase::GetReloadErrorOrRootLibrary();
EXPECT_VALID(lib);
-
EXPECT_EQ("static", SimpleInvokeStr(lib, "main"));
}
+TEST_CASE(IsolateReload_PendingSuperCall) {
+ const char* kScript =
+ "import 'test:isolate_reload_helper';\n"
+ "class S {\n"
+ " foo() => 1;\n"
+ "}\n"
+ "class C extends S {\n"
+ " foo() => 100;\n"
+ " test() {\n"
+ " var n = super.foo();\n"
+ " reloadTest();\n"
+ " return n + super.foo();\n"
+ " }\n"
+ "}\n"
+ "main() {\n"
+ " return new C().test();\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ const char* kReloadScript =
+ "import 'test:isolate_reload_helper';\n"
+ "class S {\n"
+ " foo() => 10;\n"
+ "}\n"
+ "class C extends S {\n"
+ " foo() => 100;\n"
+ " test() {\n"
+ " var n = super.foo();\n"
+ " reloadTest();\n"
+ " return n + super.foo();\n"
+ " }\n"
+ "}\n"
+ "main() {\n"
+ " return new C().test();\n"
+ "}\n";
+
+ TestCase::SetReloadTestScript(kReloadScript);
+
+ EXPECT_EQ(11, SimpleInvoke(lib, "main"));
+}
+
+
TEST_CASE(IsolateReload_EnumEquality) {
const char* kScript =
"enum Fruit {\n"
@@ -1220,7 +1322,6 @@
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
-
EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
}
@@ -1239,7 +1340,6 @@
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
-
EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
@@ -1258,7 +1358,6 @@
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
-
EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
}
@@ -1277,7 +1376,6 @@
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
-
EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
@@ -1296,7 +1394,6 @@
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
-
EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
}
@@ -1314,7 +1411,6 @@
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
-
EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
@@ -1333,7 +1429,6 @@
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
-
EXPECT_STREQ("0/Fruit.Apple 1/Fruit.Cantalope 2/Fruit.Banana",
SimpleInvokeStr(lib, "main"));
}
@@ -1350,7 +1445,6 @@
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
-
EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
@@ -1376,7 +1470,6 @@
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
-
EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
@@ -1401,129 +1494,31 @@
"}\n"
"var x;\n"
"main() {\n"
- " return Fruit.Apple.toString();\n"
- "}\n";
-
- Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
- EXPECT_VALID(lib);
-
- EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
-
- // Delete 'Cantalope'.
-
- const char* kReloadScript =
- "enum Fruit {\n"
- " Apple,\n"
- " Banana,\n"
- "}\n"
- "var x;\n"
- "main() {\n"
- " String r = '${Fruit.Apple.index}/${Fruit.Apple} ';\n"
- " r += '${Fruit.Banana.index}/${Fruit.Banana} ';\n"
- " r += '${Fruit.Cantalope.index}/${Fruit.Cantalope}';\n"
- " return r;\n"
- "}\n";
-
- lib = TestCase::ReloadTestScript(kReloadScript);
- EXPECT_VALID(lib);
-
- EXPECT_STREQ("0/Fruit.Apple 1/Fruit.Banana 2/Fruit.Cantalope",
- SimpleInvokeStr(lib, "main"));
-}
-
-
-TEST_CASE(IsolateReload_EnumComplex) {
- const char* kScript =
- "enum Fruit {\n"
- " Apple,\n"
- " Banana,\n"
- " Cantalope,\n"
- "}\n"
- "var x;\n"
- "var y;\n"
- "var z;\n"
- "main() {\n"
- " x = Fruit.Apple;\n"
- " y = Fruit.Banana;\n"
- " z = Fruit.Cantalope;\n"
- " return Fruit.Apple.toString();\n"
- "}\n";
-
- Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
- EXPECT_VALID(lib);
-
- EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
-
- // Delete 'Cantalope'. Add 'Dragon'. Move 'Apple' and 'Banana'.
-
- const char* kReloadScript =
- "enum Fruit {\n"
- " Dragon,\n"
- " Apple,\n"
- " Banana,\n"
- "}\n"
- "var x;\n"
- "var y;\n"
- "var z;\n"
- "main() {\n"
- " String r = '';\n"
- " r += '${identical(x, Fruit.Apple)}';\n"
- " r += ' ${identical(y, Fruit.Banana)}';\n"
- " r += ' ${identical(z, Fruit.Cantalope)}';\n"
- " r += ' ${Fruit.Dragon}';\n"
- " return r;\n"
- "}\n";
-
- lib = TestCase::ReloadTestScript(kReloadScript);
- EXPECT_VALID(lib);
-
- EXPECT_STREQ("true true true Fruit.Dragon", SimpleInvokeStr(lib, "main"));
-}
-
-
-TEST_CASE(IsolateReload_EnumValuesArray) {
- const char* kScript =
- "enum Fruit {\n"
- " Cantalope,\n"
- " Apple,\n"
- " Banana,\n"
- "}\n"
- "var x;\n"
- "main() {\n"
" x = Fruit.Cantalope;\n"
" return Fruit.Apple.toString();\n"
"}\n";
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
-
EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
- // Delete 'Cantalope'.
+ // Delete 'Cantalope' but make sure that we can still invoke toString,
+ // and access the hashCode and index properties.
const char* kReloadScript =
"enum Fruit {\n"
+ " Apple,\n"
" Banana,\n"
- " Apple\n"
"}\n"
"var x;\n"
- "bool identityCheck(Fruit f) {\n"
- " return identical(Fruit.values[f.index], f);\n"
- "}\n"
"main() {\n"
- " if ((x is Fruit) && identical(x, Fruit.Cantalope)) {\n"
- " String r = '${identityCheck(Fruit.Apple)}';\n"
- " r += ' ${identityCheck(Fruit.Banana)}';\n"
- " r += ' ${identityCheck(Fruit.Cantalope)}';\n"
- " r += ' ${identityCheck(x)}';\n"
- " return r;\n"
- " }\n"
+ " String r = '$x ${x.hashCode is int} ${x.index}';\n"
+ " return r;\n"
"}\n";
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
-
- EXPECT_STREQ("true true true true",
+ EXPECT_STREQ("Fruit.Cantalope true 2",
SimpleInvokeStr(lib, "main"));
}
@@ -1551,7 +1546,6 @@
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
-
EXPECT_STREQ("Fruit.Apple", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
@@ -1583,7 +1577,6 @@
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
-
EXPECT_STREQ("true true true true true true true true true ",
SimpleInvokeStr(lib, "main"));
}
@@ -1604,7 +1597,6 @@
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
-
EXPECT_STREQ("Pear", SimpleInvokeStr(lib, "main"));
const char* kReloadScript =
@@ -1624,7 +1616,6 @@
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
-
EXPECT_STREQ("yes", SimpleInvokeStr(lib, "main"));
}
@@ -1646,7 +1637,6 @@
Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
EXPECT_VALID(lib);
-
EXPECT_STREQ("Fruit.Apple Fruit.Banana", SimpleInvokeStr(lib, "main"));
// Insert 'Cantalope'.
@@ -1670,7 +1660,6 @@
lib = TestCase::ReloadTestScript(kReloadScript);
EXPECT_VALID(lib);
-
EXPECT_STREQ("Fruit.Apple Fruit.Cantalope Fruit.Banana",
SimpleInvokeStr(lib, "main"));
}
@@ -1859,6 +1848,278 @@
EXPECT_STREQ("AIterator", name.ToCString());
}
+
+// Tests reload succeeds when instance format changes.
+// Change: Foo {a, b, c:42} -> Foo {c:42}
+// Validate: c keeps the value in the retained Foo object.
+TEST_CASE(IsolateReload_ChangeInstanceFormat0) {
+ const char* kScript =
+ "class Foo {\n"
+ " var a;\n"
+ " var b;\n"
+ " var c;\n"
+ "}\n"
+ "var f;\n"
+ "main() {\n"
+ " f = new Foo();\n"
+ " f.c = 42;\n"
+ " return f.c;\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+ EXPECT_EQ(42, SimpleInvoke(lib, "main"));
+
+ const char* kReloadScript =
+ "class Foo {\n"
+ " var c;\n"
+ "}\n"
+ "var f;\n"
+ "main() {\n"
+ " return f.c;\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+ EXPECT_EQ(42, SimpleInvoke(lib, "main"));
+}
+
+
+// Tests reload succeeds when instance format changes.
+// Change: Foo {} -> Foo {c:null}
+// Validate: c is initialized to null the retained Foo object.
+TEST_CASE(IsolateReload_ChangeInstanceFormat1) {
+ const char* kScript =
+ "class Foo {\n"
+ "}\n"
+ "var f;\n"
+ "main() {\n"
+ " f = new Foo();\n"
+ " return 42;\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+ EXPECT_EQ(42, SimpleInvoke(lib, "main"));
+
+ const char* kReloadScript =
+ "class Foo {\n"
+ " var c;\n"
+ "}\n"
+ "var f;\n"
+ "main() {\n"
+ " return (f.c == null) ? 42: 21;\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+ EXPECT_EQ(42, SimpleInvoke(lib, "main"));
+}
+
+// Tests reload succeeds when instance format changes.
+// Change: Foo {c:42} -> Foo {}
+// Validate: running the after script fails.
+TEST_CASE(IsolateReload_ChangeInstanceFormat2) {
+ const char* kScript =
+ "class Foo {\n"
+ " var c;\n"
+ "}\n"
+ "var f;\n"
+ "main() {\n"
+ " f = new Foo();\n"
+ " f.c = 42;\n"
+ " return f.c;\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+ EXPECT_EQ(42, SimpleInvoke(lib, "main"));
+
+ const char* kReloadScript =
+ "class Foo {\n"
+ "}\n"
+ "var f;\n"
+ "main() {\n"
+ " try {\n"
+ " return f.c;\n"
+ " } catch (e) {\n"
+ " return 24;\n"
+ " }\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+ EXPECT_EQ(24, SimpleInvoke(lib, "main"));
+}
+
+
+// Tests reload succeeds when instance format changes.
+// Change: Foo {a, b, c:42, d} -> Foo {c:42, g}
+// Validate: c keeps the value in the retained Foo object.
+TEST_CASE(IsolateReload_ChangeInstanceFormat3) {
+ const char* kScript =
+ "class Foo<A,B> {\n"
+ " var a;\n"
+ " var b;\n"
+ " var c;\n"
+ " var d;\n"
+ "}\n"
+ "var f;\n"
+ "main() {\n"
+ " f = new Foo();\n"
+ " f.a = 1;\n"
+ " f.b = 2;\n"
+ " f.c = 3;\n"
+ " f.d = 4;\n"
+ " return f.c;\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+ EXPECT_EQ(3, SimpleInvoke(lib, "main"));
+
+ const char* kReloadScript =
+ "class Foo<A,B> {\n"
+ " var c;\n"
+ " var g;\n"
+ "}\n"
+ "var f;\n"
+ "main() {\n"
+ " return f.c;\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+ EXPECT_EQ(3, SimpleInvoke(lib, "main"));
+}
+
+
+// Tests reload succeeds when instance format changes.
+// Change: Bar {c:42}, Foo : Bar {d, e} -> Foo {c:42}
+// Validate: c keeps the value in the retained Foo object.
+TEST_CASE(IsolateReload_ChangeInstanceFormat4) {
+ const char* kScript =
+ "class Bar{\n"
+ " var c;\n"
+ "}\n"
+ "class Foo extends Bar{\n"
+ " var d;\n"
+ " var e;\n"
+ "}\n"
+ "var f;\n"
+ "main() {\n"
+ " f = new Foo();\n"
+ " f.c = 44;\n"
+ " return f.c;\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+ EXPECT_EQ(44, SimpleInvoke(lib, "main"));
+
+ const char* kReloadScript =
+ "class Foo {\n"
+ " var c;\n"
+ "}\n"
+ "var f;\n"
+ "main() {\n"
+ " return f.c;\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+ EXPECT_EQ(44, SimpleInvoke(lib, "main"));
+}
+
+
+// Tests reload succeeds when instance format changes.
+// Change: Bar {a, b}, Foo : Bar {c:42} -> Bar {c:42}, Foo : Bar {}
+// Validate: c keeps the value in the retained Foo object.
+TEST_CASE(IsolateReload_ChangeInstanceFormat5) {
+ const char* kScript =
+ "class Bar{\n"
+ " var a;\n"
+ " var b;\n"
+ "}\n"
+ "class Foo extends Bar{\n"
+ " var c;\n"
+ "}\n"
+ "var f;\n"
+ "main() {\n"
+ " f = new Foo();\n"
+ " f.c = 44;\n"
+ " return f.c;\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+ EXPECT_EQ(44, SimpleInvoke(lib, "main"));
+
+ const char* kReloadScript =
+ "class Bar{\n"
+ " var c;\n"
+ "}\n"
+ "class Foo extends Bar {\n"
+ "}\n"
+ "var f;\n"
+ "main() {\n"
+ " return f.c;\n"
+ "}\n";
+
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+ EXPECT_EQ(44, SimpleInvoke(lib, "main"));
+}
+
+
+// Tests reload fails when type parameters change.
+// Change: Foo<A,B> {a, b} -> Foo<A> {a}
+// Validate: the right error message is returned.
+TEST_CASE(IsolateReload_ChangeInstanceFormat6) {
+ const char* kScript =
+ "class Foo<A, B> {\n"
+ " var a;\n"
+ " var b;\n"
+ "}\n"
+ "main() {\n"
+ " new Foo();\n"
+ " return 43;\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+ EXPECT_EQ(43, SimpleInvoke(lib, "main"));
+
+ const char* kReloadScript =
+ "class Foo<A> {\n"
+ " var a;\n"
+ "}\n";
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_ERROR(lib, "type parameters have changed");
+}
+
+// Tests reload succeeds when type parameters are changed for allocated class.
+// Change: Foo<A,B> {a, b} -> Foo<A> {a}
+// Validate: return value from main is correct.
+// Please note: This test works because no instances are created from Foo.
+TEST_CASE(IsolateReload_ChangeInstanceFormat7) {
+ const char* kScript =
+ "class Foo<A, B> {\n"
+ " var a;\n"
+ " var b;\n"
+ "}\n";
+
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ const char* kReloadScript =
+ "class Foo<A> {\n"
+ " var a;\n"
+ "}\n";
+ lib = TestCase::ReloadTestScript(kReloadScript);
+ EXPECT_VALID(lib);
+}
+
#endif // !PRODUCT
} // namespace dart
diff --git a/runtime/vm/jit_optimizer.cc b/runtime/vm/jit_optimizer.cc
index e40cf12..56074a2 100644
--- a/runtime/vm/jit_optimizer.cc
+++ b/runtime/vm/jit_optimizer.cc
@@ -1680,7 +1680,7 @@
bool JitOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
ASSERT(call->HasICData());
const ICData& ic_data = *call->ic_data();
- if ((ic_data.NumberOfUsedChecks() == 0) || !ic_data.HasOneTarget()) {
+ if (ic_data.NumberOfUsedChecks() != 1) {
// No type feedback collected or multiple targets found.
return false;
}
@@ -1696,14 +1696,13 @@
(recognized_kind == MethodRecognizer::kExternalOneByteStringCodeUnitAt) ||
(recognized_kind == MethodRecognizer::kExternalTwoByteStringCodeUnitAt) ||
(recognized_kind == MethodRecognizer::kGrowableArraySetData) ||
- (recognized_kind == MethodRecognizer::kGrowableArraySetLength)) {
- ASSERT(ic_data.NumberOfChecks() == 1);
+ (recognized_kind == MethodRecognizer::kGrowableArraySetLength) ||
+ (recognized_kind == MethodRecognizer::kSmi_bitAndFromSmi)) {
return FlowGraphInliner::TryReplaceInstanceCallWithInline(
flow_graph_, current_iterator(), call);
}
- if ((recognized_kind == MethodRecognizer::kStringBaseCharAt) &&
- (ic_data.NumberOfChecks() == 1)) {
+ if (recognized_kind == MethodRecognizer::kStringBaseCharAt) {
ASSERT((class_ids[0] == kOneByteStringCid) ||
(class_ids[0] == kTwoByteStringCid) ||
(class_ids[0] == kExternalOneByteStringCid) ||
@@ -1712,7 +1711,7 @@
flow_graph_, current_iterator(), call);
}
- if ((class_ids[0] == kOneByteStringCid) && (ic_data.NumberOfChecks() == 1)) {
+ if (class_ids[0] == kOneByteStringCid) {
if (recognized_kind == MethodRecognizer::kOneByteStringSetAt) {
// This is an internal method, no need to check argument types nor
// range.
@@ -1735,8 +1734,7 @@
}
if (CanUnboxDouble() &&
- (recognized_kind == MethodRecognizer::kIntegerToDouble) &&
- (ic_data.NumberOfChecks() == 1)) {
+ (recognized_kind == MethodRecognizer::kIntegerToDouble)) {
if (class_ids[0] == kSmiCid) {
AddReceiverCheck(call);
ReplaceCall(call,
@@ -1805,36 +1803,23 @@
}
}
- if (IsSupportedByteArrayViewCid(class_ids[0]) &&
- (ic_data.NumberOfChecks() == 1)) {
+ if (IsSupportedByteArrayViewCid(class_ids[0])) {
return FlowGraphInliner::TryReplaceInstanceCallWithInline(
flow_graph_, current_iterator(), call);
}
- if ((class_ids[0] == kFloat32x4Cid) && (ic_data.NumberOfChecks() == 1)) {
+ if (class_ids[0] == kFloat32x4Cid) {
return TryInlineFloat32x4Method(call, recognized_kind);
}
- if ((class_ids[0] == kInt32x4Cid) && (ic_data.NumberOfChecks() == 1)) {
+ if (class_ids[0] == kInt32x4Cid) {
return TryInlineInt32x4Method(call, recognized_kind);
}
- if ((class_ids[0] == kFloat64x2Cid) && (ic_data.NumberOfChecks() == 1)) {
+ if (class_ids[0] == kFloat64x2Cid) {
return TryInlineFloat64x2Method(call, recognized_kind);
}
- if (recognized_kind == MethodRecognizer::kSmi_bitAndFromSmi) {
- AddReceiverCheck(call);
- BinarySmiOpInstr* op =
- new(Z) BinarySmiOpInstr(
- Token::kBIT_AND,
- new(Z) Value(call->ArgumentAt(0)),
- new(Z) Value(call->ArgumentAt(1)),
- call->deopt_id());
- ReplaceCall(call, op);
- return true;
- }
-
return false;
}
@@ -2347,6 +2332,12 @@
}
+// Tells whether the function of the call matches the core private name.
+static bool matches_core(InstanceCallInstr* call, const String& name) {
+ return call->function_name().raw() == Library::PrivateCoreLibName(name).raw();
+}
+
+
// TODO(srdjan): Use ICData to check if always true or false.
void JitOptimizer::ReplaceWithInstanceOf(InstanceCallInstr* call) {
ASSERT(Token::IsTypeTestOperator(call->token_kind()));
@@ -2356,26 +2347,27 @@
bool negate = false;
if (call->ArgumentCount() == 2) {
type_args = flow_graph()->constant_null();
- if (call->function_name().raw() ==
- Library::PrivateCoreLibName(Symbols::_instanceOfNum()).raw()) {
- type = Type::Number();
- } else if (call->function_name().raw() ==
- Library::PrivateCoreLibName(Symbols::_instanceOfInt()).raw()) {
- type = Type::IntType();
- } else if (call->function_name().raw() ==
- Library::PrivateCoreLibName(Symbols::_instanceOfSmi()).raw()) {
- type = Type::SmiType();
- } else if (call->function_name().raw() ==
- Library::PrivateCoreLibName(Symbols::_instanceOfDouble()).raw()) {
- type = Type::Double();
- } else if (call->function_name().raw() ==
- Library::PrivateCoreLibName(Symbols::_instanceOfString()).raw()) {
- type = Type::StringType();
+ if (matches_core(call, Symbols::_simpleInstanceOf())) {
+ type =
+ AbstractType::Cast(call->ArgumentAt(1)->AsConstant()->value()).raw();
+ negate = false; // Just to be sure.
} else {
- UNIMPLEMENTED();
+ if (matches_core(call, Symbols::_instanceOfNum())) {
+ type = Type::Number();
+ } else if (matches_core(call, Symbols::_instanceOfInt())) {
+ type = Type::IntType();
+ } else if (matches_core(call, Symbols::_instanceOfSmi())) {
+ type = Type::SmiType();
+ } else if (matches_core(call, Symbols::_instanceOfDouble())) {
+ type = Type::Double();
+ } else if (matches_core(call, Symbols::_instanceOfString())) {
+ type = Type::StringType();
+ } else {
+ UNIMPLEMENTED();
+ }
+ negate = Bool::Cast(call->ArgumentAt(1)->OriginalDefinition()
+ ->AsConstant()->value()).value();
}
- negate = Bool::Cast(call->ArgumentAt(1)->OriginalDefinition()
- ->AsConstant()->value()).value();
} else {
type_args = call->ArgumentAt(1);
type = AbstractType::Cast(call->ArgumentAt(2)->AsConstant()->value()).raw();
diff --git a/runtime/vm/message.cc b/runtime/vm/message.cc
index 035428d..0cb618a 100644
--- a/runtime/vm/message.cc
+++ b/runtime/vm/message.cc
@@ -181,6 +181,7 @@
void MessageQueue::PrintJSON(JSONStream* stream) {
+#ifndef PRODUCT
if (!FLAG_support_service) {
return;
}
@@ -221,6 +222,7 @@
}
}
}
+#endif // !PRODUCT
}
} // namespace dart
diff --git a/runtime/vm/method_recognizer.h b/runtime/vm/method_recognizer.h
index 083b477..08226f8 100644
--- a/runtime/vm/method_recognizer.h
+++ b/runtime/vm/method_recognizer.h
@@ -359,6 +359,7 @@
V(_ImmutableList, get:length, ImmutableArrayLength, 0x25943ad2) \
V(_TypedList, get:length, TypedDataLength, 0x2090dc1a) \
V(_GrowableList, get:length, GrowableArrayLength, 0x18dc9df6) \
+ V(_GrowableList, get:_capacity, GrowableArrayCapacity, 0x02734d82) \
V(_GrowableList, add, GrowableListAdd, 0x0d1358ed) \
V(_GrowableList, removeLast, GrowableListRemoveLast, 0x135d7384) \
V(_StringBase, get:length, StringBaseLength, 0x2a2c1b13) \
diff --git a/runtime/vm/metrics.cc b/runtime/vm/metrics.cc
index cb6c205..137042e 100644
--- a/runtime/vm/metrics.cc
+++ b/runtime/vm/metrics.cc
@@ -67,6 +67,7 @@
}
+#ifndef PRODUCT
static const char* UnitString(intptr_t unit) {
switch (unit) {
case Metric::kCounter: return "counter";
@@ -97,6 +98,7 @@
double value_as_double = static_cast<double>(Value());
obj.AddProperty("value", value_as_double);
}
+#endif // !PRODUCT
char* Metric::ValueToString(int64_t value, Unit unit) {
@@ -306,13 +308,13 @@
if (FLAG_print_metrics) {
// Create a zone to allocate temporary strings in.
StackZone sz(Thread::Current());
- OS::Print("Printing metrics for VM\n");
+ OS::PrintErr("Printing metrics for VM\n");
Metric* current = Metric::vm_head();
while (current != NULL) {
- OS::Print("%s\n", current->ToString());
+ OS::PrintErr("%s\n", current->ToString());
current = current->next();
}
- OS::Print("\n");
+ OS::PrintErr("\n");
}
}
diff --git a/runtime/vm/metrics.h b/runtime/vm/metrics.h
index 9fde2d8..c34f02d 100644
--- a/runtime/vm/metrics.h
+++ b/runtime/vm/metrics.h
@@ -56,7 +56,9 @@
virtual ~Metric();
+#ifndef PRODUCT
void PrintJSON(JSONStream* stream);
+#endif // !PRODUCT
// Returns a zone allocated string.
static char* ValueToString(int64_t value, Unit unit);
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 9b2e319..71cd044 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -1845,6 +1845,7 @@
Exceptions::Throw(thread, exception);
UNREACHABLE();
}
+#ifndef PRODUCT
ClassTable* class_table = isolate->class_table();
if (space == Heap::kNew) {
class_table->UpdateAllocatedNew(cls_id, size);
@@ -1855,6 +1856,7 @@
if (FLAG_profiler && cls.TraceAllocation(isolate)) {
Profiler::SampleAllocation(thread, cls_id);
}
+#endif // !PRODUCT
NoSafepointScope no_safepoint;
InitializeObject(address, cls_id, size, (isolate == Dart::vm_isolate()));
RawObject* raw_obj = reinterpret_cast<RawObject*>(address + kHeapObjectTag);
@@ -2074,7 +2076,7 @@
fields = cls.fields();
for (intptr_t i = 0; i < fields.Length(); ++i) {
f ^= fields.At(i);
- if (!f.is_static()) {
+ if (f.is_instance()) {
array.SetAt(f.Offset() >> kWordSizeLog2, f);
}
}
@@ -2808,12 +2810,17 @@
bool Class::TraceAllocation(Isolate* isolate) const {
+#ifndef PRODUCT
ClassTable* class_table = isolate->class_table();
return class_table->TraceAllocationFor(id());
+#else
+ return false;
+#endif
}
void Class::SetTraceAllocation(bool trace_allocation) const {
+#ifndef PRODUCT
Isolate* isolate = Isolate::Current();
const bool changed = trace_allocation != this->TraceAllocation(isolate);
if (changed) {
@@ -2821,6 +2828,9 @@
class_table->SetTraceAllocationFor(id(), trace_allocation);
DisableAllocationStub();
}
+#else
+ UNREACHABLE();
+#endif
}
@@ -4189,7 +4199,8 @@
}
-RawField* Class::LookupFieldAllowPrivate(const String& name) const {
+RawField* Class::LookupFieldAllowPrivate(const String& name,
+ bool instance_only) const {
// Use slow string compare, ignoring privacy name mangling.
Thread* thread = Thread::Current();
if (EnsureIsFinalized(thread) != Error::null()) {
@@ -4207,6 +4218,10 @@
for (intptr_t i = 0; i < len; i++) {
field ^= flds.At(i);
field_name ^= field.name();
+ if (field.is_static() && instance_only) {
+ // If we only care about instance fields, skip statics.
+ continue;
+ }
if (String::EqualsIgnoringPrivateKey(field_name, name)) {
return field.raw();
}
@@ -4216,7 +4231,7 @@
RawField* Class::LookupInstanceFieldAllowPrivate(const String& name) const {
- Field& field = Field::Handle(LookupFieldAllowPrivate(name));
+ Field& field = Field::Handle(LookupFieldAllowPrivate(name, true));
if (!field.IsNull() && !field.is_static()) {
return field.raw();
}
@@ -5272,7 +5287,6 @@
void Function::ClearCode() const {
ASSERT(Thread::Current()->IsMutatorThread());
- ASSERT((usage_counter() != 0) || (ic_data_array() == Array::null()));
StorePointer(&raw_ptr()->unoptimized_code_, Code::null());
SetInstructions(Code::Handle(StubCode::LazyCompile_entry()->code()));
}
@@ -8687,6 +8701,11 @@
}
+void Script::set_compile_time_constants(const Array& value) const {
+ StorePointer(&raw_ptr()->compile_time_constants_, value.raw());
+}
+
+
RawGrowableObjectArray* Script::GenerateLineNumberArray() const {
Zone* zone = Thread::Current()->zone();
const GrowableObjectArray& info =
@@ -10304,18 +10323,10 @@
}
-void Library::InitResolvedNamesCache(intptr_t size,
- SnapshotReader* reader) const {
+void Library::InitResolvedNamesCache(intptr_t size) const {
ASSERT(Thread::Current()->IsMutatorThread());
- if (reader == NULL) {
- StorePointer(&raw_ptr()->resolved_names_,
- HashTables::New<ResolvedNamesMap>(size));
- } else {
- intptr_t len = ResolvedNamesMap::ArrayLengthForNumOccupied(size);
- *reader->ArrayHandle() ^= reader->NewArray(len);
- StorePointer(&raw_ptr()->resolved_names_,
- HashTables::New<ResolvedNamesMap>(*reader->ArrayHandle()));
- }
+ StorePointer(&raw_ptr()->resolved_names_,
+ HashTables::New<ResolvedNamesMap>(size));
}
@@ -12469,7 +12480,10 @@
RawFunction* ICData::Owner() const {
Object& obj = Object::Handle(raw_ptr()->owner_);
- if (obj.IsFunction()) {
+ if (obj.IsNull()) {
+ ASSERT(Dart::snapshot_kind() == Snapshot::kAppNoJIT);
+ return Function::null();
+ } else if (obj.IsFunction()) {
return Function::Cast(obj).raw();
} else {
ICData& original = ICData::Handle();
@@ -12834,10 +12848,20 @@
}
+bool ICData::ValidateInterceptor(const Function& target) const {
+ ObjectStore* store = Isolate::Current()->object_store();
+ ASSERT((target.raw() == store->simple_instance_of_true_function()) ||
+ (target.raw() == store->simple_instance_of_false_function()));
+ const String& instance_of_name = String::Handle(
+ Library::PrivateCoreLibName(Symbols::_simpleInstanceOf()).raw());
+ ASSERT(target_name() == instance_of_name.raw());
+ return true;
+}
+
void ICData::AddCheck(const GrowableArray<intptr_t>& class_ids,
const Function& target) const {
ASSERT(!target.IsNull());
- ASSERT(target.name() == target_name());
+ ASSERT((target.name() == target_name()) || ValidateInterceptor(target));
DEBUG_ASSERT(!HasCheck(class_ids));
ASSERT(NumArgsTested() > 1); // Otherwise use 'AddReceiverCheck'.
ASSERT(class_ids.length() == NumArgsTested());
@@ -13520,95 +13544,6 @@
}
-static Token::Kind RecognizeArithmeticOp(const String& name) {
- ASSERT(name.IsSymbol());
- if (name.raw() == Symbols::Plus().raw()) {
- return Token::kADD;
- } else if (name.raw() == Symbols::Minus().raw()) {
- return Token::kSUB;
- } else if (name.raw() == Symbols::Star().raw()) {
- return Token::kMUL;
- } else if (name.raw() == Symbols::Slash().raw()) {
- return Token::kDIV;
- } else if (name.raw() == Symbols::TruncDivOperator().raw()) {
- return Token::kTRUNCDIV;
- } else if (name.raw() == Symbols::Percent().raw()) {
- return Token::kMOD;
- } else if (name.raw() == Symbols::BitOr().raw()) {
- return Token::kBIT_OR;
- } else if (name.raw() == Symbols::Ampersand().raw()) {
- return Token::kBIT_AND;
- } else if (name.raw() == Symbols::Caret().raw()) {
- return Token::kBIT_XOR;
- } else if (name.raw() == Symbols::LeftShiftOperator().raw()) {
- return Token::kSHL;
- } else if (name.raw() == Symbols::RightShiftOperator().raw()) {
- return Token::kSHR;
- } else if (name.raw() == Symbols::Tilde().raw()) {
- return Token::kBIT_NOT;
- } else if (name.raw() == Symbols::UnaryMinus().raw()) {
- return Token::kNEGATE;
- }
- return Token::kILLEGAL;
-}
-
-
-bool ICData::HasRangeFeedback() const {
- const String& target = String::Handle(target_name());
- const Token::Kind token_kind = RecognizeArithmeticOp(target);
- if (!Token::IsBinaryArithmeticOperator(token_kind) &&
- !Token::IsUnaryArithmeticOperator(token_kind)) {
- return false;
- }
-
- bool initialized = false;
- const intptr_t len = NumberOfChecks();
- GrowableArray<intptr_t> class_ids;
- for (intptr_t i = 0; i < len; i++) {
- if (IsUsedAt(i)) {
- initialized = true;
- GetClassIdsAt(i, &class_ids);
- for (intptr_t j = 0; j < class_ids.length(); j++) {
- const intptr_t cid = class_ids[j];
- if ((cid != kSmiCid) && (cid != kMintCid)) {
- return false;
- }
- }
- }
- }
-
- return initialized;
-}
-
-
-ICData::RangeFeedback ICData::DecodeRangeFeedbackAt(intptr_t idx) const {
- ASSERT((0 <= idx) && (idx < 3));
- const uint32_t raw_feedback =
- RangeFeedbackBits::decode(raw_ptr()->state_bits_);
- const uint32_t feedback =
- (raw_feedback >> (idx * kBitsPerRangeFeedback)) & kRangeFeedbackMask;
- if ((feedback & kInt64RangeBit) != 0) {
- return kInt64Range;
- }
-
- if ((feedback & kUint32RangeBit) != 0) {
- if ((feedback & kSignedRangeBit) == 0) {
- return kUint32Range;
- }
-
- // Check if Smi is large enough to accomodate Int33: a mixture of Uint32
- // and negative Int32 values.
- return (kSmiBits < 33) ? kInt64Range : kSmiRange;
- }
-
- if ((feedback & kInt32RangeBit) != 0) {
- return kInt32Range;
- }
-
- return kSmiRange;
-}
-
-
Code::Comments& Code::Comments::New(intptr_t count) {
Comments* comments;
if (count < 0 || count > (kIntptrMax / kNumberOfEntries)) {
@@ -13844,6 +13779,7 @@
void Code::Disassemble(DisassemblyFormatter* formatter) const {
+#ifndef PRODUCT
if (!FLAG_support_disassembler) {
return;
}
@@ -13854,6 +13790,7 @@
} else {
Disassembler::Disassemble(start, start + instr.size(), formatter, *this);
}
+#endif
}
@@ -15365,6 +15302,19 @@
}
+#if defined(DEBUG)
+bool Instance::CheckIsCanonical(Thread* thread) const {
+ Zone* zone = thread->zone();
+ Isolate* isolate = thread->isolate();
+ Instance& result = Instance::Handle(zone);
+ const Class& cls = Class::Handle(zone, this->clazz());
+ SafepointMutexLocker ml(isolate->constant_canonicalization_mutex());
+ result ^= cls.LookupCanonicalInstance(zone, *this);
+ return (result.raw() == this->raw());
+}
+#endif // DEBUG
+
+
RawAbstractType* Instance::GetType() const {
if (IsNull()) {
return Type::NullType();
@@ -16813,7 +16763,8 @@
}
} else if (!type_args.IsSubvectorEquivalent(other_type_args,
from_index,
- num_type_params)) {
+ num_type_params,
+ trail)) {
return false;
}
#ifdef DEBUG
@@ -17172,6 +17123,38 @@
}
+#if defined(DEBUG)
+bool Type::CheckIsCanonical(Thread* thread) const {
+ if (IsMalformed()) {
+ return true;
+ }
+ if (type_class() == Object::dynamic_class()) {
+ return (raw() == Object::dynamic_type().raw());
+ }
+ Zone* zone = thread->zone();
+ Isolate* isolate = thread->isolate();
+ AbstractType& type = Type::Handle(zone);
+ const Class& cls = Class::Handle(zone, type_class());
+
+ // Fast canonical lookup/registry for simple types.
+ if (!cls.IsGeneric() && !cls.IsClosureClass() && !cls.IsTypedefClass()) {
+ ASSERT(!IsFunctionType());
+ type = cls.CanonicalType();
+ return (raw() == type.raw());
+ }
+
+ ObjectStore* object_store = isolate->object_store();
+ {
+ SafepointMutexLocker ml(isolate->type_canonicalization_mutex());
+ CanonicalTypeSet table(zone, object_store->canonical_types());
+ type ^= table.GetOrNull(CanonicalTypeKey(*this));
+ object_store->set_canonical_types(table.Release());
+ }
+ return (raw() == type.raw());
+}
+#endif // DEBUG
+
+
RawString* Type::EnumerateURIs() const {
if (IsDynamicType() || IsVoidType()) {
return Symbols::Empty().raw();
@@ -17434,6 +17417,14 @@
}
+#if defined(DEBUG)
+bool TypeRef::CheckIsCanonical(Thread* thread) const {
+ AbstractType& ref_type = AbstractType::Handle(type());
+ return ref_type.CheckIsCanonical(thread);
+}
+#endif // DEBUG
+
+
RawString* TypeRef::EnumerateURIs() const {
Thread* thread = Thread::Current();
Zone* zone = thread->zone();
@@ -18097,11 +18088,11 @@
case kDoubleCid:
return Double::NewCanonical(Double::Cast(*this).value());
case kBigintCid: {
+ if (this->IsCanonical()) {
+ return this->raw();
+ }
Zone* zone = thread->zone();
Isolate* isolate = thread->isolate();
- if (!CheckAndCanonicalizeFields(thread, error_str)) {
- return Instance::null();
- }
Bigint& result = Bigint::Handle(zone);
const Class& cls = Class::Handle(zone, this->clazz());
intptr_t index = 0;
@@ -18141,6 +18132,38 @@
}
+#if defined(DEBUG)
+bool Number::CheckIsCanonical(Thread* thread) const {
+ intptr_t cid = GetClassId();
+ intptr_t idx = 0;
+ Zone* zone = thread->zone();
+ const Class& cls = Class::Handle(zone, this->clazz());
+ switch (cid) {
+ case kSmiCid:
+ return true;
+ case kMintCid: {
+ Mint& result = Mint::Handle(zone);
+ result ^= cls.LookupCanonicalMint(zone, Mint::Cast(*this).value(), &idx);
+ return (result.raw() == this->raw());
+ }
+ case kDoubleCid: {
+ Double& dbl = Double::Handle(zone);
+ dbl ^= cls.LookupCanonicalDouble(zone, Double::Cast(*this).value(), &idx);
+ return (dbl.raw() == this->raw());
+ }
+ case kBigintCid: {
+ Bigint& result = Bigint::Handle(zone);
+ result ^= cls.LookupCanonicalBigint(zone, Bigint::Cast(*this), &idx);
+ return (result.raw() == this->raw());
+ }
+ default:
+ UNREACHABLE();
+ }
+ return false;
+}
+#endif // DEBUG
+
+
const char* Number::ToCString() const {
// Number is an interface. No instances of Number should exist.
UNREACHABLE();
@@ -19841,6 +19864,15 @@
}
+#if defined(DEBUG)
+bool String::CheckIsCanonical(Thread* thread) const {
+ Zone* zone = thread->zone();
+ const String& str = String::Handle(zone, Symbols::Lookup(thread, *this));
+ return (str.raw() == this->raw());
+}
+#endif // DEBUG
+
+
RawString* String::New(const char* cstr, Heap::Space space) {
ASSERT(cstr != NULL);
intptr_t array_len = strlen(cstr);
@@ -21361,6 +21393,7 @@
void Array::MakeImmutable() const {
if (IsImmutable()) return;
+ ASSERT(!IsCanonical());
NoSafepointScope no_safepoint;
uword tags = raw_ptr()->tags_;
uword old_tags;
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 143cf9e..82f01cb 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -1157,13 +1157,14 @@
bool IsPrivate() const;
+ // Returns an array of instance and static fields defined by this class.
RawArray* fields() const { return raw_ptr()->fields_; }
void SetFields(const Array& value) const;
void AddField(const Field& field) const;
void AddFields(const GrowableArray<const Field*>& fields) const;
- // Returns an array of all fields of this class and its superclasses indexed
- // by offset in words.
+ // Returns an array of all instance fields of this class and its superclasses
+ // indexed by offset in words.
RawArray* OffsetToFieldMap() const;
// Returns true if non-static fields are defined.
@@ -1194,7 +1195,8 @@
RawField* LookupInstanceField(const String& name) const;
RawField* LookupStaticField(const String& name) const;
RawField* LookupField(const String& name) const;
- RawField* LookupFieldAllowPrivate(const String& name) const;
+ RawField* LookupFieldAllowPrivate(const String& name,
+ bool instance_only = false) const;
RawField* LookupInstanceFieldAllowPrivate(const String& name) const;
RawField* LookupStaticFieldAllowPrivate(const String& name) const;
@@ -1326,6 +1328,7 @@
void DisableAllocationStub() const;
RawArray* constants() const;
+ void set_constants(const Array& value) const;
intptr_t FindInvocationDispatcherFunctionIndex(const Function& needle) const;
RawFunction* InvocationDispatcherFunctionFromIndex(intptr_t idx) const;
@@ -1400,9 +1403,18 @@
void PatchFieldsAndFunctions() const;
void CopyCanonicalConstants(const Class& old_cls) const;
void CopyCanonicalType(const Class& old_cls) const;
- bool CanReload(const Class& replacement) const;
+ void CheckReload(const Class& replacement,
+ IsolateReloadContext* context) const;
private:
+ bool CanReloadFinalized(const Class& replacement,
+ IsolateReloadContext* context) const;
+ bool CanReloadPreFinalized(const Class& replacement,
+ IsolateReloadContext* context) const;
+
+ // Tells whether instances need morphing for reload.
+ bool RequiresInstanceMorphing(const Class& replacement) const;
+
template <class FakeObject> static RawClass* NewCommon(intptr_t index);
enum MemberKind {
@@ -1459,8 +1471,6 @@
RawString* GenerateUserVisibleName() const;
void set_state_bits(intptr_t bits) const;
- void set_constants(const Array& value) const;
-
void set_canonical_type(const Type& value) const;
RawType* canonical_type() const;
@@ -1861,7 +1871,6 @@
V(CheckClass) \
V(CheckArrayBound) \
V(AtCall) \
- V(Uint32Load) \
V(GuardField) \
V(TestCids) \
V(NumReasons) \
@@ -2055,78 +2064,6 @@
void GetUsedCidsForTwoArgs(GrowableArray<intptr_t>* first,
GrowableArray<intptr_t>* second) const;
- // Range feedback tracking functionality.
-
- // For arithmetic operations we store range information for inputs and the
- // result. The goal is to discover:
- //
- // - on 32-bit platforms:
- // - when Mint operation is actually a int32/uint32 operation;
- // - when Smi operation produces non-smi results;
- //
- // - on 64-bit platforms:
- // - when Smi operation is actually int32/uint32 operation;
- // - when Mint operation produces non-smi results;
- //
- enum RangeFeedback {
- kSmiRange,
- kInt32Range,
- kUint32Range,
- kInt64Range
- };
-
- // We use 4 bits per operand/result feedback. Our lattice allows us to
- // express the following states:
- //
- // - usmi 0000 [used only on 32bit platforms]
- // - smi 0001
- // - uint31 0010
- // - int32 0011
- // - uint32 0100
- // - int33 x1x1
- // - int64 1xxx
- //
- // DecodeRangeFeedbackAt() helper maps these states into the RangeFeedback
- // enumeration.
- enum RangeFeedbackLatticeBits {
- kSignedRangeBit = 1 << 0,
- kInt32RangeBit = 1 << 1,
- kUint32RangeBit = 1 << 2,
- kInt64RangeBit = 1 << 3,
- kBitsPerRangeFeedback = 4,
- kRangeFeedbackMask = (1 << kBitsPerRangeFeedback) - 1,
- kRangeFeedbackSlots = 3
- };
-
- static bool IsValidRangeFeedbackIndex(intptr_t index) {
- return (0 <= index) && (index < kRangeFeedbackSlots);
- }
-
- static intptr_t RangeFeedbackShift(intptr_t index) {
- return (index * kBitsPerRangeFeedback) + kRangeFeedbackPos;
- }
-
- static const char* RangeFeedbackToString(RangeFeedback feedback) {
- switch (feedback) {
- case kSmiRange:
- return "smi";
- case kInt32Range:
- return "int32";
- case kUint32Range:
- return "uint32";
- case kInt64Range:
- return "int64";
- default:
- UNREACHABLE();
- return "?";
- }
- }
-
- // It is only meaningful to interpret range feedback stored in the ICData
- // when all checks are Mint or Smi.
- bool HasRangeFeedback() const;
- RangeFeedback DecodeRangeFeedbackAt(intptr_t idx) const;
-
void PrintToJSONArray(const JSONArray& jsarray,
TokenPosition token_pos,
bool is_static_call) const;
@@ -2164,14 +2101,14 @@
void set_ic_data_array(const Array& value) const;
void set_state_bits(uint32_t bits) const;
+ bool ValidateInterceptor(const Function& target) const;
+
enum {
kNumArgsTestedPos = 0,
kNumArgsTestedSize = 2,
kDeoptReasonPos = kNumArgsTestedPos + kNumArgsTestedSize,
kDeoptReasonSize = kLastRecordedDeoptReason + 1,
- kRangeFeedbackPos = kDeoptReasonPos + kDeoptReasonSize,
- kRangeFeedbackSize = kBitsPerRangeFeedback * kRangeFeedbackSlots,
- kStaticCallPos = kRangeFeedbackPos + kRangeFeedbackSize,
+ kStaticCallPos = kDeoptReasonPos + kDeoptReasonSize,
kStaticCallSize = 1,
};
@@ -2183,11 +2120,6 @@
uint32_t,
ICData::kDeoptReasonPos,
ICData::kDeoptReasonSize> {};
- class RangeFeedbackBits : public BitField<uint32_t,
- uint32_t,
- ICData::kRangeFeedbackPos,
- ICData::kRangeFeedbackSize> {};
-
class StaticCallBit : public BitField<uint32_t,
bool,
ICData::kStaticCallPos,
@@ -2814,8 +2746,8 @@
void set_modifier(RawFunction::AsyncModifier value) const;
// 'was_compiled' is true if the function was compiled once in this
- // VM instantiation. It independent from presence of type feedback
- // (ic_data_array) and code, whihc may be loaded from a snapshot.
+ // VM instantiation. It is independent from presence of type feedback
+ // (ic_data_array) and code, which may be loaded from a snapshot.
void set_was_compiled(bool value) const {
StoreNonPointer(&raw_ptr()->was_compiled_, value ? 1 : 0);
}
@@ -3048,6 +2980,7 @@
virtual RawString* DictionaryName() const { return name(); }
bool is_static() const { return StaticBit::decode(raw_ptr()->kind_bits_); }
+ bool is_instance() const { return !is_static(); }
bool is_final() const { return FinalBit::decode(raw_ptr()->kind_bits_); }
bool is_const() const { return ConstBit::decode(raw_ptr()->kind_bits_); }
bool is_reflectable() const {
@@ -3477,6 +3410,11 @@
// The load time in milliseconds since epoch.
int64_t load_timestamp() const { return raw_ptr()->load_timestamp_; }
+ RawArray* compile_time_constants() const {
+ return raw_ptr()->compile_time_constants_;
+ }
+ void set_compile_time_constants(const Array& value) const;
+
RawTokenStream* tokens() const { return raw_ptr()->tokens_; }
void Tokenize(const String& private_key,
@@ -3524,6 +3462,7 @@
FINAL_HEAP_OBJECT_IMPLEMENTATION(Script, Object);
friend class Class;
+ friend class Precompiler;
};
@@ -3807,7 +3746,8 @@
// the library-specific key.
static const char kPrivateKeySeparator = '@';
- bool CanReload(const Library& replacement) const;
+ void CheckReload(const Library& replacement,
+ IsolateReloadContext* context) const;
private:
static const int kInitialImportsCapacity = 4;
@@ -3823,8 +3763,7 @@
void InitClassDictionary() const;
RawArray* resolved_names() const { return raw_ptr()->resolved_names_; }
- void InitResolvedNamesCache(intptr_t size,
- SnapshotReader* reader = NULL) const;
+ void InitResolvedNamesCache(intptr_t size) const;
void AllocateExportedNamesCache() const;
void InitExportedNamesCache() const;
static void InvalidateExportedNamesCaches();
@@ -5318,6 +5257,11 @@
virtual bool CheckAndCanonicalizeFields(Thread* thread,
const char** error_str) const;
+#if defined(DEBUG)
+ // Check if instance is canonical.
+ virtual bool CheckIsCanonical(Thread* thread) const;
+#endif // DEBUG
+
RawObject* GetField(const Field& field) const {
return *FieldAddr(field);
}
@@ -5398,7 +5342,6 @@
RawObject** NativeFieldsAddr() const {
return FieldAddrAtOffset(sizeof(RawObject));
}
-
void SetFieldAtOffset(intptr_t offset, const Object& value) const {
StorePointer(FieldAddrAtOffset(offset), value.raw());
}
@@ -5408,6 +5351,18 @@
return sizeof(RawInstance);
}
+ // The follwoing raw methods are used for morphing.
+ // They are needed due to the extraction of the class in IsValidFieldOffset.
+ RawObject** RawFieldAddrAtOffset(intptr_t offset) const {
+ return reinterpret_cast<RawObject**>(raw_value() - kHeapObjectTag + offset);
+ }
+ RawObject* RawGetFieldAtOffset(intptr_t offset) const {
+ return *RawFieldAddrAtOffset(offset);
+ }
+ void RawSetFieldAtOffset(intptr_t offset, const Object& value) const {
+ StorePointer(RawFieldAddrAtOffset(offset), value.raw());
+ }
+
// TODO(iposva): Determine if this gets in the way of Smi.
HEAP_OBJECT_IMPLEMENTATION(Instance, Object);
friend class ByteBuffer;
@@ -5421,6 +5376,7 @@
friend class InstanceSerializationCluster;
friend class InstanceDeserializationCluster;
friend class ClassDeserializationCluster; // vtable
+ friend class InstanceMorpher;
};
@@ -5552,6 +5508,14 @@
// Return the canonical version of this type.
virtual RawAbstractType* Canonicalize(TrailPtr trail = NULL) const;
+#if defined(DEBUG)
+ // Check if abstract type is canonical.
+ virtual bool CheckIsCanonical(Thread* thread) const {
+ UNREACHABLE();
+ return false;
+ }
+#endif // DEBUG
+
// Return the object associated with the receiver in the trail or
// AbstractType::null() if the receiver is not contained in the trail.
RawAbstractType* OnlyBuddyInTrail(TrailPtr trail) const;
@@ -5743,6 +5707,10 @@
const Class& new_owner,
TrailPtr trail = NULL) const;
virtual RawAbstractType* Canonicalize(TrailPtr trail = NULL) const;
+#if defined(DEBUG)
+ // Check if type is canonical.
+ virtual bool CheckIsCanonical(Thread* thread) const;
+#endif // DEBUG
virtual RawString* EnumerateURIs() const;
virtual intptr_t Hash() const;
@@ -5871,6 +5839,10 @@
const Class& new_owner,
TrailPtr trail = NULL) const;
virtual RawAbstractType* Canonicalize(TrailPtr trail = NULL) const;
+#if defined(DEBUG)
+ // Check if typeref is canonical.
+ virtual bool CheckIsCanonical(Thread* thread) const;
+#endif // DEBUG
virtual RawString* EnumerateURIs() const;
virtual intptr_t Hash() const;
@@ -5946,6 +5918,12 @@
virtual RawAbstractType* Canonicalize(TrailPtr trail = NULL) const {
return raw();
}
+#if defined(DEBUG)
+ // Check if type parameter is canonical.
+ virtual bool CheckIsCanonical(Thread* thread) const {
+ return true;
+ }
+#endif // DEBUG
virtual RawString* EnumerateURIs() const;
virtual intptr_t Hash() const;
@@ -6036,6 +6014,12 @@
virtual RawAbstractType* Canonicalize(TrailPtr trail = NULL) const {
return raw();
}
+#if defined(DEBUG)
+ // Check if bounded type is canonical.
+ virtual bool CheckIsCanonical(Thread* thread) const {
+ return true;
+ }
+#endif // DEBUG
virtual RawString* EnumerateURIs() const;
virtual intptr_t Hash() const;
@@ -6124,6 +6108,11 @@
virtual RawInstance* CheckAndCanonicalize(Thread* thread,
const char** error_str) const;
+#if defined(DEBUG)
+ // Check if number is canonical.
+ virtual bool CheckIsCanonical(Thread* thread) const;
+#endif // DEBUG
+
private:
OBJECT_IMPLEMENTATION(Number, Instance);
@@ -6600,6 +6589,11 @@
virtual RawInstance* CheckAndCanonicalize(Thread* thread,
const char** error_str) const;
+#if defined(DEBUG)
+ // Check if string is canonical.
+ virtual bool CheckIsCanonical(Thread* thread) const;
+#endif // DEBUG
+
bool IsSymbol() const { return raw()->IsCanonical(); }
bool IsOneByteString() const {
@@ -8531,9 +8525,7 @@
DART_FORCE_INLINE void Object::SetRaw(RawObject* value) {
- // NOTE: The assignment "raw_ = value" should be the first statement in
- // this function. Also do not use 'value' in this function after the
- // assignment (use 'raw_' instead).
+ NoSafepointScope no_safepoint_scope;
raw_ = value;
if ((reinterpret_cast<uword>(value) & kSmiTagMask) == kSmiTag) {
set_vtable(Smi::handle_vtable_);
@@ -8560,14 +8552,14 @@
intptr_t Field::Offset() const {
- ASSERT(!is_static()); // Valid only for dart instance fields.
+ ASSERT(is_instance()); // Valid only for dart instance fields.
intptr_t value = Smi::Value(raw_ptr()->value_.offset_);
return (value * kWordSize);
}
void Field::SetOffset(intptr_t offset_in_bytes) const {
- ASSERT(!is_static()); // Valid only for dart instance fields.
+ ASSERT(is_instance()); // Valid only for dart instance fields.
ASSERT(kWordSize != 0);
StorePointer(&raw_ptr()->value_.offset_,
Smi::New(offset_in_bytes / kWordSize));
diff --git a/runtime/vm/object_reload.cc b/runtime/vm/object_reload.cc
index f9c5ad9..577cb91 100644
--- a/runtime/vm/object_reload.cc
+++ b/runtime/vm/object_reload.cc
@@ -4,6 +4,7 @@
#include "vm/object.h"
+#include "vm/hash_table.h"
#include "vm/isolate_reload.h"
#include "vm/log.h"
#include "vm/resolver.h"
@@ -14,9 +15,9 @@
#ifndef PRODUCT
DECLARE_FLAG(bool, trace_reload);
+DECLARE_FLAG(bool, trace_reload_verbose);
DECLARE_FLAG(bool, two_args_smi_icd);
-#define IRC (Isolate::Current()->reload_context())
class ObjectReloadUtils : public AllStatic {
static void DumpLibraryDictionary(const Library& lib) {
@@ -141,6 +142,8 @@
void Class::CopyCanonicalConstants(const Class& old_cls) const {
if (is_enum_class()) {
+ // We do not copy enum classes's canonical constants because we explicitly
+ // become the old enum values to the new enum values.
return;
}
#if defined(DEBUG)
@@ -171,31 +174,47 @@
}
-static intptr_t IndexOfEnum(const Array& enum_names, const String& name) {
- ASSERT(!enum_names.IsNull());
- ASSERT(!name.IsNull());
- String& enum_name = String::Handle();
- for (intptr_t i = 0; i < enum_names.Length(); i++) {
- enum_name = String::RawCast(enum_names.At(i));
- ASSERT(!enum_name.IsNull());
- if (enum_name.Equals(name)) {
- return i;
- }
+class EnumMapTraits {
+ public:
+ static bool ReportStats() { return false; }
+ static const char* Name() { return "EnumMapTraits"; }
+
+ static bool IsMatch(const Object& a, const Object& b) {
+ return a.raw() == b.raw();
}
- return -1;
-}
+ static uword Hash(const Object& obj) {
+ ASSERT(obj.IsString());
+ return String::Cast(obj).Hash();
+ }
+};
-static void UpdateEnumIndex(const Instance& enum_value,
- const Field& enum_index_field,
- const intptr_t index) {
- enum_value.SetField(enum_index_field, Smi::Handle(Smi::New(index)));
-}
-
-
-// TODO(johnmccutchan): The code in the class finalizer canonicalizes all
-// instances and the values array. We probably should do the same thing.
+// Given an old enum class, add become mappings from old values to new values.
+// Some notes about how we reload enums below:
+//
+// When an enum is reloaded the following three things can happen, possibly
+// simultaneously.
+//
+// 1) A new enum value is added.
+// This case is handled automatically.
+// 2) Enum values are reordered.
+// We pair old and new enums and the old enums 'become' the new ones so
+// the ordering is always correct (i.e. enum indicies match slots in values
+// array)
+// 3) An existing enum value is removed.
+// We leave old enum values that have no mapping to the reloaded class
+// in the heap. This means that if a programmer does the following:
+// enum Foo { A, B }; var x = Foo.A;
+// *reload*
+// enum Foo { B };
+// *reload*
+// enum Foo { A, B }; expect(identical(x, Foo.A));
+// The program will fail because we were not able to pair Foo.A on the second
+// reload.
+//
+// Deleted enum values still in the heap continue to function but their
+// index field will not be valid.
void Class::ReplaceEnum(const Class& old_enum) const {
// We only do this for finalized enum classes.
ASSERT(is_enum_class());
@@ -204,160 +223,98 @@
ASSERT(old_enum.is_finalized());
Thread* thread = Thread::Current();
+ Zone* zone = thread->zone();
IsolateReloadContext* reload_context = Isolate::Current()->reload_context();
ASSERT(reload_context != NULL);
- TIR_Print("ReplaceEnum `%s` (%" Pd " and %" Pd ")\n",
- ToCString(), id(), old_enum.id());
+ Array& enum_fields = Array::Handle(zone);
+ Field& field = Field::Handle(zone);
+ String& enum_ident = String::Handle();
+ Instance& old_enum_value = Instance::Handle(zone);
+ Instance& enum_value = Instance::Handle(zone);
- // Grab '_enum_names' from |old_enum|.
- const Field& old_enum_names_field = Field::Handle(
- old_enum.LookupStaticFieldAllowPrivate(Symbols::_EnumNames()));
- ASSERT(!old_enum_names_field.IsNull());
- const Array& old_enum_names =
- Array::Handle(Array::RawCast(old_enum_names_field.StaticValue()));
- ASSERT(!old_enum_names.IsNull());
+ Array& enum_map_storage = Array::Handle(zone,
+ HashTables::New<UnorderedHashMap<EnumMapTraits> >(4));
+ ASSERT(!enum_map_storage.IsNull());
- // Grab 'values' from |old_enum|.
- const Field& old_enum_values_field = Field::Handle(
- old_enum.LookupStaticField(Symbols::Values()));
- ASSERT(!old_enum_values_field.IsNull());
- const Array& old_enum_values =
- Array::Handle(Array::RawCast(old_enum_values_field.StaticValue()));
- ASSERT(!old_enum_values.IsNull());
+ TIR_Print("Replacing enum `%s`\n", String::Handle(Name()).ToCString());
- // Grab _enum_names from |this|.
- const Field& enum_names_field = Field::Handle(
- LookupStaticFieldAllowPrivate(Symbols::_EnumNames()));
- ASSERT(!enum_names_field.IsNull());
- Array& enum_names =
- Array::Handle(Array::RawCast(enum_names_field.StaticValue()));
- ASSERT(!enum_names.IsNull());
-
- // Grab values from |this|.
- const Field& enum_values_field = Field::Handle(
- LookupStaticField(Symbols::Values()));
- ASSERT(!enum_values_field.IsNull());
- Array& enum_values =
- Array::Handle(Array::RawCast(enum_values_field.StaticValue()));
- ASSERT(!enum_values.IsNull());
-
- // Grab the |index| field.
- const Field& index_field =
- Field::Handle(old_enum.LookupInstanceField(Symbols::Index()));
- ASSERT(!index_field.IsNull());
-
- // Build list of enum from |old_enum| that aren't present in |this|.
- // This array holds pairs: (name, value).
- const GrowableObjectArray& to_add =
- GrowableObjectArray::Handle(GrowableObjectArray::New(Heap::kOld));
- const String& enum_class_name = String::Handle(UserVisibleName());
- String& enum_name = String::Handle();
- String& enum_field_name = String::Handle();
- Object& enum_value = Object::Handle();
- Field& enum_field = Field::Handle();
-
- TIR_Print("New version of enum has %" Pd " elements\n",
- enum_values.Length());
- TIR_Print("Old version of enum had %" Pd " elements\n",
- old_enum_values.Length());
-
- for (intptr_t i = 0; i < old_enum_names.Length(); i++) {
- enum_name = String::RawCast(old_enum_names.At(i));
- const intptr_t index_in_new_cls = IndexOfEnum(enum_names, enum_name);
- if (index_in_new_cls < 0) {
- // Doesn't exist in new enum, add.
- TIR_Print("Adding enum value `%s` to %s\n",
- enum_name.ToCString(),
- this->ToCString());
- enum_value = old_enum_values.At(i);
- ASSERT(!enum_value.IsNull());
- to_add.Add(enum_name);
- to_add.Add(enum_value);
- } else {
- // Exists in both the new and the old.
- TIR_Print("Moving enum value `%s` to %" Pd "\n",
- enum_name.ToCString(),
- index_in_new_cls);
- // Grab old value.
- enum_value = old_enum_values.At(i);
- // Update index to the be new index.
- UpdateEnumIndex(Instance::Cast(enum_value),
- index_field,
- index_in_new_cls);
- // Chop off the 'EnumClass.'
- enum_field_name = String::SubString(enum_name,
- enum_class_name.Length() + 1);
- ASSERT(!enum_field_name.IsNull());
- // Grab the static field.
- enum_field = LookupStaticField(enum_field_name);
- ASSERT(!enum_field.IsNull());
- // Use old value with updated index.
- enum_field.SetStaticValue(Instance::Cast(enum_value), true);
- enum_values.SetAt(index_in_new_cls, enum_value);
- enum_names.SetAt(index_in_new_cls, enum_name);
+ {
+ UnorderedHashMap<EnumMapTraits> enum_map(enum_map_storage.raw());
+ // Build a map of all enum name -> old enum instance.
+ enum_fields = old_enum.fields();
+ for (intptr_t i = 0; i < enum_fields.Length(); i++) {
+ field = Field::RawCast(enum_fields.At(i));
+ enum_ident = field.name();
+ if (!field.is_static()) {
+ // Enum instances are only held in static fields.
+ continue;
+ }
+ if (enum_ident.Equals(Symbols::Values())) {
+ // Non-enum instance.
+ continue;
+ }
+ old_enum_value = field.StaticValue();
+ ASSERT(!old_enum_value.IsNull());
+ VTIR_Print("Element %s being added to mapping\n", enum_ident.ToCString());
+ bool update = enum_map.UpdateOrInsert(enum_ident, old_enum_value);
+ VTIR_Print("Element %s added to mapping\n", enum_ident.ToCString());
+ ASSERT(!update);
}
+ // The storage given to the map may have been reallocated, remember the new
+ // address.
+ enum_map_storage = enum_map.Release().raw();
}
- if (to_add.Length() == 0) {
- // Nothing to do.
- TIR_Print("Found no missing enums in %s\n", ToCString());
- return;
+ bool enums_deleted = false;
+ {
+ UnorderedHashMap<EnumMapTraits> enum_map(enum_map_storage.raw());
+ // Add a become mapping from the old instances to the new instances.
+ enum_fields = fields();
+ for (intptr_t i = 0; i < enum_fields.Length(); i++) {
+ field = Field::RawCast(enum_fields.At(i));
+ enum_ident = field.name();
+ if (!field.is_static()) {
+ // Enum instances are only held in static fields.
+ continue;
+ }
+ if (enum_ident.Equals(Symbols::Values())) {
+ // Non-enum instance.
+ continue;
+ }
+ enum_value = field.StaticValue();
+ ASSERT(!enum_value.IsNull());
+ old_enum_value ^= enum_map.GetOrNull(enum_ident);
+ if (old_enum_value.IsNull()) {
+ VTIR_Print("New element %s was not found in mapping\n",
+ enum_ident.ToCString());
+ } else {
+ VTIR_Print("Adding element `%s` to become mapping\n",
+ enum_ident.ToCString());
+ bool removed = enum_map.Remove(enum_ident);
+ ASSERT(removed);
+ reload_context->AddEnumBecomeMapping(old_enum_value, enum_value);
+ }
+ }
+ enums_deleted = enum_map.NumOccupied() > 0;
+ // The storage given to the map may have been reallocated, remember the new
+ // address.
+ enum_map_storage = enum_map.Release().raw();
}
- // Grow the values and enum_names arrays.
- const intptr_t offset = enum_names.Length();
- const intptr_t num_to_add = to_add.Length() / 2;
- ASSERT(offset == enum_values.Length());
- enum_names = Array::Grow(enum_names,
- enum_names.Length() + num_to_add,
- Heap::kOld);
- enum_values = Array::Grow(enum_values,
- enum_values.Length() + num_to_add,
- Heap::kOld);
-
- // Install new names and values into the grown arrays. Also, update
- // the index of the new enum values and add static fields for the new
- // enum values.
- Field& enum_value_field = Field::Handle();
- for (intptr_t i = 0; i < num_to_add; i++) {
- const intptr_t target_index = offset + i;
- enum_name = String::RawCast(to_add.At(i * 2));
- enum_value = to_add.At(i * 2 + 1);
-
- // Update the enum value's index into the new arrays.
- TIR_Print("Updating index of %s in %s to %" Pd "\n",
- enum_name.ToCString(),
- ToCString(),
- target_index);
- UpdateEnumIndex(Instance::Cast(enum_value), index_field, target_index);
-
- enum_names.SetAt(target_index, enum_name);
- enum_values.SetAt(target_index, enum_value);
-
- // Install new static field into class.
- // Chop off the 'EnumClass.'
- enum_field_name = String::SubString(enum_name,
- enum_class_name.Length() + 1);
- ASSERT(!enum_field_name.IsNull());
- enum_field_name = Symbols::New(thread, enum_field_name);
- enum_value_field = Field::New(enum_field_name,
- /* is_static = */ true,
- /* is_final = */ true,
- /* is_const = */ true,
- /* is_reflectable = */ true,
- *this,
- Object::dynamic_type(),
- token_pos());
- enum_value_field.set_has_initializer(false);
- enum_value_field.SetStaticValue(Instance::Cast(enum_value), true);
- enum_value_field.RecordStore(Instance::Cast(enum_value));
- AddField(enum_value_field);
+ if (enums_deleted && FLAG_trace_reload_verbose) {
+ // TODO(johnmccutchan): Add this to the reload 'notices' list.
+ VTIR_Print("The following enum values were deleted and are forever lost in "
+ "the heap:\n");
+ UnorderedHashMap<EnumMapTraits> enum_map(enum_map_storage.raw());
+ UnorderedHashMap<EnumMapTraits>::Iterator it(&enum_map);
+ while (it.MoveNext()) {
+ const intptr_t entry = it.Current();
+ enum_ident = String::RawCast(enum_map.GetKey(entry));
+ ASSERT(!enum_ident.IsNull());
+ }
+ enum_map.Release();
}
-
- // Replace the arrays stored in the static fields.
- enum_names_field.SetStaticValue(enum_names, true);
- enum_values_field.SetStaticValue(enum_values, true);
}
@@ -406,133 +363,257 @@
}
-bool Class::CanReload(const Class& replacement) const {
+class EnumClassConflict : public ClassReasonForCancelling {
+ public:
+ EnumClassConflict(const Class& from, const Class& to)
+ : ClassReasonForCancelling(from, to) { }
+
+ RawString* ToString() {
+ return String::NewFormatted(
+ from_.is_enum_class()
+ ? "Enum class cannot be redefined to be a non-enum class: %s"
+ : "Class cannot be redefined to be a enum class: %s",
+ from_.ToCString());
+ }
+};
+
+
+class EnsureFinalizedError : public ClassReasonForCancelling {
+ public:
+ EnsureFinalizedError(const Class& from, const Class& to, const Error& error)
+ : ClassReasonForCancelling(from, to), error_(error) { }
+
+ private:
+ const Error& error_;
+
+ RawError* ToError() { return error_.raw(); }
+};
+
+
+class NativeFieldsConflict : public ClassReasonForCancelling {
+ public:
+ NativeFieldsConflict(const Class& from, const Class& to)
+ : ClassReasonForCancelling(from, to) { }
+
+ private:
+ RawString* ToString() {
+ return String::NewFormatted(
+ "Number of native fields changed in %s", from_.ToCString());
+ }
+};
+
+
+class TypeParametersChanged : public ClassReasonForCancelling {
+ public:
+ TypeParametersChanged(const Class& from, const Class& to)
+ : ClassReasonForCancelling(from, to) {}
+
+ RawString* ToString() {
+ return String::NewFormatted(
+ "Limitation: type parameters have changed for %s", from_.ToCString());
+ }
+};
+
+
+class PreFinalizedConflict : public ClassReasonForCancelling {
+ public:
+ PreFinalizedConflict(const Class& from, const Class& to)
+ : ClassReasonForCancelling(from, to) {}
+
+ private:
+ RawString* ToString() {
+ return String::NewFormatted(
+ "Original class ('%s') is prefinalized and replacement class "
+ "('%s') is not ",
+ from_.ToCString(), to_.ToCString());
+ }
+};
+
+
+class InstanceSizeConflict : public ClassReasonForCancelling {
+ public:
+ InstanceSizeConflict(const Class& from, const Class& to)
+ : ClassReasonForCancelling(from, to) {}
+
+ private:
+ RawString* ToString() {
+ return String::NewFormatted(
+ "Instance size mismatch between '%s' (%" Pd ") and replacement "
+ "'%s' ( %" Pd ")",
+ from_.ToCString(),
+ from_.instance_size(),
+ to_.ToCString(),
+ to_.instance_size());
+ }
+};
+
+
+class UnimplementedDeferredLibrary : public ReasonForCancelling {
+ public:
+ UnimplementedDeferredLibrary(const Library& from,
+ const Library& to,
+ const String& name)
+ : ReasonForCancelling(), from_(from), to_(to), name_(name) {}
+
+ private:
+ const Library& from_;
+ const Library& to_;
+ const String& name_;
+
+ RawString* ToString() {
+ const String& lib_url = String::Handle(to_.url());
+ from_.ToCString();
+ return String::NewFormatted(
+ "Reloading support for deferred loading has not yet been implemented:"
+ " library '%s' has deferred import '%s'",
+ lib_url.ToCString(), name_.ToCString());
+ }
+};
+
+
+// This is executed before interating over the instances.
+void Class::CheckReload(const Class& replacement,
+ IsolateReloadContext* context) const {
ASSERT(IsolateReloadContext::IsSameClass(*this, replacement));
- if (is_enum_class() && !replacement.is_enum_class()) {
- IRC->ReportError(String::Handle(String::NewFormatted(
- "Enum class cannot be redefined to be a non-enum class: %s",
- ToCString())));
- return false;
- }
-
- if (!is_enum_class() && replacement.is_enum_class()) {
- IRC->ReportError(String::Handle(String::NewFormatted(
- "Class cannot be redefined to be a enum class: %s",
- ToCString())));
- return false;
+ // Class cannot change enum property.
+ if (is_enum_class() != replacement.is_enum_class()) {
+ context->AddReasonForCancelling(
+ new EnumClassConflict(*this, replacement));
+ return;
}
if (is_finalized()) {
+ // Ensure the replacement class is also finalized.
const Error& error =
Error::Handle(replacement.EnsureIsFinalized(Thread::Current()));
if (!error.IsNull()) {
- IRC->ReportError(error);
- return false;
+ context->AddReasonForCancelling(
+ new EnsureFinalizedError(*this, replacement, error));
+ return; // No reason to check other properties.
}
TIR_Print("Finalized replacement class for %s\n", ToCString());
}
- // At this point the original and replacement must be in the same state.
- ASSERT(is_finalized() == replacement.is_finalized());
+ // Native field count cannot change.
+ if (num_native_fields() != replacement.num_native_fields()) {
+ context->AddReasonForCancelling(
+ new NativeFieldsConflict(*this, replacement));
+ return;
+ }
+
+ // Just checking.
+ ASSERT(is_enum_class() == replacement.is_enum_class());
+ ASSERT(num_native_fields() == replacement.num_native_fields());
if (is_finalized()) {
- // Get the field maps for both classes. These field maps walk the class
- // hierarchy.
- const Array& fields =
- Array::Handle(OffsetToFieldMap());
- const Array& replacement_fields =
- Array::Handle(replacement.OffsetToFieldMap());
-
- // Check that the size of the instance is the same.
- if (fields.Length() != replacement_fields.Length()) {
- IRC->ReportError(String::Handle(String::NewFormatted(
- "Number of instance fields changed in %s", ToCString())));
- return false;
- }
-
- // Check that we have the same next field offset. This check is not
- // redundant with the one above because the instance OffsetToFieldMap
- // array length is based on the instance size (which may be aligned up).
- if (next_field_offset() != replacement.next_field_offset()) {
- IRC->ReportError(String::Handle(String::NewFormatted(
- "Number of instance fields changed in %s", ToCString())));
- return false;
- }
-
- if (NumTypeArguments() != replacement.NumTypeArguments()) {
- IRC->ReportError(String::Handle(String::NewFormatted(
- "Number of type arguments changed in %s", ToCString())));
- return false;
- }
-
- // Verify that field names / offsets match across the entire hierarchy.
- Field& field = Field::Handle();
- String& field_name = String::Handle();
- Field& replacement_field = Field::Handle();
- String& replacement_field_name = String::Handle();
- for (intptr_t i = 0; i < fields.Length(); i++) {
- if (fields.At(i) == Field::null()) {
- ASSERT(replacement_fields.At(i) == Field::null());
- continue;
- }
- field = Field::RawCast(fields.At(i));
- replacement_field = Field::RawCast(replacement_fields.At(i));
- field_name = field.name();
- replacement_field_name = replacement_field.name();
- if (!field_name.Equals(replacement_field_name)) {
- IRC->ReportError(String::Handle(String::NewFormatted(
- "Name of instance field changed ('%s' vs '%s') in '%s'",
- field_name.ToCString(),
- replacement_field_name.ToCString(),
- ToCString())));
- return false;
- }
- }
- } else if (is_prefinalized()) {
- if (!replacement.is_prefinalized()) {
- IRC->ReportError(String::Handle(String::NewFormatted(
- "Original class ('%s') is prefinalized and replacement class "
- "('%s') is not ",
- ToCString(), replacement.ToCString())));
- return false;
- }
- if (instance_size() != replacement.instance_size()) {
- IRC->ReportError(String::Handle(String::NewFormatted(
- "Instance size mismatch between '%s' (%" Pd ") and replacement "
- "'%s' ( %" Pd ")",
- ToCString(),
- instance_size(),
- replacement.ToCString(),
- replacement.instance_size())));
- return false;
- }
+ if (!CanReloadFinalized(replacement, context)) return;
}
+ if (is_prefinalized()) {
+ if (!CanReloadPreFinalized(replacement, context)) return;
+ }
+ ASSERT(is_finalized() == replacement.is_finalized());
+ TIR_Print("Class `%s` can be reloaded (%" Pd " and %" Pd ")\n",
+ ToCString(), id(), replacement.id());
+}
- // native field count check.
- if (num_native_fields() != replacement.num_native_fields()) {
- IRC->ReportError(String::Handle(String::NewFormatted(
- "Number of native fields changed in %s", ToCString())));
+
+
+bool Class::RequiresInstanceMorphing(const Class& replacement) const {
+ // Get the field maps for both classes. These field maps walk the class
+ // hierarchy.
+ const Array& fields = Array::Handle(OffsetToFieldMap());
+ const Array& replacement_fields
+ = Array::Handle(replacement.OffsetToFieldMap());
+
+ // Check that the size of the instance is the same.
+ if (fields.Length() != replacement_fields.Length()) return true;
+
+ // Check that we have the same next field offset. This check is not
+ // redundant with the one above because the instance OffsetToFieldMap
+ // array length is based on the instance size (which may be aligned up).
+ if (next_field_offset() != replacement.next_field_offset()) return true;
+
+ // Verify that field names / offsets match across the entire hierarchy.
+ Field& field = Field::Handle();
+ String& field_name = String::Handle();
+ Field& replacement_field = Field::Handle();
+ String& replacement_field_name = String::Handle();
+
+ for (intptr_t i = 0; i < fields.Length(); i++) {
+ if (fields.At(i) == Field::null()) {
+ ASSERT(replacement_fields.At(i) == Field::null());
+ continue;
+ }
+ field = Field::RawCast(fields.At(i));
+ replacement_field = Field::RawCast(replacement_fields.At(i));
+ field_name = field.name();
+ replacement_field_name = replacement_field.name();
+ if (!field_name.Equals(replacement_field_name)) return true;
+ }
+ return false;
+}
+
+
+bool Class::CanReloadFinalized(const Class& replacement,
+ IsolateReloadContext* context) const {
+ // Make sure the declaration types matches for the two classes.
+ // ex. class A<int,B> {} cannot be replace with class A<B> {}.
+
+ const AbstractType& dt = AbstractType::Handle(DeclarationType());
+ const AbstractType& replacement_dt =
+ AbstractType::Handle(replacement.DeclarationType());
+ if (!dt.Equals(replacement_dt)) {
+ context->AddReasonForCancelling(
+ new TypeParametersChanged(*this, replacement));
return false;
}
-
- // TODO(johnmccutchan) type parameter count check.
-
- TIR_Print("Class `%s` can be reloaded (%" Pd " and %" Pd ")\n",
- ToCString(),
- id(),
- replacement.id());
+ if (RequiresInstanceMorphing(replacement)) {
+ context->AddInstanceMorpher(new InstanceMorpher(*this, replacement));
+ }
return true;
}
-bool Library::CanReload(const Library& replacement) const {
+bool Class::CanReloadPreFinalized(const Class& replacement,
+ IsolateReloadContext* context) const {
+ // The replacement class must also prefinalized.
+ if (!replacement.is_prefinalized()) {
+ context->AddReasonForCancelling(
+ new PreFinalizedConflict(*this, replacement));
+ return false;
+ }
+ // Check the instance sizes are equal.
+ if (instance_size() != replacement.instance_size()) {
+ context->AddReasonForCancelling(
+ new InstanceSizeConflict(*this, replacement));
+ return false;
+ }
return true;
}
+void Library::CheckReload(const Library& replacement,
+ IsolateReloadContext* context) const {
+ // TODO(26878): If the replacement library uses deferred loading,
+ // reject it. We do not yet support reloading deferred libraries.
+ LibraryPrefix& prefix = LibraryPrefix::Handle();
+ LibraryPrefixIterator it(replacement);
+ while (it.HasNext()) {
+ prefix = it.GetNext();
+ if (prefix.is_deferred_load()) {
+ const String& prefix_name = String::Handle(prefix.name());
+ context->AddReasonForCancelling(
+ new UnimplementedDeferredLibrary(*this, replacement, prefix_name));
+ return;
+ }
+ }
+}
+
+
static const Function* static_call_target = NULL;
+
void ICData::Reset() const {
if (is_static_call()) {
const Function& old_target = Function::Handle(GetTargetAt(0));
@@ -540,22 +621,62 @@
FATAL("old_target is NULL.\n");
}
static_call_target = &old_target;
- if (!old_target.is_static()) {
- // TODO(johnmccutchan): Improve this.
- TIR_Print("Cannot rebind super-call to %s from %s\n",
- old_target.ToCString(),
- Object::Handle(Owner()).ToCString());
- return;
- }
+
const String& selector = String::Handle(old_target.name());
- const Class& cls = Class::Handle(old_target.Owner());
- const Function& new_target =
- Function::Handle(cls.LookupStaticFunction(selector));
- if (new_target.IsNull()) {
- // TODO(johnmccutchan): Improve this.
- TIR_Print("Cannot rebind static call to %s from %s\n",
- old_target.ToCString(),
- Object::Handle(Owner()).ToCString());
+ Function& new_target = Function::Handle();
+ if (!old_target.is_static()) {
+ if (old_target.kind() == RawFunction::kConstructor) {
+ return; // Super constructor call.
+ }
+ Function& caller = Function::Handle();
+ caller ^= Owner();
+ ASSERT(!caller.is_static());
+ Class& cls = Class::Handle(caller.Owner());
+ if (cls.raw() == old_target.Owner()) {
+ // Dispatcher.
+ if (caller.IsImplicitClosureFunction()) {
+ return; // Tear-off.
+ }
+ if (caller.kind() == RawFunction::kNoSuchMethodDispatcher) {
+ // TODO(rmacnak): noSuchMethod might have been redefined.
+ return;
+ }
+ const Function& caller_parent =
+ Function::Handle(caller.parent_function());
+ if (!caller_parent.IsNull()) {
+ if (caller_parent.kind() == RawFunction::kInvokeFieldDispatcher) {
+ return; // Call-through-getter.
+ }
+ }
+ FATAL2("Unexpected dispatcher-like call site: %s from %s\n",
+ selector.ToCString(), caller.ToQualifiedCString());
+ }
+ // Super call.
+ cls = cls.SuperClass();
+ while (!cls.IsNull()) {
+ // TODO(rmacnak): Should use Resolver::ResolveDynamicAnyArgs to handle
+ // method-extractors and call-through-getters, but we're in a no
+ // safepoint scope here.
+ new_target = cls.LookupDynamicFunction(selector);
+ if (!new_target.IsNull()) {
+ break;
+ }
+ cls = cls.SuperClass();
+ }
+ } else {
+ // This can be incorrect if the call site was an unqualified invocation.
+ const Class& cls = Class::Handle(old_target.Owner());
+ new_target = cls.LookupStaticFunction(selector);
+ }
+
+ const Array& args_desc_array = Array::Handle(arguments_descriptor());
+ ArgumentsDescriptor args_desc(args_desc_array);
+ if (new_target.IsNull() ||
+ !new_target.AreValidArguments(args_desc, NULL)) {
+ // TODO(rmacnak): Patch to a NSME stub.
+ VTIR_Print("Cannot rebind static call to %s from %s\n",
+ old_target.ToCString(),
+ Object::Handle(Owner()).ToCString());
return;
}
ClearAndSetStaticTarget(new_target);
diff --git a/runtime/vm/object_store.cc b/runtime/vm/object_store.cc
index e1ca9dd..e0bf805 100644
--- a/runtime/vm/object_store.cc
+++ b/runtime/vm/object_store.cc
@@ -89,8 +89,10 @@
lookup_port_handler_(Function::null()),
empty_uint32_array_(TypedData::null()),
handle_message_function_(Function::null()),
+ simple_instance_of_function_(Function::null()),
+ simple_instance_of_true_function_(Function::null()),
+ simple_instance_of_false_function_(Function::null()),
library_load_error_table_(Array::null()),
- compile_time_constants_(Array::null()),
unique_dynamic_targets_(Array::null()),
token_objects_(GrowableObjectArray::null()),
token_objects_map_(Array::null()),
@@ -120,6 +122,7 @@
}
+#ifndef PRODUCT
void ObjectStore::PrintToJSONObject(JSONObject* jsobj) {
if (!FLAG_support_service) {
return;
@@ -136,6 +139,7 @@
#undef PRINT_OBJECT_STORE_FIELD
}
}
+#endif // !PRODUCT
RawError* ObjectStore::PreallocateObjects() {
@@ -202,6 +206,16 @@
}
+RawFunction* ObjectStore::PrivateObjectLookup(const String& name) {
+ const Library& core_lib = Library::Handle(core_library());
+ const String& mangled = String::ZoneHandle(core_lib.PrivateName(name));
+ const Class& cls = Class::Handle(object_class());
+ const Function& result = Function::Handle(cls.LookupDynamicFunction(mangled));
+ ASSERT(!result.IsNull());
+ return result.raw();
+}
+
+
void ObjectStore::InitKnownObjects() {
#ifdef DART_PRECOMPILED_RUNTIME
// These objects are only needed for code generation.
@@ -228,6 +242,14 @@
const Library& internal_lib = Library::Handle(internal_library());
cls = internal_lib.LookupClass(Symbols::Symbol());
set_symbol_class(cls);
+
+ // Cache the core private functions used for fast instance of checks.
+ simple_instance_of_function_ =
+ PrivateObjectLookup(Symbols::_simpleInstanceOf());
+ simple_instance_of_true_function_ =
+ PrivateObjectLookup(Symbols::_simpleInstanceOfTrue());
+ simple_instance_of_false_function_ =
+ PrivateObjectLookup(Symbols::_simpleInstanceOfFalse());
#endif
}
diff --git a/runtime/vm/object_store.h b/runtime/vm/object_store.h
index 6ab93de..e6d6293 100644
--- a/runtime/vm/object_store.h
+++ b/runtime/vm/object_store.h
@@ -440,13 +440,6 @@
return OFFSET_OF(ObjectStore, library_load_error_table_);
}
- RawArray* compile_time_constants() const {
- return compile_time_constants_;
- }
- void set_compile_time_constants(const Array& value) {
- compile_time_constants_ = value.raw();
- }
-
RawArray* unique_dynamic_targets() const {
return unique_dynamic_targets_;
}
@@ -486,6 +479,16 @@
megamorphic_miss_function_ = func.raw();
}
+ RawFunction* simple_instance_of_function() const {
+ return simple_instance_of_function_;
+ }
+ RawFunction* simple_instance_of_true_function() const {
+ return simple_instance_of_true_function_;
+ }
+ RawFunction* simple_instance_of_false_function() const {
+ return simple_instance_of_false_function_;
+ }
+
// Visit all object pointers.
void VisitObjectPointers(ObjectPointerVisitor* visitor);
@@ -498,11 +501,16 @@
static void Init(Isolate* isolate);
+#ifndef PRODUCT
void PrintToJSONObject(JSONObject* jsobj);
+#endif
private:
ObjectStore();
+ // Finds a core library private method in Object.
+ RawFunction* PrivateObjectLookup(const String& name);
+
#define OBJECT_STORE_FIELD_LIST(V) \
V(RawClass*, object_class_) \
V(RawType*, object_type_) \
@@ -578,14 +586,17 @@
V(RawFunction*, lookup_port_handler_) \
V(RawTypedData*, empty_uint32_array_) \
V(RawFunction*, handle_message_function_) \
+ V(RawFunction*, simple_instance_of_function_) \
+ V(RawFunction*, simple_instance_of_true_function_) \
+ V(RawFunction*, simple_instance_of_false_function_) \
V(RawArray*, library_load_error_table_) \
- V(RawArray*, compile_time_constants_) \
V(RawArray*, unique_dynamic_targets_) \
V(RawGrowableObjectArray*, token_objects_) \
V(RawArray*, token_objects_map_) \
V(RawGrowableObjectArray*, megamorphic_cache_table_) \
V(RawCode*, megamorphic_miss_code_) \
V(RawFunction*, megamorphic_miss_function_) \
+ // Please remember the last entry must be referred in the 'to' function below.
RawObject** from() { return reinterpret_cast<RawObject**>(&object_class_); }
#define DECLARE_OBJECT_STORE_FIELD(type, name) \
@@ -598,7 +609,7 @@
RawObject** to_snapshot(Snapshot::Kind kind) {
switch (kind) {
case Snapshot::kCore:
- return reinterpret_cast<RawObject**>(&compile_time_constants_);
+ return reinterpret_cast<RawObject**>(&library_load_error_table_);
case Snapshot::kAppWithJIT:
case Snapshot::kAppNoJIT:
return to();
diff --git a/runtime/vm/os_fuchsia.cc b/runtime/vm/os_fuchsia.cc
index 10faf1c..b634352 100644
--- a/runtime/vm/os_fuchsia.cc
+++ b/runtime/vm/os_fuchsia.cc
@@ -7,13 +7,22 @@
#include "vm/os.h"
+#include <errno.h>
#include <magenta/syscalls.h>
#include <magenta/types.h>
#include "platform/assert.h"
+#include "vm/zone.h"
namespace dart {
+#ifndef PRODUCT
+
+DEFINE_FLAG(bool, generate_perf_events_symbols, false,
+ "Generate events symbols for profiling with perf");
+
+#endif // !PRODUCT
+
const char* OS::Name() {
return "fuchsia";
}
@@ -49,25 +58,24 @@
int64_t OS::GetCurrentTimeMicros() {
- return _magenta_current_time() / 1000;
+ return mx_current_time() / 1000;
}
int64_t OS::GetCurrentMonotonicTicks() {
- UNIMPLEMENTED();
- return 0;
+ return mx_current_time();
}
int64_t OS::GetCurrentMonotonicFrequency() {
- UNIMPLEMENTED();
- return 0;
+ return kNanosecondsPerSecond;
}
int64_t OS::GetCurrentMonotonicMicros() {
- UNIMPLEMENTED();
- return 0;
+ int64_t ticks = GetCurrentMonotonicTicks();
+ ASSERT(GetCurrentMonotonicFrequency() == kNanosecondsPerSecond);
+ return ticks / kNanosecondsPerMicrosecond;
}
@@ -89,16 +97,45 @@
// TODO(5411554): May need to hoist these architecture dependent code
-// into a architecture specific file e.g: os_ia32_linux.cc
+// into a architecture specific file e.g: os_ia32_fuchsia.cc
intptr_t OS::ActivationFrameAlignment() {
- UNIMPLEMENTED();
- return 0;
+#if defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64) || \
+ defined(TARGET_ARCH_ARM64)
+ const int kMinimumAlignment = 16;
+#elif defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_DBC)
+ const int kMinimumAlignment = 8;
+#else
+#error Unsupported architecture.
+#endif
+ intptr_t alignment = kMinimumAlignment;
+ // TODO(5411554): Allow overriding default stack alignment for
+ // testing purposes.
+ // Flags::DebugIsInt("stackalign", &alignment);
+ ASSERT(Utils::IsPowerOfTwo(alignment));
+ ASSERT(alignment >= kMinimumAlignment);
+ return alignment;
}
intptr_t OS::PreferredCodeAlignment() {
- UNIMPLEMENTED();
- return 0;
+#if defined(TARGET_ARCH_IA32) || \
+ defined(TARGET_ARCH_X64) || \
+ defined(TARGET_ARCH_ARM64) || \
+ defined(TARGET_ARCH_DBC)
+ const int kMinimumAlignment = 32;
+#elif defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_MIPS)
+ const int kMinimumAlignment = 16;
+#else
+#error Unsupported architecture.
+#endif
+ intptr_t alignment = kMinimumAlignment;
+ // TODO(5411554): Allow overriding default code alignment for
+ // testing purposes.
+ // Flags::DebugIsInt("codealign", &alignment);
+ ASSERT(Utils::IsPowerOfTwo(alignment));
+ ASSERT(alignment >= kMinimumAlignment);
+ ASSERT(alignment <= OS::kMaxPreferredCodeAlignment);
+ return alignment;
}
@@ -130,19 +167,20 @@
char* OS::StrNDup(const char* s, intptr_t n) {
- UNIMPLEMENTED();
- return NULL;
+ return strndup(s, n);
}
intptr_t OS::StrNLen(const char* s, intptr_t n) {
- UNIMPLEMENTED();
- return 0;
+ return strnlen(s, n);
}
void OS::Print(const char* format, ...) {
- UNIMPLEMENTED();
+ va_list args;
+ va_start(args, format);
+ VFPrint(stdout, format, args);
+ va_end(args);
}
@@ -153,37 +191,81 @@
int OS::SNPrint(char* str, size_t size, const char* format, ...) {
- UNIMPLEMENTED();
- return 0;
+ va_list args;
+ va_start(args, format);
+ int retval = VSNPrint(str, size, format, args);
+ va_end(args);
+ return retval;
}
int OS::VSNPrint(char* str, size_t size, const char* format, va_list args) {
- UNIMPLEMENTED();
- return 0;
+ int retval = vsnprintf(str, size, format, args);
+ if (retval < 0) {
+ FATAL1("Fatal error in OS::VSNPrint with format '%s'", format);
+ }
+ return retval;
}
char* OS::SCreate(Zone* zone, const char* format, ...) {
- UNIMPLEMENTED();
- return NULL;
+ va_list args;
+ va_start(args, format);
+ char* buffer = VSCreate(zone, format, args);
+ va_end(args);
+ return buffer;
}
char* OS::VSCreate(Zone* zone, const char* format, va_list args) {
- UNIMPLEMENTED();
- return NULL;
+ // Measure.
+ va_list measure_args;
+ va_copy(measure_args, args);
+ intptr_t len = VSNPrint(NULL, 0, format, measure_args);
+ va_end(measure_args);
+
+ char* buffer;
+ if (zone) {
+ buffer = zone->Alloc<char>(len + 1);
+ } else {
+ buffer = reinterpret_cast<char*>(malloc(len + 1));
+ }
+ ASSERT(buffer != NULL);
+
+ // Print.
+ va_list print_args;
+ va_copy(print_args, args);
+ VSNPrint(buffer, len + 1, format, print_args);
+ va_end(print_args);
+ return buffer;
}
bool OS::StringToInt64(const char* str, int64_t* value) {
- UNIMPLEMENTED();
- return false;
+ ASSERT(str != NULL && strlen(str) > 0 && value != NULL);
+ int32_t base = 10;
+ char* endptr;
+ int i = 0;
+ if (str[0] == '-') {
+ i = 1;
+ }
+ if ((str[i] == '0') &&
+ (str[i + 1] == 'x' || str[i + 1] == 'X') &&
+ (str[i + 2] != '\0')) {
+ base = 16;
+ }
+ errno = 0;
+ *value = strtoll(str, &endptr, base);
+ return ((errno == 0) && (endptr != str) && (*endptr == 0));
}
void OS::RegisterCodeObservers() {
- UNIMPLEMENTED();
+#ifndef PRODUCT
+ if (FLAG_generate_perf_events_symbols) {
+ UNIMPLEMENTED();
+ }
+#endif // !PRODUCT
}
diff --git a/runtime/vm/os_thread_fuchsia.cc b/runtime/vm/os_thread_fuchsia.cc
index c3e8d25..cca791c 100644
--- a/runtime/vm/os_thread_fuchsia.cc
+++ b/runtime/vm/os_thread_fuchsia.cc
@@ -47,7 +47,7 @@
static void ComputeTimeSpecMicros(struct timespec* ts, int64_t micros) {
// time in nanoseconds.
- mx_time_t now = _magenta_current_time();
+ mx_time_t now = mx_current_time();
mx_time_t target = now + (micros * kNanosecondsPerMicrosecond);
int64_t secs = target / kNanosecondsPerSecond;
int64_t nanos = target - (secs * kNanosecondsPerSecond);
@@ -169,8 +169,7 @@
#ifndef PRODUCT
ThreadId OSThread::GetCurrentThreadTraceId() {
- UNIMPLEMENTED();
- return 0;
+ return pthread_self();
}
#endif // PRODUCT
diff --git a/runtime/vm/pages.cc b/runtime/vm/pages.cc
index a10d097..2f894b5 100644
--- a/runtime/vm/pages.cc
+++ b/runtime/vm/pages.cc
@@ -969,7 +969,7 @@
{
MonitorLocker ml(tasks_lock());
set_tasks(tasks() - 1);
- ml.Notify();
+ ml.NotifyAll();
}
}
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index c902639..9e7dcbd 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -3387,17 +3387,6 @@
ASSERT(AbstractType::Handle(Z, func.result_type()).IsResolved());
ASSERT(func.NumParameters() == params.parameters->length());
- // Check whether the function has any field initializer formal parameters,
- // which are not allowed in non-constructor functions.
- if (params.has_field_initializer) {
- for (int i = 0; i < params.parameters->length(); i++) {
- ParamDesc& param = (*params.parameters)[i];
- if (param.is_field_initializer) {
- ReportError(param.name_pos,
- "field initializer only allowed in constructors");
- }
- }
- }
// Populate function scope with the formal parameters.
AddFormalParamsToScope(¶ms, current_block_->scope);
@@ -4743,6 +4732,10 @@
TRACE_PARSER("ParseEnumDefinition");
INC_STAT(thread(), num_classes_parsed, 1);
+ const Class& helper_class =
+ Class::Handle(Z, Library::LookupCoreClass(Symbols::_EnumHelper()));
+ ASSERT(!helper_class.IsNull());
+
SkipMetadata();
ExpectToken(Token::kENUM);
@@ -4754,9 +4747,9 @@
const Type& int_type = Type::Handle(Z, Type::IntType());
index_field = Field::New(Symbols::Index(),
false, // Not static.
- true, // Field is final.
+ true, // Field is final.
false, // Not const.
- true, // Is reflectable.
+ true, // Is reflectable.
cls,
int_type,
cls.token_pos());
@@ -4782,18 +4775,12 @@
AddFormalParamsToFunction(¶ms, getter);
enum_members.AddFunction(getter);
- GrowableObjectArray& enum_names = GrowableObjectArray::Handle(Z,
- GrowableObjectArray::New(8, Heap::kOld));
- const String& name_prefix =
- String::Handle(String::Concat(enum_name, Symbols::Dot()));
-
ASSERT(IsIdentifier());
ASSERT(CurrentLiteral()->raw() == cls.Name());
ConsumeToken(); // Enum type name.
ExpectToken(Token::kLBRACE);
Field& enum_value = Field::Handle(Z);
- String& enum_value_name = String::Handle(Z);
intptr_t i = 0;
GrowableArray<String*> declared_names(8);
@@ -4841,14 +4828,6 @@
enum_value.RecordStore(ordinal_value);
i++;
- // For the user-visible name of the enumeration value, we need to
- // unmangle private names.
- if (enum_ident->CharAt(0) == '_') {
- *enum_ident = String::ScrubName(*enum_ident);
- }
- enum_value_name = Symbols::FromConcat(T, name_prefix, *enum_ident);
- enum_names.Add(enum_value_name, Heap::kOld);
-
ConsumeToken(); // Enum value name.
if (CurrentToken() == Token::kCOMMA) {
ConsumeToken();
@@ -4856,10 +4835,6 @@
}
ExpectToken(Token::kRBRACE);
- const Class& helper_class =
- Class::Handle(Z, Library::LookupCoreClass(Symbols::_EnumHelper()));
- ASSERT(!helper_class.IsNull());
-
// Add static field 'const List values'.
Field& values_field = Field::ZoneHandle(Z);
values_field = Field::New(Symbols::Values(),
@@ -4878,16 +4853,35 @@
values_field.SetStaticValue(values_array, true);
values_field.RecordStore(values_array);
- // Create a static field that contains the list of enumeration names.
- // Clone the _enum_names field from the helper class.
- Field& names_field = Field::Handle(Z,
- helper_class.LookupStaticFieldAllowPrivate(Symbols::_EnumNames()));
- ASSERT(!names_field.IsNull());
- names_field = names_field.Clone(cls);
- enum_members.AddField(names_field);
- const Array& names_array = Array::Handle(Array::MakeArray(enum_names));
- names_field.SetStaticValue(names_array, true);
- names_field.RecordStore(names_array);
+ // Clone the _name field from the helper class.
+ Field& _name_field = Field::Handle(Z,
+ helper_class.LookupInstanceFieldAllowPrivate(Symbols::_name()));
+ ASSERT(!_name_field.IsNull());
+ _name_field = _name_field.Clone(cls);
+ enum_members.AddField(_name_field);
+
+ // Add an implicit getter function for the _name field. We use the field's
+ // name directly here so that the private key matches those of the other
+ // cloned helper functions and fields.
+ const Type& string_type = Type::Handle(Z, Type::StringType());
+ const String& name_getter_name = String::Handle(Z,
+ Field::GetterSymbol(String::Handle(_name_field.name())));
+ Function& name_getter = Function::Handle(Z);
+ name_getter = Function::New(name_getter_name,
+ RawFunction::kImplicitGetter,
+ /* is_static = */ false,
+ /* is_const = */ true,
+ /* is_abstract = */ false,
+ /* is_external = */ false,
+ /* is_native = */ false,
+ cls,
+ cls.token_pos());
+ name_getter.set_result_type(string_type);
+ name_getter.set_is_debuggable(false);
+ ParamList name_params;
+ name_params.AddReceiver(&Object::dynamic_type(), cls.token_pos());
+ AddFormalParamsToFunction(&name_params, name_getter);
+ enum_members.AddFunction(name_getter);
// Clone the toString() function from the helper class.
Function& to_string_func = Function::Handle(Z,
@@ -7397,6 +7391,12 @@
ParamDesc& param_desc = (*params->parameters)[i];
func.SetParameterTypeAt(i, *param_desc.type);
func.SetParameterNameAt(i, *param_desc.name);
+ if (param_desc.is_field_initializer && !func.IsGenerativeConstructor()) {
+ // Redirecting constructors are detected later in ParseConstructor.
+ ReportError(param_desc.name_pos,
+ "only generative constructors may have "
+ "initializing formal parameters");
+ }
}
}
@@ -12134,21 +12134,21 @@
}
-void Parser::InsertCachedConstantValue(const String& url,
+void Parser::InsertCachedConstantValue(const Script& script,
TokenPosition token_pos,
const Instance& value) {
ASSERT(Thread::Current()->IsMutatorThread());
- Isolate* isolate = Isolate::Current();
- ConstantPosKey key(url, token_pos);
- if (isolate->object_store()->compile_time_constants() == Array::null()) {
- const intptr_t kInitialConstMapSize = 16;
- isolate->object_store()->set_compile_time_constants(
+ const intptr_t kInitialConstMapSize = 16;
+ ASSERT(!script.InVMHeap());
+ if (script.compile_time_constants() == Array::null()) {
+ const Array& array =
Array::Handle(HashTables::New<ConstantsMap>(kInitialConstMapSize,
- Heap::kNew)));
+ Heap::kNew));
+ script.set_compile_time_constants(array);
}
- ConstantsMap constants(isolate->object_store()->compile_time_constants());
- constants.InsertNewOrGetValue(key, value);
- isolate->object_store()->set_compile_time_constants(constants.Release());
+ ConstantsMap constants(script.compile_time_constants());
+ constants.InsertNewOrGetValue(token_pos, value);
+ script.set_compile_time_constants(constants.Release());
}
@@ -12159,26 +12159,20 @@
// evaluated only once.
return;
}
- const String& url = String::Handle(Z, script_.url());
- InsertCachedConstantValue(url, token_pos, value);
- if (FLAG_compiler_stats) {
- ConstantsMap constants(isolate()->object_store()->compile_time_constants());
- thread_->compiler_stats()->num_cached_consts = constants.NumOccupied();
- constants.Release();
- }
+ InsertCachedConstantValue(script_, token_pos, value);
}
bool Parser::GetCachedConstant(TokenPosition token_pos, Instance* value) {
- if (isolate()->object_store()->compile_time_constants() == Array::null()) {
+ bool is_present = false;
+ ASSERT(!script_.InVMHeap());
+ if (script_.compile_time_constants() == Array::null()) {
return false;
}
- ConstantPosKey key(String::Handle(Z, script_.url()), token_pos);
- ConstantsMap constants(isolate()->object_store()->compile_time_constants());
- bool is_present = false;
- *value ^= constants.GetOrNull(key, &is_present);
+ ConstantsMap constants(script_.compile_time_constants());
+ *value ^= constants.GetOrNull(token_pos, &is_present);
// Mutator compiler thread may add constants while background compiler
- // is running , and thus change the value of 'compile_time_constants';
+ // is running, and thus change the value of 'compile_time_constants';
// do not assert that 'compile_time_constants' has not changed.
constants.Release();
if (FLAG_compiler_stats && is_present) {
@@ -12230,6 +12224,8 @@
// not been evaluated. If the field is const, call the static getter method
// to evaluate the expression and canonicalize the value.
if (field.is_const()) {
+ NoReloadScope no_reload_scope(isolate(), thread());
+ NoOOBMessageScope no_msg_scope(thread());
field.SetStaticValue(Object::transition_sentinel());
const int kNumArguments = 0; // no arguments.
const Function& func = Function::Handle(Z,
@@ -12287,6 +12283,8 @@
const TypeArguments& type_arguments,
const Function& constructor,
ArgumentListNode* arguments) {
+ NoReloadScope no_reload_scope(isolate(), thread());
+ NoOOBMessageScope no_msg_scope(thread());
// Factories have one extra argument: the type arguments.
// Constructors have 1 extra arguments: receiver.
const int kNumExtraArgs = 1;
@@ -13801,6 +13799,8 @@
String& Parser::Interpolate(const GrowableArray<AstNode*>& values) {
+ NoReloadScope no_reload_scope(isolate(), thread());
+ NoOOBMessageScope no_msg_scope(thread());
const Class& cls = Class::Handle(
Z, Library::LookupCoreClass(Symbols::StringBase()));
ASSERT(!cls.IsNull());
@@ -14148,6 +14148,8 @@
// be a compile time constant.
const Instance& Parser::EvaluateConstExpr(TokenPosition expr_pos,
AstNode* expr) {
+ NoReloadScope no_reload_scope(isolate(), thread());
+ NoOOBMessageScope no_msg_scope(thread());
if (expr->IsLiteralNode()) {
return expr->AsLiteralNode()->literal();
} else if (expr->IsLoadLocalNode() &&
@@ -14623,7 +14625,7 @@
}
-void Parser::InsertCachedConstantValue(const String& url,
+void Parser::InsertCachedConstantValue(const Script& script,
TokenPosition token_pos,
const Instance& value) {
UNREACHABLE();
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index 815f978..e29f86e 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -39,61 +39,44 @@
class TopLevel;
class RecursionChecker;
-// We cache computed compile-time constants in a map so we can look them
-// up when the same code gets compiled again. The map key is a pair
-// (script url, token position) which is encoded in an array with 2
-// elements:
-// - key[0] contains the canonicalized url of the script.
-// - key[1] contains the token position of the constant in the script.
-
-// ConstantPosKey allows us to look up a constant in the map without
-// allocating a key pair (array).
-struct ConstantPosKey : ValueObject {
- ConstantPosKey(const String& url, TokenPosition pos)
- : script_url(url), token_pos(pos) { }
- const String& script_url;
- TokenPosition token_pos;
-};
-
-
+// We cache compile time constants during compilation. This allows us
+// to look them up when the same code gets compiled again. During
+// background compilation, we are not able to evaluate the constants
+// so this cache is necessary to support background compilation.
+//
+// We cache the constants with the script itself. This is helpful during isolate
+// reloading, as it allows us to reference the compile time constants associated
+// with a particular version of a script. The map key is simply the
+// TokenPosition where the constant is defined.
class ConstMapKeyEqualsTraits {
public:
static const char* Name() { return "ConstMapKeyEqualsTraits"; }
static bool ReportStats() { return false; }
static bool IsMatch(const Object& a, const Object& b) {
- const Array& key1 = Array::Cast(a);
- const Array& key2 = Array::Cast(b);
- // Compare raw strings of script url symbol and raw smi of token positon.
- return (key1.At(0) == key2.At(0)) && (key1.At(1) == key2.At(1));
+ const Smi& key1 = Smi::Cast(a);
+ const Smi& key2 = Smi::Cast(b);
+ return (key1.Value() == key2.Value());
}
- static bool IsMatch(const ConstantPosKey& key1, const Object& b) {
- const Array& key2 = Array::Cast(b);
- // Compare raw strings of script url symbol and token positon.
- return (key1.script_url.raw() == key2.At(0))
- && (key1.token_pos.value() == Smi::Value(Smi::RawCast(key2.At(1))));
+ static bool IsMatch(const TokenPosition& key1, const Object& b) {
+ const Smi& key2 = Smi::Cast(b);
+ return (key1.value() == key2.Value());
}
static uword Hash(const Object& obj) {
- const Array& key = Array::Cast(obj);
- intptr_t url_hash = String::HashRawSymbol(String::RawCast(key.At(0)));
- intptr_t pos = Smi::Value(Smi::RawCast(key.At(1)));
- return HashValue(url_hash, pos);
+ const Smi& key = Smi::Cast(obj);
+ return HashValue(key.Value());
}
- static uword Hash(const ConstantPosKey& key) {
- return HashValue(String::HashRawSymbol(key.script_url.raw()),
- key.token_pos.value());
+ static uword Hash(const TokenPosition& key) {
+ return HashValue(key.value());
}
- // Used by CachConstantValue if a new constant is added to the map.
- static RawObject* NewKey(const ConstantPosKey& key) {
- const Array& key_obj = Array::Handle(Array::New(2));
- key_obj.SetAt(0, key.script_url);
- key_obj.SetAt(1, Smi::Handle(Smi::New(key.token_pos.value())));
- return key_obj.raw();;
+ // Used by CacheConstantValue if a new constant is added to the map.
+ static RawObject* NewKey(const TokenPosition& key) {
+ return Smi::New(key.value());
}
private:
- static uword HashValue(intptr_t url_hash, intptr_t pos) {
- return url_hash * pos % (Smi::kMaxValue - 13);
+ static uword HashValue(intptr_t pos) {
+ return pos % (Smi::kMaxValue - 13);
}
};
typedef UnorderedHashMap<ConstMapKeyEqualsTraits> ConstantsMap;
@@ -278,7 +261,7 @@
// given static field.
static ParsedFunction* ParseStaticFieldInitializer(const Field& field);
- static void InsertCachedConstantValue(const String& url,
+ static void InsertCachedConstantValue(const Script& script,
TokenPosition token_pos,
const Instance& value);
@@ -617,8 +600,7 @@
ClosureNode* CreateImplicitClosureNode(const Function& func,
TokenPosition token_pos,
AstNode* receiver);
- static void AddFormalParamsToFunction(const ParamList* params,
- const Function& func);
+ void AddFormalParamsToFunction(const ParamList* params, const Function& func);
void AddFormalParamsToScope(const ParamList* params, LocalScope* scope);
SequenceNode* ParseConstructor(const Function& func);
diff --git a/runtime/vm/port.cc b/runtime/vm/port.cc
index 8ef15c5..2541b38 100644
--- a/runtime/vm/port.cc
+++ b/runtime/vm/port.cc
@@ -303,6 +303,7 @@
void PortMap::PrintPortsForMessageHandler(MessageHandler* handler,
JSONStream* stream) {
+#ifndef PRODUCT
if (!FLAG_support_service) {
return;
}
@@ -324,6 +325,7 @@
}
}
}
+#endif
}
diff --git a/runtime/vm/precompiler.cc b/runtime/vm/precompiler.cc
index 35df46b..dc0edb5 100644
--- a/runtime/vm/precompiler.cc
+++ b/runtime/vm/precompiler.cc
@@ -240,8 +240,8 @@
DropTypeArguments();
// Clear these before dropping classes as they may hold onto otherwise
- // dead instances of classes we will remove.
- I->object_store()->set_compile_time_constants(Array::null_array());
+ // dead instances of classes we will remove or otherwise unused symbols.
+ DropScriptData();
I->object_store()->set_unique_dynamic_targets(Array::null_array());
Class& null_class = Class::Handle(Z);
I->object_store()->set_future_class(null_class);
@@ -1560,6 +1560,24 @@
}
+void Precompiler::DropScriptData() {
+ Library& lib = Library::Handle(Z);
+ Array& scripts = Array::Handle(Z);
+ Script& script = Script::Handle(Z);
+ const TokenStream& null_tokens = TokenStream::Handle(Z);
+ for (intptr_t i = 0; i < libraries_.Length(); i++) {
+ lib ^= libraries_.At(i);
+ scripts = lib.LoadedScripts();
+ for (intptr_t j = 0; j < scripts.Length(); j++) {
+ script ^= scripts.At(j);
+ script.set_compile_time_constants(Array::null_array());
+ script.set_source(String::null_string());
+ script.set_tokens(null_tokens);
+ }
+ }
+}
+
+
void Precompiler::TraceTypesFromRetainedClasses() {
Library& lib = Library::Handle(Z);
Class& cls = Class::Handle(Z);
@@ -2659,6 +2677,9 @@
sinking->DetachMaterializations();
}
+ // Replace bounds check instruction with a generic one.
+ optimizer.ReplaceArrayBoundChecks();
+
// Compute and store graph informations (call & instruction counts)
// to be later used by the inliner.
FlowGraphInliner::CollectGraphInfo(flow_graph, true);
diff --git a/runtime/vm/precompiler.h b/runtime/vm/precompiler.h
index 6ec2ed3..5cae27e 100644
--- a/runtime/vm/precompiler.h
+++ b/runtime/vm/precompiler.h
@@ -306,6 +306,7 @@
void TraceTypesFromRetainedClasses();
void DropTypes();
void DropTypeArguments();
+ void DropScriptData();
void DropClasses();
void DropLibraries();
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index dd8ff93..fb1f06e 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -640,6 +640,9 @@
friend class NativeEntry; // GetClassId
friend class Simulator;
friend class SimulatorHelpers;
+ friend class ObjectLocator;
+ friend class InstanceMorpher; // GetClassId
+ friend class VerifyCanonicalVisitor;
DISALLOW_ALLOCATION();
DISALLOW_IMPLICIT_CONSTRUCTORS(RawObject);
@@ -995,9 +998,10 @@
RawObject** from() { return reinterpret_cast<RawObject**>(&ptr()->url_); }
RawString* url_;
+ RawArray* compile_time_constants_;
RawTokenStream* tokens_;
RawString* source_;
- RawObject** to() { return reinterpret_cast<RawObject**>(&ptr()->source_); }
+ RawObject** to() {return reinterpret_cast<RawObject**>(&ptr()->source_); }
RawObject** to_snapshot(Snapshot::Kind kind) {
switch (kind) {
case Snapshot::kAppNoJIT:
@@ -1170,7 +1174,6 @@
Entry* first_entry() { return &ptr()->data()[0]; }
friend class Object;
- friend class SnapshotReader;
};
@@ -1253,7 +1256,6 @@
const uint8_t* data() const { OPEN_ARRAY_START(uint8_t, intptr_t); }
friend class Object;
- friend class SnapshotReader;
};
@@ -1270,7 +1272,6 @@
const uint8_t* data() const { OPEN_ARRAY_START(uint8_t, intptr_t); }
friend class Object;
- friend class SnapshotReader;
};
@@ -1297,8 +1298,6 @@
// Variable length data follows here (bitmap of the stack layout).
uint8_t* data() { OPEN_ARRAY_START(uint8_t, uint8_t); }
const uint8_t* data() const { OPEN_ARRAY_START(uint8_t, uint8_t); }
-
- friend class SnapshotReader;
};
@@ -1372,7 +1371,6 @@
}
friend class Object;
- friend class SnapshotReader;
};
@@ -1402,7 +1400,6 @@
HandlerInfo* data() { OPEN_ARRAY_START(HandlerInfo, intptr_t); }
friend class Object;
- friend class SnapshotReader;
};
@@ -1501,8 +1498,7 @@
return NULL;
}
int32_t deopt_id_; // Deoptimization id corresponding to this IC.
- uint32_t state_bits_; // Number of arguments tested in IC, deopt reasons,
- // range feedback.
+ uint32_t state_bits_; // Number of arguments tested in IC, deopt reasons.
#if defined(TAG_IC_DATA)
intptr_t tag_; // Debugging, verifying that the icdata is assigned to the
// same instruction again. Store -1 or Instruction::Tag.
diff --git a/runtime/vm/raw_object_snapshot.cc b/runtime/vm/raw_object_snapshot.cc
index c2448a3..d94ce4e 100644
--- a/runtime/vm/raw_object_snapshot.cc
+++ b/runtime/vm/raw_object_snapshot.cc
@@ -14,16 +14,6 @@
DECLARE_FLAG(bool, remove_script_timestamps_for_test);
-#define NEW_OBJECT(type) \
- ((Snapshot::IsFull(kind)) ? reader->New##type() : type::New())
-
-#define NEW_OBJECT_WITH_LEN(type, len) \
- ((Snapshot::IsFull(kind)) ? reader->New##type(len) : type::New(len))
-
-#define NEW_OBJECT_WITH_LEN_SPACE(type, len, kind) \
- ((Snapshot::IsFull(kind)) ? \
- reader->New##type(len) : type::New(len, HEAP_SPACE(kind)))
-
#define OFFSET_OF_FROM(obj) \
obj.raw()->from() - reinterpret_cast<RawObject**>(obj.raw()->ptr())
@@ -48,21 +38,16 @@
Class& cls = Class::ZoneHandle(reader->zone(), Class::null());
bool is_in_fullsnapshot = reader->Read<bool>();
- if (Snapshot::IsFull(kind) ||
- (kind == Snapshot::kScript && !is_in_fullsnapshot)) {
+ if ((kind == Snapshot::kScript) && !is_in_fullsnapshot) {
// Read in the base information.
classid_t class_id = reader->ReadClassIDValue();
// Allocate class object of specified kind.
- if (Snapshot::IsFull(kind)) {
- cls = reader->NewClass(class_id);
+ if (class_id < kNumPredefinedCids) {
+ ASSERT((class_id >= kInstanceCid) && (class_id <= kMirrorReferenceCid));
+ cls = reader->isolate()->class_table()->At(class_id);
} else {
- if (class_id < kNumPredefinedCids) {
- ASSERT((class_id >= kInstanceCid) && (class_id <= kMirrorReferenceCid));
- cls = reader->isolate()->class_table()->At(class_id);
- } else {
- cls = Class::NewInstanceClass();
- }
+ cls = Class::NewInstanceClass();
}
reader->AddBackRef(object_id, &cls, kIsDeserialized);
@@ -85,7 +70,7 @@
cls.raw()->to_snapshot(kind),
kAsReference);
cls.StorePointer(&cls.raw_ptr()->dependent_code_, Array::null());
- ASSERT(!cls.IsInFullSnapshot() || (Snapshot::IsFull(kind)));
+ ASSERT(!cls.IsInFullSnapshot());
} else {
cls ^= reader->ReadClassId(object_id);
ASSERT((kind == Snapshot::kMessage) || cls.IsInFullSnapshot());
@@ -113,8 +98,7 @@
// to be interpreted.
writer->Write<bool>(is_in_fullsnapshot);
- if (Snapshot::IsFull(kind) ||
- (kind == Snapshot::kScript && !is_in_fullsnapshot)) {
+ if ((kind == Snapshot::kScript) && !is_in_fullsnapshot) {
// Write out all the non object pointer fields.
// NOTE: cpp_vtable_ is not written.
classid_t class_id = ptr()->id_;
@@ -160,7 +144,7 @@
// Allocate unresolved class object.
UnresolvedClass& unresolved_class = UnresolvedClass::ZoneHandle(
- reader->zone(), NEW_OBJECT(UnresolvedClass));
+ reader->zone(), UnresolvedClass::New());
reader->AddBackRef(object_id, &unresolved_class, kIsDeserialized);
// Set all non object fields.
@@ -228,10 +212,11 @@
bool typeclass_is_in_fullsnapshot = reader->Read<bool>();
// Allocate type object.
- Type& type = Type::ZoneHandle(reader->zone(), NEW_OBJECT(Type));
+ Type& type = Type::ZoneHandle(reader->zone(), Type::New());
bool is_canonical = RawObject::IsCanonical(tags);
bool defer_canonicalization = is_canonical &&
- (!Snapshot::IsFull(kind) && typeclass_is_in_fullsnapshot);
+ ((kind == Snapshot::kMessage) ||
+ (!Snapshot::IsFull(kind) && typeclass_is_in_fullsnapshot));
reader->AddBackRef(object_id, &type, kIsDeserialized, defer_canonicalization);
// Set all non object fields.
@@ -309,7 +294,7 @@
// Allocate type ref object.
TypeRef& type_ref = TypeRef::ZoneHandle(
- reader->zone(), NEW_OBJECT(TypeRef));
+ reader->zone(), TypeRef::New());
reader->AddBackRef(object_id, &type_ref, kIsDeserialized);
// Set all the object fields.
@@ -349,7 +334,7 @@
// Allocate type parameter object.
TypeParameter& type_parameter = TypeParameter::ZoneHandle(
- reader->zone(), NEW_OBJECT(TypeParameter));
+ reader->zone(), TypeParameter::New());
reader->AddBackRef(object_id, &type_parameter, kIsDeserialized);
// Set all non object fields.
@@ -413,7 +398,7 @@
// Allocate bounded type object.
BoundedType& bounded_type = BoundedType::ZoneHandle(
- reader->zone(), NEW_OBJECT(BoundedType));
+ reader->zone(), BoundedType::New());
reader->AddBackRef(object_id, &bounded_type, kIsDeserialized);
// Set all the object fields.
@@ -473,7 +458,7 @@
intptr_t len = reader->ReadSmiValue();
TypeArguments& type_arguments = TypeArguments::ZoneHandle(
- reader->zone(), NEW_OBJECT_WITH_LEN_SPACE(TypeArguments, len, kind));
+ reader->zone(), TypeArguments::New(len, HEAP_SPACE(kind)));
bool is_canonical = RawObject::IsCanonical(tags);
bool defer_canonicalization = is_canonical && (!Snapshot::IsFull(kind));
reader->AddBackRef(object_id,
@@ -482,12 +467,7 @@
defer_canonicalization);
// Set the instantiations field, which is only read from a full snapshot.
- if (Snapshot::IsFull(kind)) {
- *(reader->ArrayHandle()) ^= reader->ReadObjectImpl(kAsInlinedObject);
- type_arguments.set_instantiations(*(reader->ArrayHandle()));
- } else {
- type_arguments.set_instantiations(Object::zero_array());
- }
+ type_arguments.set_instantiations(Object::zero_array());
// Now set all the type fields.
intptr_t offset = type_arguments.TypeAddr(0) -
@@ -523,11 +503,6 @@
// Write out the length field.
writer->Write<RawObject*>(ptr()->length_);
- // Write out the instantiations field, but only in a full snapshot.
- if (Snapshot::IsFull(kind)) {
- 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++) {
@@ -542,16 +517,16 @@
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
+ ASSERT(kind == Snapshot::kScript);
// Allocate function object.
PatchClass& cls = PatchClass::ZoneHandle(reader->zone(),
- NEW_OBJECT(PatchClass));
+ PatchClass::New());
reader->AddBackRef(object_id, &cls, kIsDeserialized);
// Set all the object fields.
READ_OBJECT_FIELDS(cls, cls.raw()->from(), cls.raw()->to(), kAsReference);
- ASSERT((kind == Snapshot::kScript) || (Snapshot::IsFull(kind)));
return cls.raw();
}
@@ -561,7 +536,7 @@
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
- ASSERT((kind == Snapshot::kScript) || (Snapshot::IsFull(kind)));
+ ASSERT(kind == Snapshot::kScript);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
@@ -580,24 +555,8 @@
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
- ASSERT(reader != NULL);
- ASSERT(Snapshot::IsFull(kind));
-
- // Allocate closure object.
- Closure& closure = Closure::ZoneHandle(
- reader->zone(), NEW_OBJECT(Closure));
- reader->AddBackRef(object_id, &closure, kIsDeserialized);
-
- // Set all the object fields.
- READ_OBJECT_FIELDS(closure,
- closure.raw()->from(), closure.raw()->to(),
- kAsReference);
-
- // Set the canonical bit.
- if (RawObject::IsCanonical(tags)) {
- closure.SetCanonical();
- }
- return closure.raw();
+ UNREACHABLE();
+ return Closure::null();
}
@@ -606,27 +565,18 @@
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
- if ((kind == Snapshot::kMessage) || (kind == Snapshot::kScript)) {
- // Check if closure is serializable, throw an exception otherwise.
- RawFunction* func = writer->IsSerializableClosure(this);
- if (func != Function::null()) {
- writer->WriteStaticImplicitClosure(object_id,
- func,
- writer->GetObjectTags(this));
- return;
- }
+ ASSERT((kind == Snapshot::kMessage) || (kind == Snapshot::kScript));
+
+ // Check if closure is serializable, throw an exception otherwise.
+ RawFunction* func = writer->IsSerializableClosure(this);
+ if (func != Function::null()) {
+ writer->WriteStaticImplicitClosure(object_id,
+ func,
+ writer->GetObjectTags(this));
+ return;
}
- // Write out the serialization header value for this object.
- writer->WriteInlinedObjectHeader(object_id);
-
- // Write out the class and tags information.
- writer->WriteIndexedObject(kClosureCid);
- writer->WriteTags(writer->GetObjectTags(this));
-
- // Write out all the object pointer fields.
- SnapshotWriterVisitor visitor(writer, kAsReference);
- visitor.VisitPointers(from(), to());
+ UNREACHABLE();
}
@@ -636,11 +586,11 @@
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
- ASSERT((kind == Snapshot::kScript) || (Snapshot::IsFull(kind)));
+ ASSERT(kind == Snapshot::kScript);
// Allocate closure data object.
- ClosureData& data = ClosureData::ZoneHandle(
- reader->zone(), NEW_OBJECT(ClosureData));
+ ClosureData& data = ClosureData::ZoneHandle(reader->zone(),
+ ClosureData::New());
reader->AddBackRef(object_id, &data, kIsDeserialized);
// Set all the object fields.
@@ -657,7 +607,7 @@
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
- ASSERT((kind == Snapshot::kScript) || (Snapshot::IsFull(kind)));
+ ASSERT(kind == Snapshot::kScript);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
@@ -669,8 +619,7 @@
// Context scope.
if (ptr()->context_scope_ == Object::empty_context_scope().raw()) {
writer->WriteVMIsolateObject(kEmptyContextScopeObject);
- } else if (ptr()->context_scope_->ptr()->is_implicit_ ||
- (kind == Snapshot::kAppWithJIT)) {
+ } else if (ptr()->context_scope_->ptr()->is_implicit_) {
writer->WriteObjectImpl(ptr()->context_scope_, kAsInlinedObject);
} else {
// We don't write non implicit context scopes in the snapshot.
@@ -694,11 +643,11 @@
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
- ASSERT((kind == Snapshot::kScript) || (Snapshot::IsFull(kind)));
+ ASSERT(kind == Snapshot::kScript);
// Allocate redirection data object.
- RedirectionData& data = RedirectionData::ZoneHandle(
- reader->zone(), NEW_OBJECT(RedirectionData));
+ RedirectionData& data = RedirectionData::ZoneHandle(reader->zone(),
+ RedirectionData::New());
reader->AddBackRef(object_id, &data, kIsDeserialized);
// Set all the object fields.
@@ -715,7 +664,7 @@
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
- ASSERT((kind == Snapshot::kScript) || (Snapshot::IsFull(kind)));
+ ASSERT(kind == Snapshot::kScript);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
@@ -736,13 +685,13 @@
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
- ASSERT((kind == Snapshot::kScript) || (Snapshot::IsFull(kind)));
+ ASSERT(kind == Snapshot::kScript);
bool is_in_fullsnapshot = reader->Read<bool>();
- if ((Snapshot::IsFull(kind)) || !is_in_fullsnapshot) {
+ if (!is_in_fullsnapshot) {
// Allocate function object.
- Function& func = Function::ZoneHandle(
- reader->zone(), NEW_OBJECT(Function));
+ Function& func = Function::ZoneHandle(reader->zone(),
+ Function::New());
reader->AddBackRef(object_id, &func, kIsDeserialized);
// Set all the non object fields. Read the token positions now but
@@ -754,17 +703,10 @@
func.set_kind_tag(reader->Read<uint32_t>());
func.set_token_pos(TokenPosition::SnapshotDecode(token_pos));
func.set_end_token_pos(TokenPosition::SnapshotDecode(end_token_pos));
- if (kind == Snapshot::kAppNoJIT) {
- func.set_usage_counter(0);
- func.set_deoptimization_counter(0);
- func.set_optimized_instruction_count(0);
- func.set_optimized_call_site_count(0);
- } else {
- func.set_usage_counter(reader->Read<int32_t>());
- func.set_deoptimization_counter(reader->Read<int8_t>());
- func.set_optimized_instruction_count(reader->Read<uint16_t>());
- func.set_optimized_call_site_count(reader->Read<uint16_t>());
- }
+ func.set_usage_counter(reader->Read<int32_t>());
+ func.set_deoptimization_counter(reader->Read<int8_t>());
+ func.set_optimized_instruction_count(reader->Read<uint16_t>());
+ func.set_optimized_call_site_count(reader->Read<uint16_t>());
func.set_was_compiled(false);
// Set all the object fields.
@@ -772,34 +714,15 @@
func.raw()->from(), func.raw()->to_snapshot(),
kAsReference);
// Initialize all fields that are not part of the snapshot.
- if (kind == Snapshot::kAppNoJIT) {
- // Read the code object and fixup entry point.
- func.ClearICDataArray();
- func.ClearCode();
- (*reader->CodeHandle()) ^= reader->ReadObjectImpl(kAsInlinedObject);
- func.SetInstructions(*reader->CodeHandle());
- } else if (kind == Snapshot::kAppWithJIT) {
+ bool is_optimized = func.usage_counter() != 0;
+ if (is_optimized) {
+ // Read the ic data array as the function is an optimized one.
(*reader->ArrayHandle()) ^= reader->ReadObjectImpl(kAsReference);
func.set_ic_data_array(*reader->ArrayHandle());
- (*reader->CodeHandle()) ^= reader->ReadObjectImpl(kAsInlinedObject);
- func.set_unoptimized_code(*reader->CodeHandle());
- if (!reader->CodeHandle()->IsNull()) {
- func.SetInstructions(*reader->CodeHandle());
- func.set_was_compiled(true);
- } else {
- func.ClearCode();
- }
} else {
- bool is_optimized = func.usage_counter() != 0;
- if (is_optimized) {
- // Read the ic data array as the function is an optimized one.
- (*reader->ArrayHandle()) ^= reader->ReadObjectImpl(kAsReference);
- func.set_ic_data_array(*reader->ArrayHandle());
- } else {
- func.ClearICDataArray();
- }
- func.ClearCode();
+ func.ClearICDataArray();
}
+ func.ClearCode();
return func.raw();
} else {
return reader->ReadFunctionId(object_id);
@@ -812,7 +735,7 @@
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
- ASSERT((kind == Snapshot::kScript) || (Snapshot::IsFull(kind)));
+ ASSERT(kind == Snapshot::kScript);
bool is_in_fullsnapshot = false;
bool owner_is_class = false;
if ((kind == Snapshot::kScript) && !Function::IsSignatureFunction(this)) {
@@ -837,7 +760,7 @@
// to be interpreted.
writer->Write<bool>(is_in_fullsnapshot);
- if (Snapshot::IsFull(kind) || !is_in_fullsnapshot) {
+ if (!is_in_fullsnapshot) {
bool is_optimized = Code::IsOptimized(ptr()->code_);
// Write out all the non object fields.
@@ -846,31 +769,19 @@
writer->Write<int16_t>(ptr()->num_fixed_parameters_);
writer->Write<int16_t>(ptr()->num_optional_parameters_);
writer->Write<uint32_t>(ptr()->kind_tag_);
- if (kind == Snapshot::kAppNoJIT) {
- // Omit fields used to support de/reoptimization.
+ if (is_optimized) {
+ writer->Write<int32_t>(FLAG_optimization_counter_threshold);
} else {
- if (is_optimized) {
- writer->Write<int32_t>(FLAG_optimization_counter_threshold);
- } else {
- writer->Write<int32_t>(0);
- }
- writer->Write<int8_t>(ptr()->deoptimization_counter_);
- writer->Write<uint16_t>(ptr()->optimized_instruction_count_);
- writer->Write<uint16_t>(ptr()->optimized_call_site_count_);
+ writer->Write<int32_t>(0);
}
+ writer->Write<int8_t>(ptr()->deoptimization_counter_);
+ writer->Write<uint16_t>(ptr()->optimized_instruction_count_);
+ writer->Write<uint16_t>(ptr()->optimized_call_site_count_);
// Write out all the object pointer fields.
SnapshotWriterVisitor visitor(writer, kAsReference);
visitor.VisitPointers(from(), to_snapshot());
- if (kind == Snapshot::kAppNoJIT) {
- ASSERT(ptr()->ic_data_array_ == Array::null());
- ASSERT((ptr()->code_ == ptr()->unoptimized_code_) ||
- (ptr()->unoptimized_code_ == Code::null()));
- writer->WriteObjectImpl(ptr()->code_, kAsInlinedObject);
- } else if (kind == Snapshot::kAppWithJIT) {
- writer->WriteObjectImpl(ptr()->ic_data_array_, kAsReference);
- writer->WriteObjectImpl(ptr()->unoptimized_code_, kAsInlinedObject);
- } else if (is_optimized) {
+ if (is_optimized) {
// Write out the ic data array as the function is optimized.
writer->WriteObjectImpl(ptr()->ic_data_array_, kAsReference);
}
@@ -886,22 +797,17 @@
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
- ASSERT((kind == Snapshot::kScript) || (Snapshot::IsFull(kind)));
+ ASSERT(kind == Snapshot::kScript);
// Allocate field object.
- Field& field = Field::ZoneHandle(reader->zone(), NEW_OBJECT(Field));
+ Field& field = Field::ZoneHandle(reader->zone(), Field::New());
reader->AddBackRef(object_id, &field, kIsDeserialized);
// Set all non object fields.
- if (kind == Snapshot::kAppNoJIT) {
- field.set_token_pos(TokenPosition::kNoSource);
- ASSERT(!FLAG_use_field_guards);
- } else {
- field.set_token_pos(
- TokenPosition::SnapshotDecode(reader->Read<int32_t>()));
- field.set_guarded_cid(reader->Read<int32_t>());
- field.set_is_nullable(reader->Read<int32_t>());
- }
+ field.set_token_pos(
+ TokenPosition::SnapshotDecode(reader->Read<int32_t>()));
+ field.set_guarded_cid(reader->Read<int32_t>());
+ field.set_is_nullable(reader->Read<int32_t>());
field.set_kind_bits(reader->Read<uint8_t>());
// Set all the object fields.
@@ -929,7 +835,7 @@
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
- ASSERT((kind == Snapshot::kScript) || (Snapshot::IsFull(kind)));
+ ASSERT(kind == Snapshot::kScript);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
@@ -939,11 +845,9 @@
writer->WriteTags(writer->GetObjectTags(this));
// Write out all the non object fields.
- if (kind != Snapshot::kAppNoJIT) {
- writer->Write<int32_t>(ptr()->token_pos_.SnapshotEncode());
- writer->Write<int32_t>(ptr()->guarded_cid_);
- writer->Write<int32_t>(ptr()->is_nullable_);
- }
+ writer->Write<int32_t>(ptr()->token_pos_.SnapshotEncode());
+ writer->Write<int32_t>(ptr()->guarded_cid_);
+ writer->Write<int32_t>(ptr()->is_nullable_);
writer->Write<uint8_t>(ptr()->kind_bits_);
// Write out the name.
@@ -954,11 +858,7 @@
writer->WriteObjectImpl(ptr()->type_, kAsReference);
// Write out the initial static value or field offset.
if (Field::StaticBit::decode(ptr()->kind_bits_)) {
- if (kind == Snapshot::kAppNoJIT) {
- // For precompiled static fields, the value was already reset and
- // initializer_ now contains a Function.
- writer->WriteObjectImpl(ptr()->value_.static_value_, kAsReference);
- } else if (Field::ConstBit::decode(ptr()->kind_bits_)) {
+ if (Field::ConstBit::decode(ptr()->kind_bits_)) {
// Do not reset const fields.
writer->WriteObjectImpl(ptr()->value_.static_value_, kAsReference);
} else {
@@ -969,15 +869,9 @@
writer->WriteObjectImpl(ptr()->value_.offset_, kAsReference);
}
// Write out the initializer function or saved initial value.
- if (kind == Snapshot::kAppNoJIT) {
- writer->WriteObjectImpl(ptr()->initializer_.precompiled_, kAsReference);
- } else {
- writer->WriteObjectImpl(ptr()->initializer_.saved_value_, kAsReference);
- }
- if (kind != Snapshot::kAppNoJIT) {
- // Write out the guarded list length.
- writer->WriteObjectImpl(ptr()->guarded_list_length_, kAsReference);
- }
+ writer->WriteObjectImpl(ptr()->initializer_.saved_value_, kAsReference);
+ // Write out the guarded list length.
+ writer->WriteObjectImpl(ptr()->guarded_list_length_, kAsReference);
}
@@ -990,8 +884,8 @@
ASSERT(kind != Snapshot::kMessage);
// Create the literal token object.
- LiteralToken& literal_token = LiteralToken::ZoneHandle(
- reader->zone(), NEW_OBJECT(LiteralToken));
+ LiteralToken& literal_token = LiteralToken::ZoneHandle(reader->zone(),
+ LiteralToken::New());
reader->AddBackRef(object_id, &literal_token, kIsDeserialized);
// Read the token attributes.
@@ -1036,14 +930,14 @@
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
- ASSERT((kind == Snapshot::kScript) || (Snapshot::IsFull(kind)));
+ ASSERT(kind == Snapshot::kScript);
// Read the length so that we can determine number of tokens to read.
intptr_t len = reader->ReadSmiValue();
// Create the token stream object.
- TokenStream& token_stream = TokenStream::ZoneHandle(
- reader->zone(), NEW_OBJECT_WITH_LEN(TokenStream, len));
+ TokenStream& token_stream = TokenStream::ZoneHandle(reader->zone(),
+ TokenStream::New(len));
reader->AddBackRef(object_id, &token_stream, kIsDeserialized);
// Read the stream of tokens into the TokenStream object for script
@@ -1070,7 +964,7 @@
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
- ASSERT((kind == Snapshot::kScript) || (Snapshot::IsFull(kind)));
+ ASSERT(kind == Snapshot::kScript);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
@@ -1098,10 +992,10 @@
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
- ASSERT((kind == Snapshot::kScript) || (Snapshot::IsFull(kind)));
+ ASSERT(kind == Snapshot::kScript);
// Allocate script object.
- Script& script = Script::ZoneHandle(reader->zone(), NEW_OBJECT(Script));
+ Script& script = Script::ZoneHandle(reader->zone(), Script::New());
reader->AddBackRef(object_id, &script, kIsDeserialized);
script.StoreNonPointer(&script.raw_ptr()->line_offset_,
@@ -1139,7 +1033,7 @@
bool as_reference) {
ASSERT(writer != NULL);
ASSERT(tokens_ != TokenStream::null());
- ASSERT((kind == Snapshot::kScript) || (Snapshot::IsFull(kind)));
+ ASSERT(kind == Snapshot::kScript);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
@@ -1178,7 +1072,7 @@
ASSERT(library.is_in_fullsnapshot());
} else {
// Allocate library object.
- library = NEW_OBJECT(Library);
+ library = Library::New();
// Set all non object fields.
library.StoreNonPointer(&library.raw_ptr()->index_,
@@ -1193,9 +1087,6 @@
reader->Read<bool>());
library.StoreNonPointer(&library.raw_ptr()->debuggable_,
reader->Read<bool>());
- if (Snapshot::IsFull(kind)) {
- is_in_fullsnapshot = true;
- }
library.StoreNonPointer(&library.raw_ptr()->is_in_fullsnapshot_,
is_in_fullsnapshot);
// The native resolver and symbolizer are not serialized.
@@ -1213,13 +1104,9 @@
}
// Initialize cache of resolved names.
const intptr_t kInitialNameCacheSize = 64;
- if (!Snapshot::IsFull(kind)) {
- // The cache of resolved names in library scope is not serialized.
- library.InitResolvedNamesCache(kInitialNameCacheSize);
- library.Register(reader->thread());
- } else {
- library.InitResolvedNamesCache(kInitialNameCacheSize, reader);
- }
+ // The cache of resolved names in library scope is not serialized.
+ library.InitResolvedNamesCache(kInitialNameCacheSize);
+ library.Register(reader->thread());
library.StorePointer(&library.raw_ptr()->exported_names_, Array::null());
// Initialize cache of loaded scripts.
library.StorePointer(&library.raw_ptr()->loaded_scripts_, Array::null());
@@ -1251,7 +1138,7 @@
// Write out library URL so that it can be looked up when reading.
writer->WriteObjectImpl(ptr()->url_, kAsInlinedObject);
} else {
- ASSERT((Snapshot::IsFull(kind)) || !ptr()->is_in_fullsnapshot_);
+ ASSERT(!ptr()->is_in_fullsnapshot_);
// Write out all non object fields.
ASSERT(ptr()->index_ != static_cast<classid_t>(-1));
writer->WriteClassIDValue(ptr()->index_);
@@ -1279,11 +1166,11 @@
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
- ASSERT((kind == Snapshot::kScript) || (Snapshot::IsFull(kind)));
+ ASSERT(kind == Snapshot::kScript);
// Allocate library prefix object.
- LibraryPrefix& prefix = LibraryPrefix::ZoneHandle(
- reader->zone(), NEW_OBJECT(LibraryPrefix));
+ LibraryPrefix& prefix = LibraryPrefix::ZoneHandle(reader->zone(),
+ LibraryPrefix::New());
reader->AddBackRef(object_id, &prefix, kIsDeserialized);
// Set all non object fields.
@@ -1298,10 +1185,6 @@
prefix.raw()->from(),
prefix.raw()->to_snapshot(kind),
kAsReference);
- if (kind == Snapshot::kAppNoJIT) {
- prefix.StorePointer(&prefix.raw_ptr()->imports_,
- Object::empty_array().raw());
- }
prefix.StorePointer(&prefix.raw_ptr()->dependent_code_,
Array::null());
@@ -1314,7 +1197,7 @@
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
- ASSERT((kind == Snapshot::kScript) || (Snapshot::IsFull(kind)));
+ ASSERT(kind == Snapshot::kScript);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
@@ -1340,11 +1223,10 @@
Snapshot::Kind kind,
bool as_reference) {
ASSERT(reader != NULL);
- ASSERT((kind == Snapshot::kScript) || (Snapshot::IsFull(kind)));
+ ASSERT(kind == Snapshot::kScript);
// Allocate Namespace object.
- Namespace& ns = Namespace::ZoneHandle(
- reader->zone(), NEW_OBJECT(Namespace));
+ Namespace& ns = Namespace::ZoneHandle(reader->zone(), Namespace::New());
reader->AddBackRef(object_id, &ns, kIsDeserialized);
// Set all the object fields.
@@ -1359,7 +1241,7 @@
Snapshot::Kind kind,
bool as_reference) {
ASSERT(writer != NULL);
- ASSERT((kind == Snapshot::kScript) || (Snapshot::IsFull(kind)));
+ ASSERT(kind == Snapshot::kScript);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
@@ -1532,7 +1414,7 @@
if (num_vars == 0) {
context ^= reader->object_store()->empty_context();
} else {
- context ^= NEW_OBJECT_WITH_LEN(Context, num_vars);
+ context ^= Context::New(num_vars);
// Set all the object fields.
// TODO(5411462): Need to assert No GC can happen here, even though
@@ -1583,12 +1465,7 @@
bool is_implicit = reader->Read<bool>();
if (is_implicit) {
ContextScope& context_scope = ContextScope::ZoneHandle(reader->zone());
- if (Snapshot::IsFull(kind)) {
- context_scope = reader->NewContextScope(1);
- context_scope.set_is_implicit(true);
- } else {
- context_scope = ContextScope::New(1, true);
- }
+ context_scope = ContextScope::New(1, true);
reader->AddBackRef(object_id, &context_scope, kIsDeserialized);
*reader->TypeHandle() ^= reader->ReadObjectImpl(kAsInlinedObject);
@@ -1602,19 +1479,6 @@
context_scope.SetContextIndexAt(0, 0);
context_scope.SetContextLevelAt(0, 0);
return context_scope.raw();
- } else if (kind == Snapshot::kAppWithJIT) {
- int32_t num_vars = reader->Read<int32_t>();
-
- ContextScope& context_scope = ContextScope::ZoneHandle(reader->zone());
- context_scope = reader->NewContextScope(num_vars);
- context_scope.set_is_implicit(false);
- reader->AddBackRef(object_id, &context_scope, kIsDeserialized);
-
- READ_OBJECT_FIELDS(context_scope,
- context_scope.raw()->from(),
- context_scope.raw()->to(num_vars),
- kAsInlinedObject);
- return context_scope.raw();
}
UNREACHABLE();
return NULL;
@@ -1645,23 +1509,6 @@
writer->WriteObjectImpl(var->type, kAsInlinedObject);
return;
- } else if (kind == Snapshot::kAppWithJIT) {
- // Write out the serialization header value for this object.
- writer->WriteInlinedObjectHeader(object_id);
-
- // Write out the class and tags information.
- writer->WriteVMIsolateObject(kContextScopeCid);
- writer->WriteTags(writer->GetObjectTags(this));
-
- // Write out is_implicit flag for the context scope.
- writer->Write<bool>(false);
- int32_t num_vars = ptr()->num_variables_;
- writer->Write<int32_t>(num_vars);
-
- SnapshotWriterVisitor visitor(writer, kAsInlinedObject);
- visitor.VisitPointers(from(), to(num_vars));
-
- return;
}
UNREACHABLE();
}
@@ -1672,9 +1519,9 @@
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
- ASSERT((kind == Snapshot::kScript) || (Snapshot::IsFull(kind)));
+ ASSERT(kind == Snapshot::kScript);
- ICData& result = ICData::ZoneHandle(reader->zone(), NEW_OBJECT(ICData));
+ ICData& result = ICData::ZoneHandle(reader->zone(), ICData::New());
reader->AddBackRef(object_id, &result, kIsDeserialized);
result.set_deopt_id(reader->Read<int32_t>());
@@ -1688,9 +1535,6 @@
result.raw()->from(),
result.raw()->to_snapshot(kind),
kAsReference);
- if (kind == Snapshot::kAppNoJIT) {
- result.set_owner(Function::Handle(reader->zone()));
- }
return result.raw();
}
@@ -1700,7 +1544,7 @@
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
- ASSERT((kind == Snapshot::kScript) || (Snapshot::IsFull(kind)));
+ ASSERT(kind == Snapshot::kScript);
// Write out the serialization header value for this object.
writer->WriteInlinedObjectHeader(object_id);
@@ -1787,7 +1631,7 @@
// Allocate ApiError object.
ApiError& api_error =
- ApiError::ZoneHandle(reader->zone(), NEW_OBJECT(ApiError));
+ ApiError::ZoneHandle(reader->zone(), ApiError::New());
reader->AddBackRef(object_id, &api_error, kIsDeserialized);
// Set all the object fields.
@@ -1827,7 +1671,7 @@
// Allocate LanguageError object.
LanguageError& language_error =
- LanguageError::ZoneHandle(reader->zone(), NEW_OBJECT(LanguageError));
+ LanguageError::ZoneHandle(reader->zone(), LanguageError::New());
reader->AddBackRef(object_id, &language_error, kIsDeserialized);
// Set all non object fields.
@@ -1875,7 +1719,7 @@
Snapshot::Kind kind,
bool as_reference) {
UnhandledException& result = UnhandledException::ZoneHandle(
- reader->zone(), NEW_OBJECT(UnhandledException));
+ reader->zone(), UnhandledException::New());
reader->AddBackRef(object_id, &result, kIsDeserialized);
// Set all the object fields.
@@ -1931,19 +1775,11 @@
// Create an Instance object or get canonical one if it is a canonical
// constant.
Instance& obj = Instance::ZoneHandle(reader->zone(), Instance::null());
- if (Snapshot::IsFull(kind)) {
- obj = reader->NewInstance();
- // Set the canonical bit.
- if (RawObject::IsCanonical(tags)) {
- obj.SetCanonical();
- }
- } else {
- obj ^= Object::Allocate(kInstanceCid,
- Instance::InstanceSize(),
- HEAP_SPACE(kind));
- if (RawObject::IsCanonical(tags)) {
- obj = obj.CheckAndCanonicalize(reader->thread(), NULL);
- }
+ obj ^= Object::Allocate(kInstanceCid,
+ Instance::InstanceSize(),
+ HEAP_SPACE(kind));
+ if (RawObject::IsCanonical(tags)) {
+ obj = obj.CheckAndCanonicalize(reader->thread(), NULL);
}
reader->AddBackRef(object_id, &obj, kIsDeserialized);
@@ -1987,24 +1823,16 @@
// Create a Mint object or get canonical one if it is a canonical constant.
Mint& mint = Mint::ZoneHandle(reader->zone(), Mint::null());
- if (Snapshot::IsFull(kind)) {
- mint = reader->NewMint(value);
- // Set the canonical bit.
- if (RawObject::IsCanonical(tags)) {
- mint.SetCanonical();
- }
+ // 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.
+ if (RawObject::IsCanonical(tags)) {
+ mint = Mint::NewCanonical(value);
+ ASSERT(mint.IsCanonical());
} else {
- // 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.
- if (RawObject::IsCanonical(tags)) {
- mint = Mint::NewCanonical(value);
- ASSERT(mint.IsCanonical());
- } else {
- mint = Mint::New(value, HEAP_SPACE(kind));
- }
+ mint = Mint::New(value, HEAP_SPACE(kind));
}
reader->AddBackRef(object_id, &mint, kIsDeserialized);
return mint.raw();
@@ -2037,7 +1865,7 @@
ASSERT(reader != NULL);
// Allocate bigint object.
- Bigint& obj = Bigint::ZoneHandle(reader->zone(), NEW_OBJECT(Bigint));
+ Bigint& obj = Bigint::ZoneHandle(reader->zone(), Bigint::New());
reader->AddBackRef(object_id, &obj, kIsDeserialized);
// Set all the object fields.
@@ -2049,14 +1877,9 @@
// When reading a script snapshot or a message snapshot we always have
// to canonicalize the object.
if (RawObject::IsCanonical(tags)) {
- if (Snapshot::IsFull(kind)) {
- // Set the canonical bit.
- obj.SetCanonical();
- } else {
- obj ^= obj.CheckAndCanonicalize(reader->thread(), NULL);
- ASSERT(!obj.IsNull());
- ASSERT(obj.IsCanonical());
- }
+ obj ^= obj.CheckAndCanonicalize(reader->thread(), NULL);
+ ASSERT(!obj.IsNull());
+ ASSERT(obj.IsCanonical());
}
return obj.raw();
}
@@ -2093,23 +1916,15 @@
// Create a Double object or get canonical one if it is a canonical constant.
Double& dbl = Double::ZoneHandle(reader->zone(), Double::null());
- if (Snapshot::IsFull(kind)) {
- dbl = reader->NewDouble(value);
- // Set the canonical bit.
- if (RawObject::IsCanonical(tags)) {
- dbl.SetCanonical();
- }
+ // 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.
+ if (RawObject::IsCanonical(tags)) {
+ dbl = Double::NewCanonical(value);
+ ASSERT(dbl.IsCanonical());
} else {
- // 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.
- if (RawObject::IsCanonical(tags)) {
- dbl = Double::NewCanonical(value);
- ASSERT(dbl.IsCanonical());
- } else {
- dbl = Double::New(value, HEAP_SPACE(kind));
- }
+ dbl = Double::New(value, HEAP_SPACE(kind));
}
reader->AddBackRef(object_id, &dbl, kIsDeserialized);
return dbl.raw();
@@ -2193,28 +2008,10 @@
// Read the length so that we can determine instance size to allocate.
ASSERT(reader != NULL);
intptr_t len = reader->ReadSmiValue();
- intptr_t hash = reader->ReadSmiValue();
String& str_obj = String::ZoneHandle(reader->zone(), String::null());
- if (Snapshot::IsFull(kind)) {
- // 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;
- if (RawObject::IsCanonical(tags)) {
- str_obj.SetCanonical();
- }
- str_obj.SetHash(hash);
- if (len > 0) {
- uint8_t* raw_ptr = CharAddr(str_obj, 0);
- reader->ReadBytes(raw_ptr, len);
- }
- ASSERT((hash == 0) || (String::Hash(str_obj, 0, str_obj.Length()) == hash));
- } else {
- String::ReadFromImpl<OneByteString, uint8_t>(
- reader, &str_obj, len, tags, Symbols::FromLatin1, kind);
- }
+ String::ReadFromImpl<OneByteString, uint8_t>(
+ reader, &str_obj, len, tags, Symbols::FromLatin1, kind);
reader->AddBackRef(object_id, &str_obj, kIsDeserialized);
return raw(str_obj);
}
@@ -2228,28 +2025,10 @@
// Read the length so that we can determine instance size to allocate.
ASSERT(reader != NULL);
intptr_t len = reader->ReadSmiValue();
- intptr_t hash = reader->ReadSmiValue();
String& str_obj = String::ZoneHandle(reader->zone(), String::null());
- if (Snapshot::IsFull(kind)) {
- RawTwoByteString* obj = reader->NewTwoByteString(len);
- str_obj = obj;
- if (RawObject::IsCanonical(tags)) {
- str_obj.SetCanonical();
- }
- str_obj.SetHash(hash);
- NoSafepointScope no_safepoint;
- uint16_t* raw_ptr = (len > 0)? CharAddr(str_obj, 0) : NULL;
- for (intptr_t i = 0; i < len; i++) {
- ASSERT(CharAddr(str_obj, i) == raw_ptr); // Will trigger assertions.
- *raw_ptr = reader->Read<uint16_t>();
- raw_ptr += 1;
- }
- ASSERT(String::Hash(str_obj, 0, str_obj.Length()) == hash);
- } else {
- String::ReadFromImpl<TwoByteString, uint16_t>(
- reader, &str_obj, len, tags, Symbols::FromUTF16, kind);
- }
+ String::ReadFromImpl<TwoByteString, uint16_t>(
+ reader, &str_obj, len, tags, Symbols::FromUTF16, kind);
reader->AddBackRef(object_id, &str_obj, kIsDeserialized);
return raw(str_obj);
}
@@ -2262,7 +2041,6 @@
intptr_t class_id,
intptr_t tags,
RawSmi* length,
- RawSmi* hash,
T* data) {
ASSERT(writer != NULL);
intptr_t len = Smi::Value(length);
@@ -2277,9 +2055,6 @@
// Write out the length field.
writer->Write<RawObject*>(length);
- // Write out the hash field.
- writer->Write<RawObject*>(hash);
-
// Write out the string.
if (len > 0) {
if (class_id == kOneByteStringCid) {
@@ -2303,7 +2078,6 @@
kOneByteStringCid,
writer->GetObjectTags(this),
ptr()->length_,
- ptr()->hash_,
ptr()->data());
}
@@ -2318,7 +2092,6 @@
kTwoByteStringCid,
writer->GetObjectTags(this),
ptr()->length_,
- ptr()->hash_,
ptr()->data());
}
@@ -2356,7 +2129,6 @@
kOneByteStringCid,
writer->GetObjectTags(this),
ptr()->length_,
- ptr()->hash_,
ptr()->external_data_->data());
}
@@ -2372,7 +2144,6 @@
kTwoByteStringCid,
writer->GetObjectTags(this),
ptr()->length_,
- ptr()->hash_,
ptr()->external_data_->data());
}
@@ -2414,7 +2185,7 @@
}
if (array == NULL) {
array = &(Array::ZoneHandle(reader->zone(),
- NEW_OBJECT_WITH_LEN_SPACE(Array, len, kind)));
+ Array::New(len, HEAP_SPACE(kind))));
reader->AddBackRef(object_id, array, state);
}
if (!as_reference) {
@@ -2446,18 +2217,14 @@
if (array == NULL) {
array = &(Array::ZoneHandle(
reader->zone(),
- NEW_OBJECT_WITH_LEN_SPACE(ImmutableArray, len, kind)));
+ ImmutableArray::New(len, HEAP_SPACE(kind))));
reader->AddBackRef(object_id, array, state);
}
if (!as_reference) {
// Read all the individual elements for inlined objects.
reader->ArrayReadFrom(object_id, *array, len, tags);
if (RawObject::IsCanonical(tags)) {
- if (Snapshot::IsFull(kind)) {
- array->SetCanonical();
- } else {
- *array ^= array->CheckAndCanonicalize(reader->thread(), NULL);
- }
+ *array ^= array->CheckAndCanonicalize(reader->thread(), NULL);
}
}
return raw(*array);
@@ -2503,11 +2270,7 @@
// Read the length so that we can determine instance size to allocate.
GrowableObjectArray& array = GrowableObjectArray::ZoneHandle(
reader->zone(), GrowableObjectArray::null());
- if (Snapshot::IsFull(kind)) {
- array = reader->NewGrowableObjectArray();
- } else {
- array = GrowableObjectArray::New(0, HEAP_SPACE(kind));
- }
+ array = GrowableObjectArray::New(0, HEAP_SPACE(kind));
reader->AddBackRef(object_id, &array, kIsDeserialized);
// Read type arguments of growable array object.
@@ -2562,17 +2325,13 @@
LinkedHashMap& map = LinkedHashMap::ZoneHandle(
reader->zone(), LinkedHashMap::null());
- if (Snapshot::IsFull(kind) || kind == Snapshot::kScript) {
+ if (kind == Snapshot::kScript) {
// The immutable maps that seed map literals are not yet VM-internal, so
// we don't reach this.
UNREACHABLE();
} else {
// Since the map might contain itself as a key or value, allocate first.
- if (Snapshot::IsFull(kind)) {
- map = reader->NewLinkedHashMap();
- } else {
- map = LinkedHashMap::NewUninitialized(HEAP_SPACE(kind));
- }
+ map = LinkedHashMap::NewUninitialized(HEAP_SPACE(kind));
}
reader->AddBackRef(object_id, &map, kIsDeserialized);
@@ -2593,9 +2352,7 @@
Utils::RoundUpToPowerOfTwo(used_data),
static_cast<uintptr_t>(LinkedHashMap::kInitialIndexSize));
Array& data = Array::ZoneHandle(reader->zone(),
- NEW_OBJECT_WITH_LEN_SPACE(Array,
- data_size,
- kind));
+ Array::New(data_size, HEAP_SPACE(kind)));
map.SetData(data);
map.SetDeletedKeys(0);
@@ -2620,7 +2377,7 @@
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
- if (Snapshot::IsFull(kind) || kind == Snapshot::kScript) {
+ if (kind == Snapshot::kScript) {
// The immutable maps that seed map literals are not yet VM-internal, so
// we don't reach this.
}
@@ -2682,11 +2439,7 @@
// Create a Float32x4 object.
Float32x4& simd = Float32x4::ZoneHandle(reader->zone(),
Float32x4::null());
- if (Snapshot::IsFull(kind)) {
- simd = reader->NewFloat32x4(value0, value1, value2, value3);
- } else {
- simd = Float32x4::New(value0, value1, value2, value3, HEAP_SPACE(kind));
- }
+ simd = Float32x4::New(value0, value1, value2, value3, HEAP_SPACE(kind));
reader->AddBackRef(object_id, &simd, kIsDeserialized);
return simd.raw();
}
@@ -2727,12 +2480,7 @@
// Create a Float32x4 object.
Int32x4& simd = Int32x4::ZoneHandle(reader->zone(), Int32x4::null());
-
- if (Snapshot::IsFull(kind)) {
- simd = reader->NewInt32x4(value0, value1, value2, value3);
- } else {
- simd = Int32x4::New(value0, value1, value2, value3, HEAP_SPACE(kind));
- }
+ simd = Int32x4::New(value0, value1, value2, value3, HEAP_SPACE(kind));
reader->AddBackRef(object_id, &simd, kIsDeserialized);
return simd.raw();
}
@@ -2772,11 +2520,7 @@
// Create a Float64x2 object.
Float64x2& simd = Float64x2::ZoneHandle(reader->zone(),
Float64x2::null());
- if (Snapshot::IsFull(kind)) {
- simd = reader->NewFloat64x2(value0, value1);
- } else {
- simd = Float64x2::New(value0, value1, HEAP_SPACE(kind));
- }
+ simd = Float64x2::New(value0, value1, HEAP_SPACE(kind));
reader->AddBackRef(object_id, &simd, kIsDeserialized);
return simd.raw();
}
@@ -2816,9 +2560,8 @@
intptr_t cid = RawObject::ClassIdTag::decode(tags);
intptr_t len = reader->ReadSmiValue();
- TypedData& result = TypedData::ZoneHandle(reader->zone(),
- (Snapshot::IsFull(kind)) ? reader->NewTypedData(cid, len)
- : TypedData::New(cid, len, HEAP_SPACE(kind)));
+ TypedData& result = TypedData::ZoneHandle(
+ reader->zone(), TypedData::New(cid, len, HEAP_SPACE(kind)));
reader->AddBackRef(object_id, &result, kIsDeserialized);
// Setup the array elements.
@@ -2866,14 +2609,9 @@
// When reading a script snapshot or a message snapshot we always have
// to canonicalize the object.
if (RawObject::IsCanonical(tags)) {
- if (Snapshot::IsFull(kind)) {
- // Set the canonical bit.
- result.SetCanonical();
- } else {
- result ^= result.CheckAndCanonicalize(reader->thread(), NULL);
- ASSERT(!result.IsNull());
- ASSERT(result.IsCanonical());
- }
+ result ^= result.CheckAndCanonicalize(reader->thread(), NULL);
+ ASSERT(!result.IsNull());
+ ASSERT(result.IsCanonical());
}
return result.raw();
}
@@ -3129,21 +2867,6 @@
intptr_t tags,
Snapshot::Kind kind,
bool as_reference) {
- if (Snapshot::IsFull(kind)) {
- Stacktrace& result = Stacktrace::ZoneHandle(reader->zone(),
- reader->NewStacktrace());
- reader->AddBackRef(object_id, &result, kIsDeserialized);
-
- bool expand_inlined = reader->Read<bool>();
- result.set_expand_inlined(expand_inlined);
-
- // Set all the object fields.
- READ_OBJECT_FIELDS(result,
- result.raw()->from(), result.raw()->to(),
- kAsReference);
-
- return result.raw();
- }
UNREACHABLE(); // Stacktraces are not sent in a snapshot.
return Stacktrace::null();
}
@@ -3153,29 +2876,10 @@
intptr_t object_id,
Snapshot::Kind kind,
bool as_reference) {
- if (Snapshot::IsFull(kind)) {
- ASSERT(writer != NULL);
- ASSERT(this == Isolate::Current()->object_store()->
- preallocated_stack_trace());
-
- // Write out the serialization header value for this object.
- writer->WriteInlinedObjectHeader(object_id);
-
- // Write out the class and tags information.
- writer->WriteIndexedObject(kStacktraceCid);
- writer->WriteTags(writer->GetObjectTags(this));
-
- writer->Write(ptr()->expand_inlined_);
-
- // Write out all the object pointer fields.
- SnapshotWriterVisitor visitor(writer, kAsReference);
- visitor.VisitPointers(from(), to());
- } else {
- // Stacktraces are not allowed in other snapshot forms.
- writer->SetWriteException(Exceptions::kArgument,
- "Illegal argument in isolate message"
- " : (object is a stacktrace)");
- }
+ ASSERT(kind == Snapshot::kMessage);
+ writer->SetWriteException(Exceptions::kArgument,
+ "Illegal argument in isolate message"
+ " : (object is a stacktrace)");
}
@@ -3187,7 +2891,7 @@
ASSERT(reader != NULL);
// Allocate RegExp object.
- RegExp& regex = RegExp::ZoneHandle(reader->zone(), NEW_OBJECT(RegExp));
+ RegExp& regex = RegExp::ZoneHandle(reader->zone(), RegExp::New());
reader->AddBackRef(object_id, ®ex, kIsDeserialized);
// Read and Set all the other fields.
@@ -3244,8 +2948,8 @@
ASSERT(reader != NULL);
// Allocate the weak property object.
- WeakProperty& weak_property = WeakProperty::ZoneHandle(
- reader->zone(), NEW_OBJECT(WeakProperty));
+ WeakProperty& weak_property = WeakProperty::ZoneHandle(reader->zone(),
+ WeakProperty::New());
reader->AddBackRef(object_id, &weak_property, kIsDeserialized);
// Set all the object fields.
diff --git a/runtime/vm/runtime_entry_list.h b/runtime/vm/runtime_entry_list.h
index 60e46a0..a63f9bb 100644
--- a/runtime/vm/runtime_entry_list.h
+++ b/runtime/vm/runtime_entry_list.h
@@ -33,6 +33,7 @@
V(OptimizeInvokedFunction) \
V(TraceICCall) \
V(PatchStaticCall) \
+ V(RangeError) \
V(ReThrow) \
V(StackOverflow) \
V(Throw) \
diff --git a/runtime/vm/safepoint.cc b/runtime/vm/safepoint.cc
index 6cbd0f7..7f5d92d 100644
--- a/runtime/vm/safepoint.cc
+++ b/runtime/vm/safepoint.cc
@@ -41,12 +41,14 @@
: isolate_(isolate),
safepoint_lock_(new Monitor()),
number_threads_not_at_safepoint_(0),
- safepoint_in_progress_(false) {
+ safepoint_operation_count_(0),
+ owner_(NULL) {
}
SafepointHandler::~SafepointHandler() {
- ASSERT(safepoint_in_progress_ == false);
+ ASSERT(owner_ == NULL);
+ ASSERT(safepoint_operation_count_ == 0);
delete safepoint_lock_;
safepoint_lock_ = NULL;
isolate_ = NULL;
@@ -63,12 +65,19 @@
// Now check to see if a safepoint operation is already in progress
// for this isolate, block if an operation is in progress.
- while (safepoint_in_progress()) {
+ while (SafepointInProgress()) {
+ // If we are recursively invoking a Safepoint operation then we
+ // just increment the count and return, otherwise we wait for the
+ // safepoint operation to be done.
+ if (owner_ == T) {
+ increment_safepoint_operation_count();
+ return;
+ }
sl.WaitWithSafepointCheck(T);
}
- // Set safepoint in progress by this thread.
- set_safepoint_in_progress(true);
+ // Set safepoint in progress state by this thread.
+ SetSafepointInProgress(T);
// Go over the active thread list and ensure that all threads active
// in the isolate reach a safepoint.
@@ -101,9 +110,13 @@
Monitor::WaitResult retval = sl.Wait(1000);
if (retval == Monitor::kTimedOut) {
num_attempts += 1;
- OS::Print("Attempt:%" Pd " waiting for %d threads to check in\n",
- num_attempts,
- number_threads_not_at_safepoint_);
+ if (num_attempts > 10) {
+ // We have been waiting too long, start logging this as we might
+ // have an issue where a thread is not checking in for a safepoint.
+ OS::Print("Attempt:%" Pd " waiting for %d threads to check in\n",
+ num_attempts,
+ number_threads_not_at_safepoint_);
+ }
}
}
}
@@ -114,6 +127,14 @@
// First resume all the threads which are blocked for the safepoint
// operation.
MonitorLocker sl(threads_lock());
+
+ // First check if we are in a recursive safepoint operation, in that case
+ // we just decrement safepoint_operation_count and return.
+ ASSERT(SafepointInProgress());
+ if (safepoint_operation_count() > 1) {
+ decrement_safepoint_operation_count();
+ return;
+ }
Thread* current = isolate()->thread_registry()->active_list();
while (current != NULL) {
MonitorLocker tl(current->thread_lock());
@@ -127,10 +148,10 @@
}
current = current->next();
}
- // Now set the safepoint_in_progress_ flag to false and notify all threads
+ // Now reset the safepoint_in_progress_ state and notify all threads
// that are waiting to enter the isolate or waiting to start another
// safepoint operation.
- set_safepoint_in_progress(false);
+ ResetSafepointInProgress(T);
sl.NotifyAll();
}
diff --git a/runtime/vm/safepoint.h b/runtime/vm/safepoint.h
index 58afb49..15c2c98 100644
--- a/runtime/vm/safepoint.h
+++ b/runtime/vm/safepoint.h
@@ -33,21 +33,45 @@
void EnterSafepointUsingLock(Thread* T);
void ExitSafepointUsingLock(Thread* T);
- void SafepointThreads(Thread* T);
- void ResumeThreads(Thread* T);
-
void BlockForSafepoint(Thread* T);
private:
+ void SafepointThreads(Thread* T);
+ void ResumeThreads(Thread* T);
+
Isolate* isolate() const { return isolate_; }
Monitor* threads_lock() const { return isolate_->threads_lock(); }
- bool safepoint_in_progress() const {
+ bool SafepointInProgress() const {
ASSERT(threads_lock()->IsOwnedByCurrentThread());
- return safepoint_in_progress_;
+ return ((safepoint_operation_count_ > 0) && (owner_ != NULL));
}
- void set_safepoint_in_progress(bool value) {
+ void SetSafepointInProgress(Thread* T) {
ASSERT(threads_lock()->IsOwnedByCurrentThread());
- safepoint_in_progress_ = value;
+ ASSERT(owner_ == NULL);
+ ASSERT(safepoint_operation_count_ == 0);
+ safepoint_operation_count_ = 1;
+ owner_ = T;
+ }
+ void ResetSafepointInProgress(Thread* T) {
+ ASSERT(threads_lock()->IsOwnedByCurrentThread());
+ ASSERT(owner_ == T);
+ ASSERT(safepoint_operation_count_ == 1);
+ safepoint_operation_count_ = 0;
+ owner_ = NULL;
+ }
+ int32_t safepoint_operation_count() const {
+ ASSERT(threads_lock()->IsOwnedByCurrentThread());
+ return safepoint_operation_count_;
+ }
+ void increment_safepoint_operation_count() {
+ ASSERT(threads_lock()->IsOwnedByCurrentThread());
+ ASSERT(safepoint_operation_count_ < kMaxInt32);
+ safepoint_operation_count_ += 1;
+ }
+ void decrement_safepoint_operation_count() {
+ ASSERT(threads_lock()->IsOwnedByCurrentThread());
+ ASSERT(safepoint_operation_count_ > 0);
+ safepoint_operation_count_ -= 1;
}
Isolate* isolate_;
@@ -57,8 +81,14 @@
Monitor* safepoint_lock_;
int32_t number_threads_not_at_safepoint_;
- // Flag to indicate if a safepoint operation is currently in progress.
- bool safepoint_in_progress_;
+ // Count that indicates if a safepoint operation is currently in progress
+ // and also tracks the number of recursive safepoint operations on the
+ // same thread.
+ int32_t safepoint_operation_count_;
+
+ // If a safepoint operation is currently in progress, this field contains
+ // the thread that initiated the safepoint operation, otherwise it is NULL.
+ Thread* owner_;
friend class Isolate;
friend class SafepointOperationScope;
diff --git a/runtime/vm/scavenger.cc b/runtime/vm/scavenger.cc
index d1bfd3f..cb028ce 100644
--- a/runtime/vm/scavenger.cc
+++ b/runtime/vm/scavenger.cc
@@ -124,14 +124,14 @@
new_addr = ForwardedAddr(header);
} else {
intptr_t size = raw_obj->Size();
- intptr_t cid = raw_obj->GetClassId();
- ClassTable* class_table = isolate()->class_table();
+ NOT_IN_PRODUCT(intptr_t cid = raw_obj->GetClassId());
+ NOT_IN_PRODUCT(ClassTable* class_table = isolate()->class_table());
// Check whether object should be promoted.
if (scavenger_->survivor_end_ <= raw_addr) {
// Not a survivor of a previous scavenge. Just copy the object into the
// to space.
new_addr = scavenger_->TryAllocate(size);
- class_table->UpdateLiveNew(cid, size);
+ NOT_IN_PRODUCT(class_table->UpdateLiveNew(cid, size));
} else {
// TODO(iposva): Experiment with less aggressive promotion. For example
// a coin toss determines if an object is promoted or whether it should
@@ -146,11 +146,11 @@
// be traversed later.
scavenger_->PushToPromotedStack(new_addr);
bytes_promoted_ += size;
- class_table->UpdateAllocatedOld(cid, size);
+ NOT_IN_PRODUCT(class_table->UpdateAllocatedOld(cid, size));
} else {
// Promotion did not succeed. Copy into the to space instead.
new_addr = scavenger_->TryAllocate(size);
- class_table->UpdateLiveNew(cid, size);
+ NOT_IN_PRODUCT(class_table->UpdateLiveNew(cid, size));
}
}
// During a scavenge we always succeed to at least copy all of the
@@ -487,6 +487,7 @@
void Scavenger::IterateObjectIdTable(Isolate* isolate,
ScavengerVisitor* visitor) {
+#ifndef PRODUCT
if (!FLAG_support_service) {
return;
}
@@ -497,6 +498,7 @@
return;
}
ring->VisitPointers(visitor);
+#endif // !PRODUCT
}
@@ -858,6 +860,7 @@
}
+#ifndef PRODUCT
void Scavenger::PrintToJSONObject(JSONObject* object) const {
if (!FLAG_support_service) {
return;
@@ -885,6 +888,7 @@
space.AddProperty64("external", ExternalInWords() * kWordSize);
space.AddProperty("time", MicrosecondsToSeconds(gc_time_micros()));
}
+#endif // !PRODUCT
void Scavenger::AllocateExternal(intptr_t size) {
diff --git a/runtime/vm/scavenger.h b/runtime/vm/scavenger.h
index 5e7dcb1..8fce1a4 100644
--- a/runtime/vm/scavenger.h
+++ b/runtime/vm/scavenger.h
@@ -204,7 +204,9 @@
return collections_;
}
+#ifndef PRODUCT
void PrintToJSONObject(JSONObject* object) const;
+#endif // !PRODUCT
void AllocateExternal(intptr_t size);
void FreeExternal(intptr_t size);
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index e209d3b..ccc5309 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -1339,12 +1339,13 @@
static bool GetStack(Thread* thread, JSONStream* js) {
- if (!thread->isolate()->compilation_allowed()) {
+ Isolate* isolate = thread->isolate();
+ if (isolate->debugger() == NULL) {
js->PrintError(kFeatureDisabled,
- "Cannot get stack when running a precompiled program.");
+ "Cannot get stack when debugger disabled.");
return true;
}
- Isolate* isolate = thread->isolate();
+ ASSERT(isolate->compilation_allowed());
DebuggerStackTrace* stack = isolate->debugger()->StackTrace();
// Do we want the complete script object and complete local variable objects?
// This is true for dump requests.
diff --git a/runtime/vm/service_event.cc b/runtime/vm/service_event.cc
index 94af480..3ff1e1b 100644
--- a/runtime/vm/service_event.cc
+++ b/runtime/vm/service_event.cc
@@ -23,6 +23,8 @@
extension_rpc_(NULL),
exception_(NULL),
reload_error_(NULL),
+ spawn_token_(NULL),
+ spawn_error_(NULL),
at_async_jump_(false),
inspectee_(NULL),
gc_stats_(NULL),
@@ -69,6 +71,8 @@
return "ServiceExtensionAdded";
case kIsolateReload:
return "IsolateReload";
+ case kIsolateSpawn:
+ return "IsolateSpawn";
case kPauseStart:
return "PauseStart";
case kPauseExit:
@@ -122,6 +126,7 @@
case kIsolateExit:
case kIsolateUpdate:
case kIsolateReload:
+ case kIsolateSpawn:
case kServiceExtensionAdded:
return &Service::isolate_stream;
@@ -183,6 +188,16 @@
jsobj.AddProperty("reloadError", *(reload_error()));
}
}
+ if (kind() == kIsolateSpawn) {
+ ASSERT(spawn_token() != NULL);
+ jsobj.AddPropertyStr("spawnToken", *(spawn_token()));
+ if (spawn_error_ == NULL) {
+ jsobj.AddProperty("status", "success");
+ } else {
+ jsobj.AddProperty("status", "failure");
+ jsobj.AddPropertyStr("spawnError", *(spawn_error()));
+ }
+ }
if (kind() == kServiceExtensionAdded) {
ASSERT(extension_rpc_ != NULL);
jsobj.AddProperty("extensionRPC", extension_rpc_->ToCString());
diff --git a/runtime/vm/service_event.h b/runtime/vm/service_event.h
index d6bc92e..cd48844 100644
--- a/runtime/vm/service_event.h
+++ b/runtime/vm/service_event.h
@@ -29,6 +29,7 @@
kIsolateExit, // Isolate has exited
kIsolateUpdate, // Isolate identity information has changed
kIsolateReload, // Result of a reload request
+ kIsolateSpawn, // Result of an isolate spawn request
kServiceExtensionAdded, // A service extension was registered
kPauseStart, // --pause-isolates-on-start
@@ -158,6 +159,24 @@
reload_error_ = error;
}
+ const String* spawn_token() const {
+ ASSERT(kind_ == kIsolateSpawn);
+ return spawn_token_;
+ }
+ void set_spawn_token(const String* error) {
+ ASSERT(kind_ == kIsolateSpawn);
+ spawn_token_ = error;
+ }
+
+ const String* spawn_error() const {
+ ASSERT(kind_ == kIsolateSpawn);
+ return spawn_error_;
+ }
+ void set_spawn_error(const String* error) {
+ ASSERT(kind_ == kIsolateSpawn);
+ spawn_error_ = error;
+ }
+
bool at_async_jump() const {
return at_async_jump_;
}
@@ -232,6 +251,8 @@
const String* extension_rpc_;
const Object* exception_;
const Error* reload_error_;
+ const String* spawn_token_;
+ const String* spawn_error_;
bool at_async_jump_;
const Object* inspectee_;
const Heap::GCStats* gc_stats_;
diff --git a/runtime/vm/service_isolate.cc b/runtime/vm/service_isolate.cc
index e85a5c0..19ccf68 100644
--- a/runtime/vm/service_isolate.cc
+++ b/runtime/vm/service_isolate.cc
@@ -23,8 +23,6 @@
namespace dart {
-DECLARE_FLAG(bool, shutdown);
-
#define Z (T->zone())
@@ -462,9 +460,6 @@
void ServiceIsolate::KillServiceIsolate() {
- if (!FLAG_shutdown) {
- return;
- }
{
MonitorLocker ml(monitor_);
shutting_down_ = true;
diff --git a/runtime/vm/signal_handler_android.cc b/runtime/vm/signal_handler_android.cc
index 64670de..8812c63 100644
--- a/runtime/vm/signal_handler_android.cc
+++ b/runtime/vm/signal_handler_android.cc
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
#include "vm/globals.h"
+#include "vm/instructions.h"
#include "vm/simulator.h"
#include "vm/signal_handler.h"
#if defined(TARGET_OS_ANDROID)
@@ -65,20 +66,11 @@
uintptr_t SignalHandler::GetDartStackPointer(const mcontext_t& mcontext) {
- uintptr_t sp = 0;
-
-#if defined(HOST_ARCH_IA32)
- sp = static_cast<uintptr_t>(mcontext.gregs[REG_ESP]);
-#elif defined(HOST_ARCH_X64)
- sp = static_cast<uintptr_t>(mcontext.gregs[REG_RSP]);
-#elif defined(HOST_ARCH_ARM)
- sp = static_cast<uintptr_t>(mcontext.arm_sp);
-#elif defined(HOST_ARCH_ARM64)
- sp = static_cast<uintptr_t>(mcontext.regs[19]);
+#if defined(TARGET_ARCH_ARM64) && !defined(USING_SIMULATOR)
+ return static_cast<uintptr_t>(mcontext.regs[SPREG]);
#else
-#error Unsupported architecture.
-#endif // HOST_ARCH_...
- return sp;
+ return GetCStackPointer(mcontext);
+#endif
}
diff --git a/runtime/vm/signal_handler_linux.cc b/runtime/vm/signal_handler_linux.cc
index 1df46f0..b867c00 100644
--- a/runtime/vm/signal_handler_linux.cc
+++ b/runtime/vm/signal_handler_linux.cc
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
#include "vm/globals.h"
+#include "vm/instructions.h"
#include "vm/simulator.h"
#include "vm/signal_handler.h"
#if defined(TARGET_OS_LINUX)
@@ -72,7 +73,7 @@
uintptr_t SignalHandler::GetDartStackPointer(const mcontext_t& mcontext) {
#if defined(TARGET_ARCH_ARM64) && !defined(USING_SIMULATOR)
- return static_cast<uintptr_t>(mcontext.regs[19]);
+ return static_cast<uintptr_t>(mcontext.regs[SPREG]);
#else
return GetCStackPointer(mcontext);
#endif
diff --git a/runtime/vm/signal_handler_macos.cc b/runtime/vm/signal_handler_macos.cc
index bfcc42c..75c9c09 100644
--- a/runtime/vm/signal_handler_macos.cc
+++ b/runtime/vm/signal_handler_macos.cc
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
#include "vm/globals.h"
+#include "vm/instructions.h"
#include "vm/simulator.h"
#include "vm/signal_handler.h"
#if defined(TARGET_OS_MACOS)
@@ -68,7 +69,7 @@
uintptr_t SignalHandler::GetDartStackPointer(const mcontext_t& mcontext) {
#if defined(TARGET_ARCH_ARM64) && !defined(USING_SIMULATOR)
- return static_cast<uintptr_t>(mcontext->__ss.__x[19]);
+ return static_cast<uintptr_t>(mcontext->__ss.__x[SPREG]);
#else
return GetCStackPointer(mcontext);
#endif
diff --git a/runtime/vm/simulator_dbc.cc b/runtime/vm/simulator_dbc.cc
index b1c648d..416dda5 100644
--- a/runtime/vm/simulator_dbc.cc
+++ b/runtime/vm/simulator_dbc.cc
@@ -1374,7 +1374,7 @@
}
{
- BYTECODE(StaticCall, A_D);
+ BYTECODE(IndirectStaticCall, A_D);
// Check if single stepping.
if (thread->isolate()->single_step()) {
@@ -1386,6 +1386,12 @@
// Invoke target function.
{
const uint16_t argc = rA;
+ // Lookup the funciton in the ICData.
+ RawObject* ic_data_obj = SP[0];
+ RawICData* ic_data = RAW_CAST(ICData, ic_data_obj);
+ RawArray* cache = ic_data->ptr()->ic_data_->ptr();
+ SP[0] = cache->data()[ICData::TargetIndexFor(
+ ic_data->ptr()->state_bits_ & 0x3)];
RawObject** call_base = SP - argc;
RawObject** call_top = SP; // *SP contains function
argdesc = static_cast<RawArray*>(LOAD_CONSTANT(rD));
@@ -1396,6 +1402,16 @@
}
{
+ BYTECODE(StaticCall, A_D);
+ const uint16_t argc = rA;
+ RawObject** call_base = SP - argc;
+ RawObject** call_top = SP; // *SP contains function
+ argdesc = static_cast<RawArray*>(LOAD_CONSTANT(rD));
+ Invoke(thread, call_base, call_top, &pp, &pc, &FP, &SP);
+ DISPATCH();
+ }
+
+ {
BYTECODE(InstanceCall1, A_D);
// Check if single stepping.
@@ -1694,6 +1710,316 @@
DISPATCH();
}
+ {
+ BYTECODE(ShrImm, A_B_C);
+ const uint8_t shift = rC;
+ const intptr_t lhs = reinterpret_cast<intptr_t>(FP[rB]) >> kSmiTagSize;
+ *reinterpret_cast<intptr_t*>(&FP[rA]) = (lhs >> shift) << kSmiTagSize;
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(Min, A_B_C);
+ const intptr_t lhs = reinterpret_cast<intptr_t>(FP[rB]);
+ const intptr_t rhs = reinterpret_cast<intptr_t>(FP[rC]);
+ FP[rA] = reinterpret_cast<RawObject*>((lhs < rhs) ? lhs : rhs);
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(Max, A_B_C);
+ const intptr_t lhs = reinterpret_cast<intptr_t>(FP[rB]);
+ const intptr_t rhs = reinterpret_cast<intptr_t>(FP[rC]);
+ FP[rA] = reinterpret_cast<RawObject*>((lhs > rhs) ? lhs : rhs);
+ DISPATCH();
+ }
+
+#if defined(ARCH_IS_64_BIT)
+ {
+ BYTECODE(WriteIntoDouble, A_D);
+ const double value = bit_cast<double, RawObject*>(FP[rD]);
+ RawDouble* box = RAW_CAST(Double, *SP--);
+ box->ptr()->value_ = value;
+ FP[rA] = box;
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(UnboxDouble, A_D);
+ const RawDouble* box = RAW_CAST(Double, FP[rD]);
+ FP[rA] = bit_cast<RawObject*, double>(box->ptr()->value_);
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(CheckedUnboxDouble, A_D);
+ const intptr_t box_cid = SimulatorHelpers::GetClassId(FP[rD]);
+ if (box_cid == kSmiCid) {
+ const intptr_t value = reinterpret_cast<intptr_t>(FP[rD]) >> kSmiTagSize;
+ const double result = static_cast<double>(value);
+ FP[rA] = bit_cast<RawObject*, double>(result);
+ pc++;
+ } else if (box_cid == kDoubleCid) {
+ const RawDouble* box = RAW_CAST(Double, FP[rD]);
+ FP[rA] = bit_cast<RawObject*, double>(box->ptr()->value_);
+ pc++;
+ }
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(DoubleToSmi, A_D);
+ const double value = bit_cast<double, RawObject*>(FP[rD]);
+ if (!isnan(value)) {
+ const intptr_t result = static_cast<intptr_t>(value);
+ if ((result <= Smi::kMaxValue) && (result >= Smi::kMinValue)) {
+ FP[rA] = reinterpret_cast<RawObject*>(result << kSmiTagSize);
+ pc++;
+ }
+ }
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(SmiToDouble, A_D);
+ const intptr_t value = reinterpret_cast<intptr_t>(FP[rD]) >> kSmiTagSize;
+ const double result = static_cast<double>(value);
+ FP[rA] = bit_cast<RawObject*, double>(result);
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(DAdd, A_B_C);
+ const double lhs = bit_cast<double, RawObject*>(FP[rB]);
+ const double rhs = bit_cast<double, RawObject*>(FP[rC]);
+ FP[rA] = bit_cast<RawObject*, double>(lhs + rhs);
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(DSub, A_B_C);
+ const double lhs = bit_cast<double, RawObject*>(FP[rB]);
+ const double rhs = bit_cast<double, RawObject*>(FP[rC]);
+ FP[rA] = bit_cast<RawObject*, double>(lhs - rhs);
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(DMul, A_B_C);
+ const double lhs = bit_cast<double, RawObject*>(FP[rB]);
+ const double rhs = bit_cast<double, RawObject*>(FP[rC]);
+ FP[rA] = bit_cast<RawObject*, double>(lhs * rhs);
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(DDiv, A_B_C);
+ const double lhs = bit_cast<double, RawObject*>(FP[rB]);
+ const double rhs = bit_cast<double, RawObject*>(FP[rC]);
+ const double result = lhs / rhs;
+ FP[rA] = bit_cast<RawObject*, double>(result);
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(DNeg, A_D);
+ const double value = bit_cast<double, RawObject*>(FP[rD]);
+ FP[rA] = bit_cast<RawObject*, double>(-value);
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(DSqrt, A_D);
+ const double value = bit_cast<double, RawObject*>(FP[rD]);
+ FP[rA] = bit_cast<RawObject*, double>(sqrt(value));
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(DSin, A_D);
+ const double value = bit_cast<double, RawObject*>(FP[rD]);
+ FP[rA] = bit_cast<RawObject*, double>(sin(value));
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(DCos, A_D);
+ const double value = bit_cast<double, RawObject*>(FP[rD]);
+ FP[rA] = bit_cast<RawObject*, double>(cos(value));
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(DPow, A_B_C);
+ const double lhs = bit_cast<double, RawObject*>(FP[rB]);
+ const double rhs = bit_cast<double, RawObject*>(FP[rC]);
+ const double result = pow(lhs, rhs);
+ FP[rA] = bit_cast<RawObject*, double>(result);
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(DMod, A_B_C);
+ const double lhs = bit_cast<double, RawObject*>(FP[rB]);
+ const double rhs = bit_cast<double, RawObject*>(FP[rC]);
+ const double result = DartModulo(lhs, rhs);
+ FP[rA] = bit_cast<RawObject*, double>(result);
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(DMin, A_B_C);
+ const double lhs = bit_cast<double, RawObject*>(FP[rB]);
+ const double rhs = bit_cast<double, RawObject*>(FP[rC]);
+ FP[rA] = bit_cast<RawObject*, double>(fmin(lhs, rhs));
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(DMax, A_B_C);
+ const double lhs = bit_cast<double, RawObject*>(FP[rB]);
+ const double rhs = bit_cast<double, RawObject*>(FP[rC]);
+ FP[rA] = bit_cast<RawObject*, double>(fmax(lhs, rhs));
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(LoadFloat64Indexed, A_B_C);
+ ASSERT(RawObject::IsTypedDataClassId(FP[rB]->GetClassId()));
+ RawTypedData* array = reinterpret_cast<RawTypedData*>(FP[rB]);
+ RawSmi* index = RAW_CAST(Smi, FP[rC]);
+ ASSERT(SimulatorHelpers::CheckIndex(index, array->ptr()->length_));
+ double* data = reinterpret_cast<double*>(array->ptr()->data());
+ FP[rA] = bit_cast<RawObject*, double>(data[Smi::Value(index)]);
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(StoreFloat64Indexed, A_B_C);
+ ASSERT(RawObject::IsTypedDataClassId(FP[rA]->GetClassId()));
+ RawTypedData* array = reinterpret_cast<RawTypedData*>(FP[rA]);
+ RawSmi* index = RAW_CAST(Smi, FP[rB]);
+ ASSERT(SimulatorHelpers::CheckIndex(index, array->ptr()->length_));
+ double* data = reinterpret_cast<double*>(array->ptr()->data());
+ data[Smi::Value(index)] = bit_cast<double, RawObject*>(FP[rC]);
+ DISPATCH();
+ }
+#else // defined(ARCH_IS_64_BIT)
+ {
+ BYTECODE(WriteIntoDouble, A_D);
+ UNIMPLEMENTED();
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(UnboxDouble, A_D);
+ UNIMPLEMENTED();
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(CheckedUnboxDouble, A_D);
+ UNIMPLEMENTED();
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(DoubleToSmi, A_D);
+ UNREACHABLE();
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(SmiToDouble, A_D);
+ UNIMPLEMENTED();
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(DAdd, A_B_C);
+ UNIMPLEMENTED();
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(DSub, A_B_C);
+ UNIMPLEMENTED();
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(DMul, A_B_C);
+ UNIMPLEMENTED();
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(DDiv, A_B_C);
+ UNIMPLEMENTED();
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(DNeg, A_D);
+ UNIMPLEMENTED();
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(DSqrt, A_D);
+ UNREACHABLE();
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(DSin, A_D);
+ UNREACHABLE();
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(DCos, A_D);
+ UNREACHABLE();
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(DPow, A_B_C);
+ UNREACHABLE();
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(DMod, A_B_C);
+ UNREACHABLE();
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(DMin, A_B_C);
+ UNREACHABLE();
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(DMax, A_B_C);
+ UNREACHABLE();
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(LoadFloat64Indexed, A_B_C);
+ UNREACHABLE();
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(StoreFloat64Indexed, A_B_C);
+ UNREACHABLE();
+ DISPATCH();
+ }
+#endif // defined(ARCH_IS_64_BIT)
+
// Return and return like instructions (Instrinsic).
{
RawObject* result; // result to return to the caller.
@@ -2058,6 +2384,27 @@
}
{
+ BYTECODE(TestCids, A_D);
+ const intptr_t cid = SimulatorHelpers::GetClassId(FP[rA]);
+ const intptr_t num_cases = rD;
+ for (intptr_t i = 0; i < num_cases; i++) {
+ ASSERT(Bytecode::DecodeOpcode(pc[i]) == Bytecode::kNop);
+ intptr_t test_target = Bytecode::DecodeA(pc[i]);
+ intptr_t test_cid = Bytecode::DecodeD(pc[i]);
+ if (cid == test_cid) {
+ if (test_target != 0) {
+ pc += 1; // Match true.
+ } else {
+ pc += 2; // Match false.
+ }
+ break;
+ }
+ }
+ pc += num_cases;
+ DISPATCH();
+ }
+
+ {
BYTECODE(CheckSmi, 0);
intptr_t obj = reinterpret_cast<intptr_t>(FP[rA]);
if ((obj & kSmiTagMask) == kSmiTag) {
@@ -2067,8 +2414,20 @@
}
{
+ BYTECODE(CheckEitherNonSmi, A_D);
+ const intptr_t obj1 = reinterpret_cast<intptr_t>(FP[rA]);
+ const intptr_t obj2 = reinterpret_cast<intptr_t>(FP[rD]);
+ const intptr_t tag = (obj1 | obj2) & kSmiTagMask;
+ if (tag != kSmiTag) {
+ pc++;
+ }
+ DISPATCH();
+ }
+
+ {
BYTECODE(CheckClassId, A_D);
- const intptr_t actual_cid = SimulatorHelpers::GetClassId(FP[rA]);
+ const intptr_t actual_cid =
+ reinterpret_cast<intptr_t>(FP[rA]) >> kSmiTagSize;
const intptr_t desired_cid = rD;
pc += (actual_cid == desired_cid) ? 1 : 0;
DISPATCH();
@@ -2194,6 +2553,172 @@
}
{
+ BYTECODE(IfLe, A_D);
+ const intptr_t lhs = reinterpret_cast<intptr_t>(FP[rA]);
+ const intptr_t rhs = reinterpret_cast<intptr_t>(FP[rD]);
+ if (lhs > rhs) {
+ pc++;
+ }
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(IfLt, A_D);
+ const intptr_t lhs = reinterpret_cast<intptr_t>(FP[rA]);
+ const intptr_t rhs = reinterpret_cast<intptr_t>(FP[rD]);
+ if (lhs >= rhs) {
+ pc++;
+ }
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(IfGe, A_D);
+ const intptr_t lhs = reinterpret_cast<intptr_t>(FP[rA]);
+ const intptr_t rhs = reinterpret_cast<intptr_t>(FP[rD]);
+ if (lhs < rhs) {
+ pc++;
+ }
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(IfGt, A_D);
+ const intptr_t lhs = reinterpret_cast<intptr_t>(FP[rA]);
+ const intptr_t rhs = reinterpret_cast<intptr_t>(FP[rD]);
+ if (lhs <= rhs) {
+ pc++;
+ }
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(IfULe, A_D);
+ const uintptr_t lhs = reinterpret_cast<uintptr_t>(FP[rA]);
+ const uintptr_t rhs = reinterpret_cast<uintptr_t>(FP[rD]);
+ if (lhs > rhs) {
+ pc++;
+ }
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(IfULt, A_D);
+ const uintptr_t lhs = reinterpret_cast<uintptr_t>(FP[rA]);
+ const uintptr_t rhs = reinterpret_cast<uintptr_t>(FP[rD]);
+ if (lhs >= rhs) {
+ pc++;
+ }
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(IfUGe, A_D);
+ const uintptr_t lhs = reinterpret_cast<uintptr_t>(FP[rA]);
+ const uintptr_t rhs = reinterpret_cast<uintptr_t>(FP[rD]);
+ if (lhs < rhs) {
+ pc++;
+ }
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(IfUGt, A_D);
+ const uintptr_t lhs = reinterpret_cast<uintptr_t>(FP[rA]);
+ const uintptr_t rhs = reinterpret_cast<uintptr_t>(FP[rD]);
+ if (lhs <= rhs) {
+ pc++;
+ }
+ DISPATCH();
+ }
+
+#if defined(ARCH_IS_64_BIT)
+ {
+ BYTECODE(IfDEq, A_D);
+ const double lhs = bit_cast<double, RawObject*>(FP[rA]);
+ const double rhs = bit_cast<double, RawObject*>(FP[rD]);
+ pc += (lhs == rhs) ? 0 : 1;
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(IfDNe, A_D);
+ const double lhs = bit_cast<double, RawObject*>(FP[rA]);
+ const double rhs = bit_cast<double, RawObject*>(FP[rD]);
+ pc += (lhs != rhs) ? 0 : 1;
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(IfDLe, A_D);
+ const double lhs = bit_cast<double, RawObject*>(FP[rA]);
+ const double rhs = bit_cast<double, RawObject*>(FP[rD]);
+ pc += (lhs <= rhs) ? 0 : 1;
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(IfDLt, A_D);
+ const double lhs = bit_cast<double, RawObject*>(FP[rA]);
+ const double rhs = bit_cast<double, RawObject*>(FP[rD]);
+ pc += (lhs < rhs) ? 0 : 1;
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(IfDGe, A_D);
+ const double lhs = bit_cast<double, RawObject*>(FP[rA]);
+ const double rhs = bit_cast<double, RawObject*>(FP[rD]);
+ pc += (lhs >= rhs) ? 0 : 1;
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(IfDGt, A_D);
+ const double lhs = bit_cast<double, RawObject*>(FP[rA]);
+ const double rhs = bit_cast<double, RawObject*>(FP[rD]);
+ pc += (lhs > rhs) ? 0 : 1;
+ DISPATCH();
+ }
+#else // defined(ARCH_IS_64_BIT)
+ {
+ BYTECODE(IfDEq, A_D);
+ UNREACHABLE();
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(IfDNe, A_D);
+ UNREACHABLE();
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(IfDLe, A_D);
+ UNREACHABLE();
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(IfDLt, A_D);
+ UNREACHABLE();
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(IfDGe, A_D);
+ UNREACHABLE();
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(IfDGt, A_D);
+ UNREACHABLE();
+ DISPATCH();
+ }
+#endif // defined(ARCH_IS_64_BIT)
+
+ {
BYTECODE(IfEqStrictNum, A_D);
RawObject* lhs = FP[rA];
RawObject* rhs = FP[rD];
@@ -2254,11 +2779,9 @@
{
BYTECODE(StoreIndexedTOS, 0);
SP -= 3;
- RawArray* array = static_cast<RawArray*>(SP[1]);
- RawSmi* index = static_cast<RawSmi*>(SP[2]);
+ RawArray* array = RAW_CAST(Array, SP[1]);
+ RawSmi* index = RAW_CAST(Smi, SP[2]);
RawObject* value = SP[3];
- ASSERT(array->GetClassId() == kArrayCid);
- ASSERT(!index->IsHeapObject());
ASSERT(SimulatorHelpers::CheckIndex(index, array->ptr()->length_));
array->StorePointer(array->ptr()->data() + Smi::Value(index), value);
DISPATCH();
@@ -2266,17 +2789,42 @@
{
BYTECODE(StoreIndexed, A_B_C);
- RawArray* array = static_cast<RawArray*>(FP[rA]);
- RawSmi* index = static_cast<RawSmi*>(FP[rB]);
+ RawArray* array = RAW_CAST(Array, FP[rA]);
+ RawSmi* index = RAW_CAST(Smi, FP[rB]);
RawObject* value = FP[rC];
- ASSERT(array->GetClassId() == kArrayCid);
- ASSERT(!index->IsHeapObject());
ASSERT(SimulatorHelpers::CheckIndex(index, array->ptr()->length_));
array->StorePointer(array->ptr()->data() + Smi::Value(index), value);
DISPATCH();
}
{
+ BYTECODE(LoadIndexed, A_B_C);
+ RawArray* array = RAW_CAST(Array, FP[rB]);
+ RawSmi* index = RAW_CAST(Smi, FP[rC]);
+ ASSERT(SimulatorHelpers::CheckIndex(index, array->ptr()->length_));
+ FP[rA] = array->ptr()->data()[Smi::Value(index)];
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(LoadOneByteStringIndexed, A_B_C);
+ RawOneByteString* array = RAW_CAST(OneByteString, FP[rB]);
+ RawSmi* index = RAW_CAST(Smi, FP[rC]);
+ ASSERT(SimulatorHelpers::CheckIndex(index, array->ptr()->length_));
+ FP[rA] = Smi::New(array->ptr()->data()[Smi::Value(index)]);
+ DISPATCH();
+ }
+
+ {
+ BYTECODE(LoadTwoByteStringIndexed, A_B_C);
+ RawTwoByteString* array = RAW_CAST(TwoByteString, FP[rB]);
+ RawSmi* index = RAW_CAST(Smi, FP[rC]);
+ ASSERT(SimulatorHelpers::CheckIndex(index, array->ptr()->length_));
+ FP[rA] = Smi::New(array->ptr()->data()[Smi::Value(index)]);
+ DISPATCH();
+ }
+
+ {
BYTECODE(Deopt, A_D);
const bool is_lazy = rD == 0;
@@ -2422,6 +2970,7 @@
return 0;
}
+
void Simulator::Longjmp(uword pc,
uword sp,
uword fp,
@@ -2459,5 +3008,4 @@
} // namespace dart
-
#endif // defined TARGET_ARCH_DBC
diff --git a/runtime/vm/snapshot.cc b/runtime/vm/snapshot.cc
index 4195995..6a4371f 100644
--- a/runtime/vm/snapshot.cc
+++ b/runtime/vm/snapshot.cc
@@ -166,14 +166,10 @@
SnapshotReader::SnapshotReader(
const uint8_t* buffer,
intptr_t size,
- const uint8_t* instructions_buffer,
- const uint8_t* data_buffer,
Snapshot::Kind kind,
ZoneGrowableArray<BackRefNode>* backward_refs,
Thread* thread)
: BaseReader(buffer, size),
- instructions_buffer_(instructions_buffer),
- data_buffer_(data_buffer),
kind_(kind),
thread_(thread),
zone_(thread->zone()),
@@ -192,19 +188,12 @@
stream_(TokenStream::Handle(zone_)),
data_(ExternalTypedData::Handle(zone_)),
typed_data_(TypedData::Handle(zone_)),
- code_(Code::Handle(zone_)),
function_(Function::Handle(zone_)),
- megamorphic_cache_(MegamorphicCache::Handle(zone_)),
error_(UnhandledException::Handle(zone_)),
max_vm_isolate_object_id_(
(Snapshot::IsFull(kind)) ?
Object::vm_isolate_snapshot_object_table().Length() : 0),
- backward_references_(backward_refs),
- instructions_reader_(NULL) {
- if (instructions_buffer != NULL) {
- instructions_reader_ =
- new InstructionsReader(instructions_buffer, data_buffer);
- }
+ backward_references_(backward_refs) {
}
@@ -220,9 +209,7 @@
(*backward_references_)[i].set_state(kIsDeserialized);
}
}
- if (!Snapshot::IsFull(kind())) {
- ProcessDeferredCanonicalizations();
- }
+ ProcessDeferredCanonicalizations();
return obj.raw();
} else {
// An error occurred while reading, return the error object.
@@ -480,11 +467,7 @@
instance_size = cls_.instance_size();
ASSERT(instance_size > 0);
// Allocate the instance and read in all the fields for the object.
- if (Snapshot::IsFull(kind_)) {
- *result ^= AllocateUninitialized(cls_.id(), instance_size);
- } else {
- *result ^= Object::Allocate(cls_.id(), instance_size, HEAP_SPACE(kind_));
- }
+ *result ^= Object::Allocate(cls_.id(), instance_size, HEAP_SPACE(kind_));
} else {
cls_ ^= ReadObjectImpl(kAsInlinedObject);
ASSERT(!cls_.IsNull());
@@ -522,21 +505,9 @@
// snapshot (kFull, kScript) with asserts.
offset += kWordSize;
}
- if (Snapshot::IsFull(kind_)) {
- // 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;
- }
- }
if (RawObject::IsCanonical(tags)) {
- if (Snapshot::IsFull(kind_)) {
- result->SetCanonical();
- } else {
- *result = result->CheckAndCanonicalize(thread(), NULL);
- ASSERT(!result->IsNull());
- }
+ *result = result->CheckAndCanonicalize(thread(), NULL);
+ ASSERT(!result->IsNull());
}
}
return result->raw();
@@ -681,418 +652,16 @@
}
-#define ALLOC_NEW_OBJECT_WITH_LEN(type, length) \
- ASSERT(Snapshot::IsFull(kind_)); \
- 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)); \
- return obj; \
-
-
-RawArray* SnapshotReader::NewArray(intptr_t len) {
- ALLOC_NEW_OBJECT_WITH_LEN(Array, len);
-}
-
-
-RawImmutableArray* SnapshotReader::NewImmutableArray(intptr_t len) {
- ALLOC_NEW_OBJECT_WITH_LEN(ImmutableArray, len);
-}
-
-
-RawOneByteString* SnapshotReader::NewOneByteString(intptr_t len) {
- ALLOC_NEW_OBJECT_WITH_LEN(OneByteString, len);
-}
-
-
-RawTwoByteString* SnapshotReader::NewTwoByteString(intptr_t len) {
- ALLOC_NEW_OBJECT_WITH_LEN(TwoByteString, len);
-}
-
-
-RawTypeArguments* SnapshotReader::NewTypeArguments(intptr_t len) {
- ALLOC_NEW_OBJECT_WITH_LEN(TypeArguments, len);
-}
-
-
-RawObjectPool* SnapshotReader::NewObjectPool(intptr_t len) {
- ASSERT(Snapshot::IsFull(kind_));
- ASSERT_NO_SAFEPOINT_SCOPE();
- RawObjectPool* obj = reinterpret_cast<RawObjectPool*>(
- AllocateUninitialized(kObjectPoolCid, ObjectPool::InstanceSize(len)));
- obj->ptr()->length_ = len;
- return obj;
-}
-
-
-RawLocalVarDescriptors* SnapshotReader::NewLocalVarDescriptors(
- intptr_t num_entries) {
- ASSERT(Snapshot::IsFull(kind_));
- ASSERT_NO_SAFEPOINT_SCOPE();
- RawLocalVarDescriptors* obj = reinterpret_cast<RawLocalVarDescriptors*>(
- AllocateUninitialized(kLocalVarDescriptorsCid,
- LocalVarDescriptors::InstanceSize(num_entries)));
- obj->ptr()->num_entries_ = num_entries;
- return obj;
-}
-
-
-RawExceptionHandlers* SnapshotReader::NewExceptionHandlers(
- intptr_t num_entries) {
- ASSERT(Snapshot::IsFull(kind_));
- ASSERT_NO_SAFEPOINT_SCOPE();
- RawExceptionHandlers* obj = reinterpret_cast<RawExceptionHandlers*>(
- AllocateUninitialized(kExceptionHandlersCid,
- ExceptionHandlers::InstanceSize(num_entries)));
- obj->ptr()->num_entries_ = num_entries;
- return obj;
-}
-
-
-RawPcDescriptors* SnapshotReader::NewPcDescriptors(intptr_t len) {
- ASSERT(Snapshot::IsFull(kind_));
- ASSERT_NO_SAFEPOINT_SCOPE();
- RawPcDescriptors* obj = reinterpret_cast<RawPcDescriptors*>(
- AllocateUninitialized(kPcDescriptorsCid,
- PcDescriptors::InstanceSize(len)));
- obj->ptr()->length_ = len;
- return obj;
-}
-
-
-RawCodeSourceMap* SnapshotReader::NewCodeSourceMap(intptr_t len) {
- ASSERT(Snapshot::IsFull(kind_));
- ASSERT_NO_SAFEPOINT_SCOPE();
- RawCodeSourceMap* obj = reinterpret_cast<RawCodeSourceMap*>(
- AllocateUninitialized(kCodeSourceMapCid,
- CodeSourceMap::InstanceSize(len)));
- obj->ptr()->length_ = len;
- return obj;
-}
-
-
-RawStackmap* SnapshotReader::NewStackmap(intptr_t len) {
- ASSERT(Snapshot::IsFull(kind_));
- ASSERT_NO_SAFEPOINT_SCOPE();
- RawStackmap* obj = reinterpret_cast<RawStackmap*>(
- AllocateUninitialized(kStackmapCid, Stackmap::InstanceSize(len)));
- obj->ptr()->length_ = len;
- return obj;
-}
-
-
-RawContextScope* SnapshotReader::NewContextScope(intptr_t num_variables) {
- ASSERT(Snapshot::IsFull(kind_));
- ASSERT_NO_SAFEPOINT_SCOPE();
- RawContextScope* obj = reinterpret_cast<RawContextScope*>(
- AllocateUninitialized(kContextScopeCid,
- ContextScope::InstanceSize(num_variables)));
- obj->ptr()->num_variables_ = num_variables;
- return obj;
-}
-
-
-RawCode* SnapshotReader::NewCode(intptr_t pointer_offsets_length) {
- ASSERT(pointer_offsets_length == 0);
- ASSERT(Snapshot::IsFull(kind_));
- ASSERT_NO_SAFEPOINT_SCOPE();
- RawCode* obj = reinterpret_cast<RawCode*>(
- AllocateUninitialized(kCodeCid, Code::InstanceSize(0)));
- return obj;
-}
-
-
-RawTokenStream* SnapshotReader::NewTokenStream(intptr_t len) {
- ASSERT(Snapshot::IsFull(kind_));
- ASSERT_NO_SAFEPOINT_SCOPE();
- stream_ = reinterpret_cast<RawTokenStream*>(
- AllocateUninitialized(kTokenStreamCid, TokenStream::InstanceSize()));
- uint8_t* array = const_cast<uint8_t*>(CurrentBufferAddress());
- ASSERT(array != NULL);
- Advance(len);
- data_ = reinterpret_cast<RawExternalTypedData*>(
- AllocateUninitialized(kExternalTypedDataUint8ArrayCid,
- ExternalTypedData::InstanceSize()));
- data_.SetData(array);
- data_.SetLength(len);
- stream_.SetStream(data_);
- return stream_.raw();
-}
-
-
-RawContext* SnapshotReader::NewContext(intptr_t num_variables) {
- ASSERT(Snapshot::IsFull(kind_));
- ASSERT_NO_SAFEPOINT_SCOPE();
- RawContext* obj = reinterpret_cast<RawContext*>(
- AllocateUninitialized(kContextCid, Context::InstanceSize(num_variables)));
- obj->ptr()->num_variables_ = num_variables;
- return obj;
-}
-
-
-RawClass* SnapshotReader::NewClass(intptr_t class_id) {
- ASSERT(Snapshot::IsFull(kind_));
- ASSERT_NO_SAFEPOINT_SCOPE();
- if (class_id < kNumPredefinedCids) {
- ASSERT((class_id >= kInstanceCid) &&
- (class_id <= kNullCid));
- return isolate()->class_table()->At(class_id);
- }
- RawClass* obj = reinterpret_cast<RawClass*>(
- AllocateUninitialized(kClassCid, Class::InstanceSize()));
- Instance fake;
- obj->ptr()->handle_vtable_ = fake.vtable();
- cls_ = obj;
- cls_.set_id(class_id);
- isolate()->RegisterClassAt(class_id, cls_);
- return cls_.raw();
-}
-
-
-RawInstance* SnapshotReader::NewInstance() {
- ASSERT(Snapshot::IsFull(kind_));
- ASSERT_NO_SAFEPOINT_SCOPE();
- RawInstance* obj = reinterpret_cast<RawInstance*>(
- AllocateUninitialized(kInstanceCid, Instance::InstanceSize()));
- return obj;
-}
-
-
-RawMint* SnapshotReader::NewMint(int64_t value) {
- ASSERT(Snapshot::IsFull(kind_));
- ASSERT_NO_SAFEPOINT_SCOPE();
- RawMint* obj = reinterpret_cast<RawMint*>(
- AllocateUninitialized(kMintCid, Mint::InstanceSize()));
- obj->ptr()->value_ = value;
- return obj;
-}
-
-
-RawDouble* SnapshotReader::NewDouble(double value) {
- ASSERT(Snapshot::IsFull(kind_));
- ASSERT_NO_SAFEPOINT_SCOPE();
- RawDouble* obj = reinterpret_cast<RawDouble*>(
- AllocateUninitialized(kDoubleCid, Double::InstanceSize()));
- obj->ptr()->value_ = value;
- return obj;
-}
-
-
-RawTypedData* SnapshotReader::NewTypedData(intptr_t class_id, intptr_t len) {
- ASSERT(Snapshot::IsFull(kind_));
- ASSERT_NO_SAFEPOINT_SCOPE();
- const intptr_t lengthInBytes = len * TypedData::ElementSizeInBytes(class_id);
- RawTypedData* obj = reinterpret_cast<RawTypedData*>(
- AllocateUninitialized(class_id, TypedData::InstanceSize(lengthInBytes)));
- obj->StoreSmi(&(obj->ptr()->length_), Smi::New(len));
- return obj;
-}
-
-
-#define ALLOC_NEW_OBJECT(type) \
- ASSERT(Snapshot::IsFull(kind_)); \
- ASSERT_NO_SAFEPOINT_SCOPE(); \
- return reinterpret_cast<Raw##type*>( \
- AllocateUninitialized(k##type##Cid, type::InstanceSize())); \
-
-
-RawBigint* SnapshotReader::NewBigint() {
- ALLOC_NEW_OBJECT(Bigint);
-}
-
-
-RawUnresolvedClass* SnapshotReader::NewUnresolvedClass() {
- ALLOC_NEW_OBJECT(UnresolvedClass);
-}
-
-
-RawType* SnapshotReader::NewType() {
- ALLOC_NEW_OBJECT(Type);
-}
-
-
-RawTypeRef* SnapshotReader::NewTypeRef() {
- ALLOC_NEW_OBJECT(TypeRef);
-}
-
-
-RawTypeParameter* SnapshotReader::NewTypeParameter() {
- ALLOC_NEW_OBJECT(TypeParameter);
-}
-
-
-RawBoundedType* SnapshotReader::NewBoundedType() {
- ALLOC_NEW_OBJECT(BoundedType);
-}
-
-
-RawMixinAppType* SnapshotReader::NewMixinAppType() {
- ALLOC_NEW_OBJECT(MixinAppType);
-}
-
-
-RawPatchClass* SnapshotReader::NewPatchClass() {
- ALLOC_NEW_OBJECT(PatchClass);
-}
-
-
-RawClosure* SnapshotReader::NewClosure() {
- ALLOC_NEW_OBJECT(Closure);
-}
-
-
-RawClosureData* SnapshotReader::NewClosureData() {
- ALLOC_NEW_OBJECT(ClosureData);
-}
-
-
-RawRedirectionData* SnapshotReader::NewRedirectionData() {
- ALLOC_NEW_OBJECT(RedirectionData);
-}
-
-
-RawFunction* SnapshotReader::NewFunction() {
- ALLOC_NEW_OBJECT(Function);
-}
-
-
-RawICData* SnapshotReader::NewICData() {
- ALLOC_NEW_OBJECT(ICData);
-}
-
-
-RawLinkedHashMap* SnapshotReader::NewLinkedHashMap() {
- ALLOC_NEW_OBJECT(LinkedHashMap);
-}
-
-
-RawMegamorphicCache* SnapshotReader::NewMegamorphicCache() {
- ALLOC_NEW_OBJECT(MegamorphicCache);
-}
-
-
-RawSubtypeTestCache* SnapshotReader::NewSubtypeTestCache() {
- ALLOC_NEW_OBJECT(SubtypeTestCache);
-}
-
-
-RawField* SnapshotReader::NewField() {
- ALLOC_NEW_OBJECT(Field);
-}
-
-
-RawLibrary* SnapshotReader::NewLibrary() {
- ALLOC_NEW_OBJECT(Library);
-}
-
-
-RawLibraryPrefix* SnapshotReader::NewLibraryPrefix() {
- ALLOC_NEW_OBJECT(LibraryPrefix);
-}
-
-
-RawNamespace* SnapshotReader::NewNamespace() {
- ALLOC_NEW_OBJECT(Namespace);
-}
-
-
-RawScript* SnapshotReader::NewScript() {
- ALLOC_NEW_OBJECT(Script);
-}
-
-
-RawLiteralToken* SnapshotReader::NewLiteralToken() {
- ALLOC_NEW_OBJECT(LiteralToken);
-}
-
-
-RawGrowableObjectArray* SnapshotReader::NewGrowableObjectArray() {
- ALLOC_NEW_OBJECT(GrowableObjectArray);
-}
-
-
-RawWeakProperty* SnapshotReader::NewWeakProperty() {
- ALLOC_NEW_OBJECT(WeakProperty);
-}
-
-
-RawRegExp* SnapshotReader::NewRegExp() {
- ALLOC_NEW_OBJECT(RegExp);
-}
-
-
-RawFloat32x4* SnapshotReader::NewFloat32x4(float v0, float v1, float v2,
- float v3) {
- ASSERT(Snapshot::IsFull(kind_));
- ASSERT_NO_SAFEPOINT_SCOPE();
- RawFloat32x4* obj = reinterpret_cast<RawFloat32x4*>(
- AllocateUninitialized(kFloat32x4Cid, Float32x4::InstanceSize()));
- obj->ptr()->value_[0] = v0;
- obj->ptr()->value_[1] = v1;
- obj->ptr()->value_[2] = v2;
- obj->ptr()->value_[3] = v3;
- return obj;
-}
-
-
-RawInt32x4* SnapshotReader::NewInt32x4(uint32_t v0, uint32_t v1, uint32_t v2,
- uint32_t v3) {
- ASSERT(Snapshot::IsFull(kind_));
- ASSERT_NO_SAFEPOINT_SCOPE();
- RawInt32x4* obj = reinterpret_cast<RawInt32x4*>(
- AllocateUninitialized(kInt32x4Cid, Int32x4::InstanceSize()));
- obj->ptr()->value_[0] = v0;
- obj->ptr()->value_[1] = v1;
- obj->ptr()->value_[2] = v2;
- obj->ptr()->value_[3] = v3;
- return obj;
-}
-
-
-RawFloat64x2* SnapshotReader::NewFloat64x2(double v0, double v1) {
- ASSERT(Snapshot::IsFull(kind_));
- ASSERT_NO_SAFEPOINT_SCOPE();
- RawFloat64x2* obj = reinterpret_cast<RawFloat64x2*>(
- AllocateUninitialized(kFloat64x2Cid, Float64x2::InstanceSize()));
- obj->ptr()->value_[0] = v0;
- obj->ptr()->value_[1] = v1;
- return obj;
-}
-
-
-RawApiError* SnapshotReader::NewApiError() {
- ALLOC_NEW_OBJECT(ApiError);
-}
-
-
-RawLanguageError* SnapshotReader::NewLanguageError() {
- ALLOC_NEW_OBJECT(LanguageError);
-}
-
-
-RawUnhandledException* SnapshotReader::NewUnhandledException() {
- ALLOC_NEW_OBJECT(UnhandledException);
-}
-
-
RawObject* SnapshotReader::NewInteger(int64_t value) {
ASSERT((value & kSmiTagMask) == kSmiTag);
value = value >> kSmiTagShift;
if (Smi::IsValid(value)) {
return Smi::New(static_cast<intptr_t>(value));
}
- if (Snapshot::IsFull(kind_)) {
- return NewMint(value);
- }
return Mint::NewCanonical(value);
}
-RawStacktrace* SnapshotReader::NewStacktrace() {
- ALLOC_NEW_OBJECT(Stacktrace);
-}
-
-
int32_t InstructionsWriter::GetOffsetFor(RawInstructions* instructions,
RawCode* code) {
#if defined(PRODUCT)
@@ -1422,34 +991,6 @@
}
-RawObject* SnapshotReader::AllocateUninitialized(intptr_t class_id,
- intptr_t size) {
- ASSERT_NO_SAFEPOINT_SCOPE();
- ASSERT(Utils::IsAligned(size, kObjectAlignment));
-
- uword address =
- old_space()->TryAllocateDataBumpLocked(size, PageSpace::kForceGrowth);
- if (address == 0) {
- // Use the preallocated out of memory exception to avoid calling
- // into dart code or allocating any code.
- // We do a longjmp at this point to unwind out of the entire
- // read part and return the error object back.
- const UnhandledException& error = UnhandledException::Handle(
- object_store()->preallocated_unhandled_exception());
- thread()->long_jump_base()->Jump(1, error);
- }
-
- RawObject* raw_obj = reinterpret_cast<RawObject*>(address + kHeapObjectTag);
- uword tags = 0;
- ASSERT(class_id != kIllegalCid);
- tags = RawObject::ClassIdTag::update(class_id, tags);
- tags = RawObject::SizeTag::update(size, tags);
- tags = RawObject::VMHeapObjectTag::update(is_vm_isolate(), tags);
- raw_obj->ptr()->tags_ = tags;
- return raw_obj;
-}
-
-
#define READ_VM_SINGLETON_OBJ(id, obj) \
if (object_id == id) { \
return obj; \
@@ -1520,10 +1061,8 @@
if (IsObjectStoreClassId(class_id)) {
return isolate()->class_table()->At(class_id); // get singleton class.
}
- if (!Snapshot::IsFull(kind_)) {
- if (IsObjectStoreTypeId(object_id)) {
- return GetType(object_store(), object_id); // return type obj.
- }
+ if (IsObjectStoreTypeId(object_id)) {
+ return GetType(object_store(), object_id); // return type obj.
}
ASSERT(object_id >= kMaxPredefinedObjectIds);
intptr_t index = (object_id - kMaxPredefinedObjectIds);
@@ -1538,7 +1077,7 @@
void SnapshotReader::AddPatchRecord(intptr_t object_id,
intptr_t patch_object_id,
intptr_t patch_offset) {
- if (patch_object_id != kInvalidPatchIndex && !Snapshot::IsFull(kind())) {
+ if (patch_object_id != kInvalidPatchIndex) {
ASSERT(object_id >= kMaxPredefinedObjectIds);
intptr_t index = (object_id - kMaxPredefinedObjectIds);
ASSERT(index >= max_vm_isolate_object_id_);
@@ -1623,8 +1162,6 @@
Thread* thread)
: SnapshotReader(buffer,
size,
- NULL, /* instructions_buffer */
- NULL, /* data_buffer */
Snapshot::kScript,
new ZoneGrowableArray<BackRefNode>(kNumInitialReferences),
thread) {
@@ -1641,8 +1178,6 @@
Thread* thread)
: SnapshotReader(buffer,
size,
- NULL, /* instructions_buffer */
- NULL, /* data_buffer */
Snapshot::kMessage,
new ZoneGrowableArray<BackRefNode>(kNumInitialReferences),
thread) {
@@ -1660,21 +1195,16 @@
ReAlloc alloc,
intptr_t initial_size,
ForwardList* forward_list,
- InstructionsWriter* instructions_writer,
- bool can_send_any_object,
- bool writing_vm_isolate)
+ bool can_send_any_object)
: BaseWriter(buffer, alloc, initial_size),
thread_(thread),
kind_(kind),
object_store_(isolate()->object_store()),
class_table_(isolate()->class_table()),
forward_list_(forward_list),
- instructions_writer_(instructions_writer),
exception_type_(Exceptions::kNone),
exception_msg_(NULL),
- unmarked_objects_(false),
- can_send_any_object_(can_send_any_object),
- writing_vm_isolate_(writing_vm_isolate) {
+ can_send_any_object_(can_send_any_object) {
ASSERT(forward_list_ != NULL);
}
@@ -1766,47 +1296,25 @@
}
}
- if (writing_vm_isolate_) {
- // When we are writing the VM isolate snapshot, write out the object
- // itself instead of a VM object id.
- return false;
- }
-
- if (Snapshot::IsFull(kind())) {
- // Check it is a predefined symbol in the VM isolate.
- id = Symbols::LookupPredefinedSymbol(rawobj);
- if (id != kInvalidIndex) {
- WriteVMIsolateObject(id);
- return true;
- }
-
- // Check if it is an object from the vm isolate snapshot object table.
- id = FindVmSnapshotObject(rawobj);
- if (id != kInvalidIndex) {
- WriteIndexedObject(id);
- return true;
- }
+ // In the case of script snapshots or for messages we do not use
+ // the index into the vm isolate snapshot object table, instead we
+ // explicitly write the object out.
+ intptr_t object_id = forward_list_->FindObject(rawobj);
+ if (object_id != -1) {
+ WriteIndexedObject(object_id);
+ return true;
} else {
- // In the case of script snapshots or for messages we do not use
- // the index into the vm isolate snapshot object table, instead we
- // explicitly write the object out.
- intptr_t object_id = forward_list_->FindObject(rawobj);
- if (object_id != -1) {
- WriteIndexedObject(object_id);
- return true;
- } else {
- switch (id) {
- VM_OBJECT_CLASS_LIST(VM_OBJECT_WRITE)
- case kTypedDataUint32ArrayCid: {
- object_id = forward_list_->AddObject(zone(), rawobj, kIsSerialized);
- RawTypedData* raw_obj = reinterpret_cast<RawTypedData*>(rawobj);
- raw_obj->WriteTo(this, object_id, kind(), false);
- return true;
- }
- default:
- OS::Print("class id = %" Pd "\n", id);
- break;
+ switch (id) {
+ VM_OBJECT_CLASS_LIST(VM_OBJECT_WRITE)
+ case kTypedDataUint32ArrayCid: {
+ object_id = forward_list_->AddObject(zone(), rawobj, kIsSerialized);
+ RawTypedData* raw_obj = reinterpret_cast<RawTypedData*>(rawobj);
+ raw_obj->WriteTo(this, object_id, kind(), false);
+ return true;
}
+ default:
+ OS::Print("class id = %" Pd "\n", id);
+ break;
}
}
@@ -1930,34 +1438,32 @@
// Check if it is a code object in that case just write a Null object
// as we do not want code objects in the snapshot.
- if (cid == kCodeCid && !Snapshot::IncludesCode(kind_)) {
+ if (cid == kCodeCid) {
WriteVMIsolateObject(kNullObject);
return true;
}
// Check if classes are not being serialized and it is preinitialized type
// or a predefined internal VM class in the object store.
- if (!Snapshot::IsFull(kind_)) {
- // Check if it is an internal VM class which is in the object store.
- if (cid == kClassCid) {
- RawClass* raw_class = reinterpret_cast<RawClass*>(rawobj);
- intptr_t class_id = raw_class->ptr()->id_;
- if (IsObjectStoreClassId(class_id)) {
- intptr_t object_id = ObjectIdFromClassId(class_id);
- WriteIndexedObject(object_id);
- return true;
- }
- }
-
- // Now check it is a preinitialized type object.
- RawType* raw_type = reinterpret_cast<RawType*>(rawobj);
- intptr_t index = GetTypeIndex(object_store(), raw_type);
- if (index != kInvalidIndex) {
- WriteIndexedObject(index);
+ // Check if it is an internal VM class which is in the object store.
+ if (cid == kClassCid) {
+ RawClass* raw_class = reinterpret_cast<RawClass*>(rawobj);
+ intptr_t class_id = raw_class->ptr()->id_;
+ if (IsObjectStoreClassId(class_id)) {
+ intptr_t object_id = ObjectIdFromClassId(class_id);
+ WriteIndexedObject(object_id);
return true;
}
}
+ // Now check it is a preinitialized type object.
+ RawType* raw_type = reinterpret_cast<RawType*>(rawobj);
+ intptr_t index = GetTypeIndex(object_store(), raw_type);
+ if (index != kInvalidIndex) {
+ WriteIndexedObject(index);
+ return true;
+ }
+
return false;
}
@@ -2358,9 +1864,7 @@
alloc,
kInitialSize,
&forward_list_,
- NULL, /* instructions_writer */
- true, /* can_send_any_object */
- false /* writing_vm_isolate */),
+ true /* can_send_any_object */),
forward_list_(thread(), kMaxPredefinedObjectIds) {
ASSERT(buffer != NULL);
ASSERT(alloc != NULL);
@@ -2414,9 +1918,7 @@
alloc,
kInitialSize,
&forward_list_,
- NULL, /* instructions_writer */
- can_send_any_object,
- false /* writing_vm_isolate */),
+ can_send_any_object),
forward_list_(thread(), kMaxPredefinedObjectIds) {
ASSERT(buffer != NULL);
ASSERT(alloc != NULL);
diff --git a/runtime/vm/snapshot.h b/runtime/vm/snapshot.h
index 1d8f585..a2f8197 100644
--- a/runtime/vm/snapshot.h
+++ b/runtime/vm/snapshot.h
@@ -412,9 +412,7 @@
TokenStream* StreamHandle() { return &stream_; }
ExternalTypedData* DataHandle() { return &data_; }
TypedData* TypedDataHandle() { return &typed_data_; }
- Code* CodeHandle() { return &code_; }
Function* FunctionHandle() { return &function_; }
- MegamorphicCache* MegamorphicCacheHandle() { return &megamorphic_cache_; }
Snapshot::Kind kind() const { return kind_; }
// Reads an object.
@@ -435,79 +433,11 @@
// Read version number of snapshot and verify.
RawApiError* VerifyVersionAndFeatures();
- // Helper functions for creating uninitialized versions
- // of various object types. These are used when reading a
- // full snapshot.
- RawArray* NewArray(intptr_t len);
- RawImmutableArray* NewImmutableArray(intptr_t len);
- RawOneByteString* NewOneByteString(intptr_t len);
- RawTwoByteString* NewTwoByteString(intptr_t len);
- RawTypeArguments* NewTypeArguments(intptr_t len);
- RawTokenStream* NewTokenStream(intptr_t len);
- RawContext* NewContext(intptr_t num_variables);
- RawClass* NewClass(intptr_t class_id);
- RawInstance* NewInstance();
- RawMint* NewMint(int64_t value);
- RawBigint* NewBigint();
- RawTypedData* NewTypedData(intptr_t class_id, intptr_t len);
- RawDouble* NewDouble(double value);
- RawUnresolvedClass* NewUnresolvedClass();
- RawType* NewType();
- RawTypeRef* NewTypeRef();
- RawTypeParameter* NewTypeParameter();
- RawBoundedType* NewBoundedType();
- RawMixinAppType* NewMixinAppType();
- RawPatchClass* NewPatchClass();
- RawClosure* NewClosure();
- RawClosureData* NewClosureData();
- RawRedirectionData* NewRedirectionData();
- RawFunction* NewFunction();
- RawCode* NewCode(intptr_t pointer_offsets_length);
- RawObjectPool* NewObjectPool(intptr_t length);
- RawPcDescriptors* NewPcDescriptors(intptr_t length);
- RawCodeSourceMap* NewCodeSourceMap(intptr_t length);
- RawLocalVarDescriptors* NewLocalVarDescriptors(intptr_t num_entries);
- RawExceptionHandlers* NewExceptionHandlers(intptr_t num_entries);
- RawStackmap* NewStackmap(intptr_t length);
- RawContextScope* NewContextScope(intptr_t num_variables);
- RawICData* NewICData();
- RawMegamorphicCache* NewMegamorphicCache();
- RawSubtypeTestCache* NewSubtypeTestCache();
- RawLinkedHashMap* NewLinkedHashMap();
- RawField* NewField();
- RawLibrary* NewLibrary();
- RawLibraryPrefix* NewLibraryPrefix();
- RawNamespace* NewNamespace();
- RawScript* NewScript();
- RawLiteralToken* NewLiteralToken();
- RawGrowableObjectArray* NewGrowableObjectArray();
- RawFloat32x4* NewFloat32x4(float v0, float v1, float v2, float v3);
- RawInt32x4* NewInt32x4(uint32_t v0, uint32_t v1, uint32_t v2, uint32_t v3);
- RawFloat64x2* NewFloat64x2(double v0, double v1);
- RawApiError* NewApiError();
- RawLanguageError* NewLanguageError();
- RawUnhandledException* NewUnhandledException();
RawObject* NewInteger(int64_t value);
- RawStacktrace* NewStacktrace();
- RawWeakProperty* NewWeakProperty();
- RawRegExp* NewRegExp();
-
- uword GetInstructionsAt(int32_t offset) {
- return instructions_reader_->GetInstructionsAt(offset);
- }
-
- RawObject* GetObjectAt(int32_t offset) {
- return instructions_reader_->GetObjectAt(offset);
- }
-
- const uint8_t* instructions_buffer_;
- const uint8_t* data_buffer_;
protected:
SnapshotReader(const uint8_t* buffer,
intptr_t size,
- const uint8_t* instructions_buffer,
- const uint8_t* data_buffer,
Snapshot::Kind kind,
ZoneGrowableArray<BackRefNode>* backward_references,
Thread* thread);
@@ -520,9 +450,6 @@
PageSpace* old_space() const { return old_space_; }
private:
- // Allocate uninitialized objects, this is used when reading a full snapshot.
- RawObject* AllocateUninitialized(intptr_t class_id, intptr_t size);
-
RawClass* ReadClassId(intptr_t object_id);
RawFunction* ReadFunctionId(intptr_t object_id);
RawObject* ReadStaticImplicitClosure(intptr_t object_id, intptr_t cls_header);
@@ -593,13 +520,10 @@
TokenStream& stream_; // Temporary token stream handle.
ExternalTypedData& data_; // Temporary stream data handle.
TypedData& typed_data_; // Temporary typed data handle.
- Code& code_; // Temporary code handle.
Function& function_; // Temporary function handle.
- MegamorphicCache& megamorphic_cache_; // Temporary megamorphic cache handle.
UnhandledException& error_; // Error handle.
intptr_t max_vm_isolate_object_id_;
ZoneGrowableArray<BackRefNode>* backward_references_;
- InstructionsReader* instructions_reader_;
friend class ApiError;
friend class Array;
@@ -608,7 +532,6 @@
friend class Class;
friend class Closure;
friend class ClosureData;
- friend class Code;
friend class Context;
friend class ContextScope;
friend class ExceptionHandlers;
@@ -617,23 +540,18 @@
friend class GrowableObjectArray;
friend class ICData;
friend class ImmutableArray;
- friend class Instructions;
friend class RegExp;
friend class LanguageError;
friend class Library;
friend class LibraryPrefix;
friend class LinkedHashMap;
friend class LiteralToken;
- friend class LocalVarDescriptors;
- friend class MegamorphicCache;
friend class MirrorReference;
friend class MixinAppType;
friend class Namespace;
- friend class ObjectPool;
friend class PatchClass;
friend class RedirectionData;
friend class Script;
- friend class Stacktrace;
friend class SubtypeTestCache;
friend class TokenStream;
friend class Type;
@@ -945,9 +863,7 @@
ReAlloc alloc,
intptr_t initial_size,
ForwardList* forward_list,
- InstructionsWriter* instructions_writer,
- bool can_send_any_object,
- bool writing_vm_isolate = false);
+ bool can_send_any_object);
public:
// Snapshot kind.
@@ -973,20 +889,11 @@
exception_msg_ = msg;
}
bool can_send_any_object() const { return can_send_any_object_; }
- bool writing_vm_isolate() const { return writing_vm_isolate_; }
void ThrowException(Exceptions::ExceptionType type, const char* msg);
// Write a version string for the snapshot.
void WriteVersionAndFeatures();
- int32_t GetInstructionsId(RawInstructions* instructions, RawCode* code) {
- return instructions_writer_->GetOffsetFor(instructions, code);
- }
-
- int32_t GetObjectId(RawObject* raw) {
- return instructions_writer_->GetObjectOffsetFor(raw);
- }
-
void WriteFunctionId(RawFunction* func, bool owner_is_class);
RawFunction* IsSerializableClosure(RawClosure* closure);
@@ -1032,12 +939,9 @@
ObjectStore* object_store_; // Object store for common classes.
ClassTable* class_table_; // Class table for the class index to class lookup.
ForwardList* forward_list_;
- InstructionsWriter* instructions_writer_;
Exceptions::ExceptionType exception_type_; // Exception type.
const char* exception_msg_; // Message associated with exception.
- bool unmarked_objects_; // True if marked objects have been unmarked.
bool can_send_any_object_; // True if any Dart instance can be sent.
- bool writing_vm_isolate_;
friend class RawArray;
friend class RawClass;
diff --git a/runtime/vm/snapshot_test.cc b/runtime/vm/snapshot_test.cc
index c5862e4..bcd69f7 100644
--- a/runtime/vm/snapshot_test.cc
+++ b/runtime/vm/snapshot_test.cc
@@ -833,7 +833,6 @@
alloc,
kInitialSize,
&forward_list_,
- NULL, /* test_writer */
true /* can_send_any_object */),
forward_list_(thread(), kMaxPredefinedObjectIds) {
ASSERT(buffer != NULL);
diff --git a/runtime/vm/stack_frame.cc b/runtime/vm/stack_frame.cc
index 827407d..d9bd0fa 100644
--- a/runtime/vm/stack_frame.cc
+++ b/runtime/vm/stack_frame.cc
@@ -489,6 +489,7 @@
InlinedFunctionsIterator::InlinedFunctionsIterator(const Code& code, uword pc)
: index_(0),
num_materializations_(0),
+ dest_frame_size_(0),
code_(Code::Handle(code.raw())),
deopt_info_(TypedData::Handle()),
function_(Function::Handle()),
@@ -512,6 +513,7 @@
ASSERT(!deopt_table.IsNull());
DeoptInfo::Unpack(deopt_table, deopt_info_, &deopt_instructions_);
num_materializations_ = DeoptInfo::NumMaterializations(deopt_instructions_);
+ dest_frame_size_ = DeoptInfo::FrameSize(deopt_info_);
object_table_ = code_.GetObjectPool();
Advance();
}
@@ -550,7 +552,14 @@
index++) {
DeoptInstr* deopt_instr = deopt_instructions_[index];
if (deopt_instr->kind() == DeoptInstr::kCallerFp) {
+#if defined(TARGET_ARCH_DBC)
+ // Stack on DBC is growing upwards but we record deopt commands
+ // in the same order we record them on other architectures as if
+ // the stack was growing downwards.
+ return dest_frame_size_ - index;
+#else
return (index - num_materializations_);
+#endif
}
}
UNREACHABLE();
diff --git a/runtime/vm/stack_frame.h b/runtime/vm/stack_frame.h
index dac3e5f..268ca4a 100644
--- a/runtime/vm/stack_frame.h
+++ b/runtime/vm/stack_frame.h
@@ -336,6 +336,7 @@
intptr_t index_;
intptr_t num_materializations_;
+ intptr_t dest_frame_size_;
Code& code_;
TypedData& deopt_info_;
Function& function_;
@@ -346,9 +347,11 @@
DISALLOW_COPY_AND_ASSIGN(InlinedFunctionsIterator);
};
+
#if !defined(TARGET_ARCH_DBC)
-DART_FORCE_INLINE static uword LocalVarAddress(uword fp, intptr_t index) {
- return fp + (index * kWordSize);
+DART_FORCE_INLINE static intptr_t LocalVarIndex(intptr_t fp_offset,
+ intptr_t var_index) {
+ return fp_offset + var_index;
}
@@ -367,6 +370,12 @@
static const uword kInterruptStackLimit = ~static_cast<uword>(0);
#endif
+
+DART_FORCE_INLINE static uword LocalVarAddress(uword fp, intptr_t index) {
+ return fp + LocalVarIndex(0, index) * kWordSize;
+}
+
+
} // namespace dart
#endif // VM_STACK_FRAME_H_
diff --git a/runtime/vm/stack_frame_dbc.h b/runtime/vm/stack_frame_dbc.h
index a59a417..5d5ee78 100644
--- a/runtime/vm/stack_frame_dbc.h
+++ b/runtime/vm/stack_frame_dbc.h
@@ -10,7 +10,7 @@
/* DBC Frame Layout
IMPORTANT: On DBC stack is growing upwards which is different from all other
-architectures. This enables effecient addressing for locals via unsigned index.
+architectures. This enables efficient addressing for locals via unsigned index.
| | <- TOS
Callee frame | ... |
@@ -56,15 +56,17 @@
static const int kFirstLocalSlotFromFp = -1;
-DART_FORCE_INLINE static uword LocalVarAddress(uword fp, intptr_t index) {
- ASSERT(index != 0);
- if (index > 0) {
- return fp - index * kWordSize;
+DART_FORCE_INLINE static intptr_t LocalVarIndex(intptr_t fp_offset,
+ intptr_t var_index) {
+ ASSERT(var_index != 0);
+ if (var_index > 0) {
+ return fp_offset - var_index;
} else {
- return fp - (index + 1) * kWordSize;
+ return fp_offset - (var_index + 1);
}
}
+
DART_FORCE_INLINE static uword ParamAddress(uword fp, intptr_t reverse_index) {
return fp - (kDartFrameFixedSize + reverse_index) * kWordSize;
}
diff --git a/runtime/vm/stub_code.cc b/runtime/vm/stub_code.cc
index a6992bf..53a06cb 100644
--- a/runtime/vm/stub_code.cc
+++ b/runtime/vm/stub_code.cc
@@ -183,20 +183,20 @@
isolate->heap()->CollectAllGarbage();
}
}
+#ifndef PRODUCT
if (FLAG_support_disassembler && FLAG_disassemble_stubs) {
LogBlock lb;
THR_Print("Code for allocation stub '%s': {\n", name);
-#ifndef PRODUCT
DisassembleToStdout formatter;
stub.Disassemble(&formatter);
-#endif
THR_Print("}\n");
const ObjectPool& object_pool = ObjectPool::Handle(stub.object_pool());
object_pool.DebugPrint();
}
+#endif // !PRODUCT
}
return stub.raw();
-#endif
+#endif // !DBC
UNIMPLEMENTED();
return Code::null();
}
@@ -229,6 +229,7 @@
GenerateStub(&assembler);
const Code& code = Code::Handle(
Code::FinalizeCode(name, &assembler, false /* optimized */));
+#ifndef PRODUCT
if (FLAG_support_disassembler && FLAG_disassemble_stubs) {
LogBlock lb;
THR_Print("Code for stub '%s': {\n", name);
@@ -238,6 +239,7 @@
const ObjectPool& object_pool = ObjectPool::Handle(code.object_pool());
object_pool.DebugPrint();
}
+#endif // !PRODUCT
return code.raw();
}
diff --git a/runtime/vm/stub_code.h b/runtime/vm/stub_code.h
index cecec5d..d5103e6 100644
--- a/runtime/vm/stub_code.h
+++ b/runtime/vm/stub_code.h
@@ -54,8 +54,6 @@
V(SmiAddInlineCache) \
V(SmiSubInlineCache) \
V(SmiEqualInlineCache) \
- V(UnaryRangeCollectingInlineCache) \
- V(BinaryRangeCollectingInlineCache) \
V(OneArgOptimizedCheckInlineCache) \
V(TwoArgsOptimizedCheckInlineCache) \
V(ZeroArgsUnoptimizedStaticCall) \
@@ -155,8 +153,6 @@
static const intptr_t kNoInstantiator = 0;
- static void EmitMegamorphicLookup(Assembler* assembler);
-
private:
friend class MegamorphicCacheTable;
@@ -172,11 +168,6 @@
VM_STUB_CODE_LIST(STUB_CODE_ENTRY);
#undef STUB_CODE_ENTRY
- enum RangeCollectionMode {
- kCollectRanges,
- kIgnoreRanges
- };
-
// Generate the stub and finalize the generated code into the stub
// code executable area.
static RawCode* Generate(const char* name,
@@ -190,7 +181,6 @@
intptr_t num_args,
const RuntimeEntry& handle_ic_miss,
Token::Kind kind,
- RangeCollectionMode range_collection_mode,
bool optimized = false);
static void GenerateUsageCounterIncrement(Assembler* assembler,
Register temp_reg);
diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc
index 9a7429b..370711b 100644
--- a/runtime/vm/stub_code_arm.cc
+++ b/runtime/vm/stub_code_arm.cc
@@ -1324,7 +1324,6 @@
intptr_t num_args,
const RuntimeEntry& handle_ic_miss,
Token::Kind kind,
- RangeCollectionMode range_collection_mode,
bool optimized) {
__ CheckCodePointer();
ASSERT(num_args > 0);
@@ -1352,18 +1351,7 @@
__ Bind(&done_stepping);
}
- __ Comment("Range feedback collection");
Label not_smi_or_overflow;
- if (range_collection_mode == kCollectRanges) {
- ASSERT((num_args == 1) || (num_args == 2));
- if (num_args == 2) {
- __ ldr(R0, Address(SP, 1 * kWordSize));
- __ UpdateRangeFeedback(R0, 0, R9, R1, R4, ¬_smi_or_overflow);
- }
-
- __ ldr(R0, Address(SP, 0 * kWordSize));
- __ UpdateRangeFeedback(R0, num_args - 1, R9, R1, R4, ¬_smi_or_overflow);
- }
if (kind != Token::kILLEGAL) {
EmitFastSmiOp(assembler, kind, num_args, ¬_smi_or_overflow);
}
@@ -1478,31 +1466,8 @@
__ Bind(&call_target_function);
// R0: target function.
__ ldr(R2, FieldAddress(R0, Function::entry_point_offset()));
- if (range_collection_mode == kCollectRanges) {
- __ ldr(R1, Address(SP, 0 * kWordSize));
- if (num_args == 2) {
- __ ldr(R3, Address(SP, 1 * kWordSize));
- }
- __ EnterStubFrame();
- if (num_args == 2) {
- __ PushList((1 << R1) | (1 << R3) | (1 << R9));
- } else {
- __ PushList((1 << R1) | (1 << R9));
- }
- __ ldr(CODE_REG, FieldAddress(R0, Function::code_offset()));
- __ blx(R2);
-
- Label done;
- __ ldr(R9, Address(FP, kFirstLocalSlotFromFp * kWordSize));
- __ UpdateRangeFeedback(R0, 2, R9, R1, R4, &done);
- __ Bind(&done);
- __ RestoreCodePointer();
- __ LeaveStubFrame();
- __ Ret();
- } else {
- __ ldr(CODE_REG, FieldAddress(R0, Function::code_offset()));
- __ bx(R2);
- }
+ __ ldr(CODE_REG, FieldAddress(R0, Function::code_offset()));
+ __ bx(R2);
if (FLAG_support_debugger && !optimized) {
__ Bind(&stepping);
@@ -1532,8 +1497,7 @@
GenerateNArgsCheckInlineCacheStub(assembler,
1,
kInlineCacheMissHandlerOneArgRuntimeEntry,
- Token::kILLEGAL,
- kIgnoreRanges);
+ Token::kILLEGAL);
}
@@ -1542,8 +1506,7 @@
GenerateNArgsCheckInlineCacheStub(assembler,
2,
kInlineCacheMissHandlerTwoArgsRuntimeEntry,
- Token::kILLEGAL,
- kIgnoreRanges);
+ Token::kILLEGAL);
}
@@ -1552,44 +1515,21 @@
GenerateNArgsCheckInlineCacheStub(assembler,
2,
kInlineCacheMissHandlerTwoArgsRuntimeEntry,
- Token::kADD,
- kCollectRanges);
+ Token::kADD);
}
void StubCode::GenerateSmiSubInlineCacheStub(Assembler* assembler) {
GenerateUsageCounterIncrement(assembler, R8);
GenerateNArgsCheckInlineCacheStub(assembler, 2,
- kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kSUB,
- kCollectRanges);
+ kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kSUB);
}
void StubCode::GenerateSmiEqualInlineCacheStub(Assembler* assembler) {
GenerateUsageCounterIncrement(assembler, R8);
GenerateNArgsCheckInlineCacheStub(assembler, 2,
- kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kEQ,
- kIgnoreRanges);
-}
-
-
-void StubCode::GenerateUnaryRangeCollectingInlineCacheStub(
- Assembler* assembler) {
- GenerateUsageCounterIncrement(assembler, R8);
- GenerateNArgsCheckInlineCacheStub(assembler, 1,
- kInlineCacheMissHandlerOneArgRuntimeEntry,
- Token::kILLEGAL,
- kCollectRanges);
-}
-
-
-void StubCode::GenerateBinaryRangeCollectingInlineCacheStub(
- Assembler* assembler) {
- GenerateUsageCounterIncrement(assembler, R8);
- GenerateNArgsCheckInlineCacheStub(assembler, 2,
- kInlineCacheMissHandlerTwoArgsRuntimeEntry,
- Token::kILLEGAL,
- kCollectRanges);
+ kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kEQ);
}
@@ -1598,7 +1538,7 @@
GenerateOptimizedUsageCounterIncrement(assembler);
GenerateNArgsCheckInlineCacheStub(assembler, 1,
kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL,
- kIgnoreRanges, true /* optimized */);
+ true /* optimized */);
}
@@ -1607,7 +1547,7 @@
GenerateOptimizedUsageCounterIncrement(assembler);
GenerateNArgsCheckInlineCacheStub(assembler, 2,
kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL,
- kIgnoreRanges, true /* optimized */);
+ true /* optimized */);
}
@@ -1681,16 +1621,14 @@
void StubCode::GenerateOneArgUnoptimizedStaticCallStub(Assembler* assembler) {
GenerateUsageCounterIncrement(assembler, R8);
GenerateNArgsCheckInlineCacheStub(
- assembler, 1, kStaticCallMissHandlerOneArgRuntimeEntry, Token::kILLEGAL,
- kIgnoreRanges);
+ assembler, 1, kStaticCallMissHandlerOneArgRuntimeEntry, Token::kILLEGAL);
}
void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) {
GenerateUsageCounterIncrement(assembler, R8);
GenerateNArgsCheckInlineCacheStub(assembler, 2,
- kStaticCallMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL,
- kIgnoreRanges);
+ kStaticCallMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL);
}
@@ -2048,48 +1986,6 @@
}
-void StubCode::EmitMegamorphicLookup(Assembler* assembler) {
- __ LoadTaggedClassIdMayBeSmi(R0, R0);
- // R0: receiver cid as Smi.
- __ ldr(R4, FieldAddress(R9, MegamorphicCache::arguments_descriptor_offset()));
- __ ldr(R2, FieldAddress(R9, MegamorphicCache::buckets_offset()));
- __ ldr(R1, FieldAddress(R9, MegamorphicCache::mask_offset()));
- // R2: cache buckets array.
- // R1: mask.
- __ LoadImmediate(IP, MegamorphicCache::kSpreadFactor);
- __ mul(R3, R0, IP);
- // R3: probe.
-
- Label loop, update, load_target_function;
- __ b(&loop);
-
- __ Bind(&update);
- __ add(R3, R3, Operand(Smi::RawValue(1)));
- __ Bind(&loop);
- __ and_(R3, R3, Operand(R1));
- const intptr_t base = Array::data_offset();
- // R3 is smi tagged, but table entries are two words, so LSL 2.
- __ add(IP, R2, Operand(R3, LSL, 2));
- __ ldr(R6, FieldAddress(IP, base));
-
- ASSERT(kIllegalCid == 0);
- __ tst(R6, Operand(R6));
- __ b(&load_target_function, EQ);
- __ cmp(R6, Operand(R0));
- __ b(&update, NE);
-
- __ Bind(&load_target_function);
- // Call the target found in the cache. For a class id match, this is a
- // proper target for the given name and arguments descriptor. If the
- // illegal class id was found, the target is a cache miss handler that can
- // be invoked as a normal Dart function.
- __ add(IP, R2, Operand(R3, LSL, 2));
- __ ldr(R0, FieldAddress(IP, base + kWordSize));
- __ ldr(R1, FieldAddress(R0, Function::entry_point_offset()));
- __ ldr(CODE_REG, FieldAddress(R0, Function::code_offset()));
-}
-
-
// Called from megamorphic calls.
// R0: receiver
// R9: MegamorphicCache (preserved)
@@ -2098,8 +1994,51 @@
// CODE_REG: target Code
// R4: arguments descriptor
void StubCode::GenerateMegamorphicLookupStub(Assembler* assembler) {
- EmitMegamorphicLookup(assembler);
+ __ LoadTaggedClassIdMayBeSmi(R0, R0);
+ // R0: receiver cid as Smi.
+ __ ldr(R2, FieldAddress(R9, MegamorphicCache::buckets_offset()));
+ __ ldr(R1, FieldAddress(R9, MegamorphicCache::mask_offset()));
+ // R2: cache buckets array.
+ // R1: mask.
+
+ // Compute the table index.
+ ASSERT(MegamorphicCache::kSpreadFactor == 7);
+ // Use reverse substract to multiply with 7 == 8 - 1.
+ __ rsb(R3, R0, Operand(R0, LSL, 3));
+ // R3: probe.
+ Label loop;
+ __ Bind(&loop);
+ __ and_(R3, R3, Operand(R1));
+
+ const intptr_t base = Array::data_offset();
+ // R3 is smi tagged, but table entries are two words, so LSL 2.
+ Label probe_failed;
+ __ add(IP, R2, Operand(R3, LSL, 2));
+ __ ldr(R6, FieldAddress(IP, base));
+ __ cmp(R6, Operand(R0));
+ __ b(&probe_failed, NE);
+
+ Label load_target;
+ __ Bind(&load_target);
+ // Call the target found in the cache. For a class id match, this is a
+ // proper target for the given name and arguments descriptor. If the
+ // illegal class id was found, the target is a cache miss handler that can
+ // be invoked as a normal Dart function.
+ __ ldr(R0, FieldAddress(IP, base + kWordSize));
+ __ ldr(R4, FieldAddress(R9, MegamorphicCache::arguments_descriptor_offset()));
+ __ ldr(R1, FieldAddress(R0, Function::entry_point_offset()));
+ __ ldr(CODE_REG, FieldAddress(R0, Function::code_offset()));
__ Ret();
+
+ // Probe failed, check if it is a miss.
+ __ Bind(&probe_failed);
+ ASSERT(kIllegalCid == 0);
+ __ tst(R6, Operand(R6));
+ __ b(&load_target, EQ); // branch if miss.
+
+ // Try next extry in the table.
+ __ AddImmediate(R3, Smi::RawValue(1));
+ __ b(&loop);
}
diff --git a/runtime/vm/stub_code_arm64.cc b/runtime/vm/stub_code_arm64.cc
index 04dd0f4..9034730 100644
--- a/runtime/vm/stub_code_arm64.cc
+++ b/runtime/vm/stub_code_arm64.cc
@@ -1293,8 +1293,7 @@
static void EmitFastSmiOp(Assembler* assembler,
Token::Kind kind,
intptr_t num_args,
- Label* not_smi_or_overflow,
- bool should_update_result_range) {
+ Label* not_smi_or_overflow) {
__ Comment("Fast Smi op");
__ ldr(R0, Address(SP, + 0 * kWordSize)); // Right.
__ ldr(R1, Address(SP, + 1 * kWordSize)); // Left.
@@ -1322,12 +1321,6 @@
default: UNIMPLEMENTED();
}
- if (should_update_result_range) {
- Label done;
- __ UpdateRangeFeedback(R0, 2, R5, R1, R6, &done);
- __ Bind(&done);
- }
-
// R5: IC data object (preserved).
__ LoadFieldFromOffset(R6, R5, ICData::ic_data_offset());
// R6: ic_data_array with check entries: classes and target functions.
@@ -1376,7 +1369,6 @@
intptr_t num_args,
const RuntimeEntry& handle_ic_miss,
Token::Kind kind,
- RangeCollectionMode range_collection_mode,
bool optimized) {
ASSERT(num_args > 0);
#if defined(DEBUG)
@@ -1405,24 +1397,12 @@
__ Bind(&done_stepping);
}
- __ Comment("Range feedback collection");
Label not_smi_or_overflow;
- if (range_collection_mode == kCollectRanges) {
- ASSERT((num_args == 1) || (num_args == 2));
- if (num_args == 2) {
- __ ldr(R0, Address(SP, 1 * kWordSize));
- __ UpdateRangeFeedback(R0, 0, R5, R1, R4, ¬_smi_or_overflow);
- }
-
- __ ldr(R0, Address(SP, 0 * kWordSize));
- __ UpdateRangeFeedback(R0, num_args - 1, R5, R1, R4, ¬_smi_or_overflow);
- }
if (kind != Token::kILLEGAL) {
EmitFastSmiOp(assembler,
kind,
num_args,
- ¬_smi_or_overflow,
- (range_collection_mode == kCollectRanges));
+ ¬_smi_or_overflow);
}
__ Bind(¬_smi_or_overflow);
@@ -1546,32 +1526,9 @@
__ Comment("Call target");
__ Bind(&call_target_function);
// R0: target function.
- if (range_collection_mode == kCollectRanges) {
- __ LoadFieldFromOffset(R2, R0, Function::entry_point_offset());
- __ ldr(R1, Address(SP, 0 * kWordSize));
- if (num_args == 2) {
- __ ldr(R3, Address(SP, 1 * kWordSize));
- }
- __ EnterStubFrame();
- __ Push(R5);
- if (num_args == 2) {
- __ Push(R3);
- }
- __ Push(R1);
- __ LoadFieldFromOffset(CODE_REG, R0, Function::code_offset());
- __ blr(R2);
-
- Label done;
- __ ldr(R5, Address(FP, kFirstLocalSlotFromFp * kWordSize));
- __ UpdateRangeFeedback(R0, 2, R5, R1, R4, &done);
- __ Bind(&done);
- __ LeaveStubFrame();
- __ ret();
- } else {
- __ LoadFieldFromOffset(CODE_REG, R0, Function::code_offset());
- __ LoadFieldFromOffset(R2, R0, Function::entry_point_offset());
- __ br(R2);
- }
+ __ LoadFieldFromOffset(CODE_REG, R0, Function::code_offset());
+ __ LoadFieldFromOffset(R2, R0, Function::entry_point_offset());
+ __ br(R2);
if (FLAG_support_debugger && !optimized) {
__ Bind(&stepping);
@@ -1599,60 +1556,35 @@
void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) {
GenerateUsageCounterIncrement(assembler, R6);
GenerateNArgsCheckInlineCacheStub(assembler, 1,
- kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL,
- kIgnoreRanges);
+ kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL);
}
void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) {
GenerateUsageCounterIncrement(assembler, R6);
GenerateNArgsCheckInlineCacheStub(assembler, 2,
- kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL,
- kIgnoreRanges);
+ kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL);
}
void StubCode::GenerateSmiAddInlineCacheStub(Assembler* assembler) {
GenerateUsageCounterIncrement(assembler, R6);
GenerateNArgsCheckInlineCacheStub(assembler, 2,
- kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kADD,
- kCollectRanges);
+ kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kADD);
}
void StubCode::GenerateSmiSubInlineCacheStub(Assembler* assembler) {
GenerateUsageCounterIncrement(assembler, R6);
GenerateNArgsCheckInlineCacheStub(assembler, 2,
- kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kSUB,
- kCollectRanges);
+ kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kSUB);
}
void StubCode::GenerateSmiEqualInlineCacheStub(Assembler* assembler) {
GenerateUsageCounterIncrement(assembler, R6);
GenerateNArgsCheckInlineCacheStub(assembler, 2,
- kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kEQ,
- kIgnoreRanges);
-}
-
-
-void StubCode::GenerateUnaryRangeCollectingInlineCacheStub(
- Assembler* assembler) {
- GenerateUsageCounterIncrement(assembler, R6);
- GenerateNArgsCheckInlineCacheStub(assembler, 1,
- kInlineCacheMissHandlerOneArgRuntimeEntry,
- Token::kILLEGAL,
- kCollectRanges);
-}
-
-
-void StubCode::GenerateBinaryRangeCollectingInlineCacheStub(
- Assembler* assembler) {
- GenerateUsageCounterIncrement(assembler, R6);
- GenerateNArgsCheckInlineCacheStub(assembler, 2,
- kInlineCacheMissHandlerTwoArgsRuntimeEntry,
- Token::kILLEGAL,
- kCollectRanges);
+ kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kEQ);
}
@@ -1661,7 +1593,7 @@
GenerateOptimizedUsageCounterIncrement(assembler);
GenerateNArgsCheckInlineCacheStub(assembler, 1,
kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL,
- kIgnoreRanges, true /* optimized */);
+ true /* optimized */);
}
@@ -1670,7 +1602,7 @@
GenerateOptimizedUsageCounterIncrement(assembler);
GenerateNArgsCheckInlineCacheStub(assembler, 2,
kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL,
- kIgnoreRanges, true /* optimized */);
+ true /* optimized */);
}
@@ -1744,16 +1676,14 @@
void StubCode::GenerateOneArgUnoptimizedStaticCallStub(Assembler* assembler) {
GenerateUsageCounterIncrement(assembler, R6);
GenerateNArgsCheckInlineCacheStub(
- assembler, 1, kStaticCallMissHandlerOneArgRuntimeEntry, Token::kILLEGAL,
- kIgnoreRanges);
+ assembler, 1, kStaticCallMissHandlerOneArgRuntimeEntry, Token::kILLEGAL);
}
void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) {
GenerateUsageCounterIncrement(assembler, R6);
GenerateNArgsCheckInlineCacheStub(assembler, 2,
- kStaticCallMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL,
- kIgnoreRanges);
+ kStaticCallMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL);
}
@@ -2098,48 +2028,6 @@
}
-void StubCode::EmitMegamorphicLookup(Assembler* assembler) {
- __ LoadTaggedClassIdMayBeSmi(R0, R0);
- // R0: class ID of the receiver (smi).
- __ ldr(R4, FieldAddress(R5, MegamorphicCache::arguments_descriptor_offset()));
- __ ldr(R2, FieldAddress(R5, MegamorphicCache::buckets_offset()));
- __ ldr(R1, FieldAddress(R5, MegamorphicCache::mask_offset()));
- // R2: cache buckets array.
- // R1: mask.
- __ LoadImmediate(TMP, MegamorphicCache::kSpreadFactor);
- __ mul(R3, R0, TMP);
- // R3: probe.
-
- Label loop, update, load_target_function;
- __ b(&loop);
-
- __ Bind(&update);
- __ add(R3, R3, Operand(Smi::RawValue(1)));
- __ Bind(&loop);
- __ and_(R3, R3, Operand(R1));
- 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));
- __ ldr(R6, FieldAddress(TMP, base));
-
- ASSERT(kIllegalCid == 0);
- __ tst(R6, Operand(R6));
- __ b(&load_target_function, EQ);
- __ CompareRegisters(R6, R0);
- __ b(&update, NE);
-
- __ Bind(&load_target_function);
- // Call the target found in the cache. For a class id match, this is a
- // proper target for the given name and arguments descriptor. If the
- // 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));
- __ ldr(R0, FieldAddress(TMP, base + kWordSize));
- __ ldr(R1, FieldAddress(R0, Function::entry_point_offset()));
- __ ldr(CODE_REG, FieldAddress(R0, Function::code_offset()));
-}
-
-
// Called from megamorphic calls.
// R0: receiver
// R5: MegamorphicCache (preserved)
@@ -2148,8 +2036,69 @@
// CODE_REG: target Code
// R4: arguments descriptor
void StubCode::GenerateMegamorphicLookupStub(Assembler* assembler) {
- EmitMegamorphicLookup(assembler);
+ // Jump if receiver is a smi.
+ Label smi_case;
+ __ TestImmediate(R0, kSmiTagMask);
+ __ b(&smi_case, EQ);
+
+ // Loads the cid of the object.
+ __ LoadClassId(R0, R0);
+
+ Label cid_loaded;
+ __ Bind(&cid_loaded);
+ __ ldr(R2, FieldAddress(R5, MegamorphicCache::buckets_offset()));
+ __ ldr(R1, FieldAddress(R5, MegamorphicCache::mask_offset()));
+ // R2: cache buckets array.
+ // R1: mask.
+
+ // Make the cid into a smi.
+ __ SmiTag(R0);
+ // R0: class ID of the receiver (smi).
+
+ // Compute the table index.
+ ASSERT(MegamorphicCache::kSpreadFactor == 7);
+ // Use lsl and sub to multiply with 7 == 8 - 1.
+ __ LslImmediate(R3, R0, 3);
+ __ sub(R3, R3, Operand(R0));
+ // R3: probe.
+ Label loop;
+ __ Bind(&loop);
+ __ and_(R3, R3, Operand(R1));
+
+ 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));
+ __ ldr(R6, FieldAddress(TMP, base));
+ Label probe_failed;
+ __ CompareRegisters(R6, R0);
+ __ b(&probe_failed, NE);
+
+ Label load_target;
+ __ Bind(&load_target);
+ // Call the target found in the cache. For a class id match, this is a
+ // proper target for the given name and arguments descriptor. If the
+ // illegal class id was found, the target is a cache miss handler that can
+ // be invoked as a normal Dart function.
+ __ ldr(R0, FieldAddress(TMP, base + kWordSize));
+ __ ldr(R4, FieldAddress(R5, MegamorphicCache::arguments_descriptor_offset()));
+ __ ldr(R1, FieldAddress(R0, Function::entry_point_offset()));
+ __ ldr(CODE_REG, FieldAddress(R0, Function::code_offset()));
__ ret();
+
+ // Probe failed, check if it is a miss.
+ __ Bind(&probe_failed);
+ ASSERT(kIllegalCid == 0);
+ __ tst(R6, Operand(R6));
+ __ b(&load_target, EQ); // branch if miss.
+
+ // Try next extry in the table.
+ __ AddImmediate(R3, R3, Smi::RawValue(1));
+ __ b(&loop);
+
+ // Load cid for the Smi case.
+ __ Bind(&smi_case);
+ __ LoadImmediate(R0, kSmiCid);
+ __ b(&cid_loaded);
}
diff --git a/runtime/vm/stub_code_ia32.cc b/runtime/vm/stub_code_ia32.cc
index 139a4a2..71cf786 100644
--- a/runtime/vm/stub_code_ia32.cc
+++ b/runtime/vm/stub_code_ia32.cc
@@ -1278,7 +1278,6 @@
intptr_t num_args,
const RuntimeEntry& handle_ic_miss,
Token::Kind kind,
- RangeCollectionMode range_collection_mode,
bool optimized) {
ASSERT(num_args > 0);
#if defined(DEBUG)
@@ -1303,19 +1302,7 @@
__ j(NOT_EQUAL, &stepping);
__ Bind(&done_stepping);
}
- __ Comment("Range feedback collection");
Label not_smi_or_overflow;
- if (range_collection_mode == kCollectRanges) {
- ASSERT((num_args == 1) || (num_args == 2));
- if (num_args == 2) {
- __ movl(EAX, Address(ESP, + 2 * kWordSize));
- __ UpdateRangeFeedback(EAX, 0, ECX, EBX, EDI, EDX, ¬_smi_or_overflow);
- }
-
- __ movl(EAX, Address(ESP, + 1 * kWordSize));
- __ UpdateRangeFeedback(EAX, (num_args - 1), ECX, EBX, EDI, EDX,
- ¬_smi_or_overflow);
- }
if (kind != Token::kILLEGAL) {
EmitFastSmiOp(assembler, kind, num_args, ¬_smi_or_overflow);
}
@@ -1434,27 +1421,7 @@
__ Comment("Call target");
// EAX: Target function.
__ movl(EBX, FieldAddress(EAX, Function::entry_point_offset()));
- if (range_collection_mode == kCollectRanges) {
- __ EnterStubFrame();
- __ pushl(ECX);
- const intptr_t arg_offset_words = num_args +
- Assembler::kEnterStubFramePushedWords +
- 1; // ECX
- for (intptr_t i = 0; i < num_args; i++) {
- __ movl(EDI, Address(ESP, arg_offset_words * kWordSize));
- __ pushl(EDI);
- }
- __ call(EBX);
-
- __ movl(ECX, Address(EBP, kFirstLocalSlotFromFp * kWordSize));
- Label done;
- __ UpdateRangeFeedback(EAX, 2, ECX, EBX, EDI, EDX, &done);
- __ Bind(&done);
- __ LeaveFrame();
- __ ret();
- } else {
- __ jmp(EBX);
- }
+ __ jmp(EBX);
if (FLAG_support_debugger && !optimized) {
__ Bind(&stepping);
@@ -1482,8 +1449,7 @@
GenerateUsageCounterIncrement(assembler, EBX);
GenerateNArgsCheckInlineCacheStub(assembler, 1,
kInlineCacheMissHandlerOneArgRuntimeEntry,
- Token::kILLEGAL,
- kIgnoreRanges);
+ Token::kILLEGAL);
}
@@ -1491,8 +1457,7 @@
GenerateUsageCounterIncrement(assembler, EBX);
GenerateNArgsCheckInlineCacheStub(assembler, 2,
kInlineCacheMissHandlerTwoArgsRuntimeEntry,
- Token::kILLEGAL,
- kIgnoreRanges);
+ Token::kILLEGAL);
}
@@ -1500,8 +1465,7 @@
GenerateUsageCounterIncrement(assembler, EBX);
GenerateNArgsCheckInlineCacheStub(assembler, 2,
kInlineCacheMissHandlerTwoArgsRuntimeEntry,
- Token::kADD,
- kCollectRanges);
+ Token::kADD);
}
@@ -1509,8 +1473,7 @@
GenerateUsageCounterIncrement(assembler, EBX);
GenerateNArgsCheckInlineCacheStub(assembler, 2,
kInlineCacheMissHandlerTwoArgsRuntimeEntry,
- Token::kSUB,
- kCollectRanges);
+ Token::kSUB);
}
@@ -1518,28 +1481,7 @@
GenerateUsageCounterIncrement(assembler, EBX);
GenerateNArgsCheckInlineCacheStub(assembler, 2,
kInlineCacheMissHandlerTwoArgsRuntimeEntry,
- Token::kEQ,
- kIgnoreRanges);
-}
-
-
-void StubCode::GenerateUnaryRangeCollectingInlineCacheStub(
- Assembler* assembler) {
- GenerateUsageCounterIncrement(assembler, EBX);
- GenerateNArgsCheckInlineCacheStub(assembler, 1,
- kInlineCacheMissHandlerOneArgRuntimeEntry,
- Token::kILLEGAL,
- kCollectRanges);
-}
-
-
-void StubCode::GenerateBinaryRangeCollectingInlineCacheStub(
- Assembler* assembler) {
- GenerateUsageCounterIncrement(assembler, EBX);
- GenerateNArgsCheckInlineCacheStub(assembler, 2,
- kInlineCacheMissHandlerTwoArgsRuntimeEntry,
- Token::kILLEGAL,
- kCollectRanges);
+ Token::kEQ);
}
@@ -1560,7 +1502,6 @@
GenerateNArgsCheckInlineCacheStub(assembler, 1,
kInlineCacheMissHandlerOneArgRuntimeEntry,
Token::kILLEGAL,
- kIgnoreRanges,
true /* optimized */);
}
@@ -1571,7 +1512,6 @@
GenerateNArgsCheckInlineCacheStub(assembler, 2,
kInlineCacheMissHandlerTwoArgsRuntimeEntry,
Token::kILLEGAL,
- kIgnoreRanges,
true /* optimized */);
}
@@ -1645,8 +1585,7 @@
GenerateUsageCounterIncrement(assembler, EBX);
GenerateNArgsCheckInlineCacheStub(
assembler, 1, kStaticCallMissHandlerOneArgRuntimeEntry,
- Token::kILLEGAL,
- kIgnoreRanges);
+ Token::kILLEGAL);
}
@@ -1654,8 +1593,7 @@
GenerateUsageCounterIncrement(assembler, EBX);
GenerateNArgsCheckInlineCacheStub(assembler, 2,
kStaticCallMissHandlerTwoArgsRuntimeEntry,
- Token::kILLEGAL,
- kIgnoreRanges);
+ Token::kILLEGAL);
}
@@ -2021,48 +1959,6 @@
}
-void StubCode::EmitMegamorphicLookup(Assembler* assembler) {
- __ LoadTaggedClassIdMayBeSmi(EAX, EBX);
- // EAX: class ID of the receiver (smi).
- __ movl(EDI, FieldAddress(ECX, MegamorphicCache::buckets_offset()));
- __ movl(EBX, FieldAddress(ECX, MegamorphicCache::mask_offset()));
- // EDI: cache buckets array.
- // EBX: mask.
- __ pushl(ECX); // Spill MegamorphicCache.
- __ movl(ECX, EAX);
- __ imull(ECX, Immediate(MegamorphicCache::kSpreadFactor));
- // ECX: probe.
-
- Label loop, update, load_target_function;
- __ jmp(&loop);
-
- __ Bind(&update);
- __ addl(ECX, Immediate(Smi::RawValue(1)));
- __ Bind(&loop);
- __ andl(ECX, EBX);
- const intptr_t base = Array::data_offset();
- // ECX is smi tagged, but table entries are two words, so TIMES_4.
- __ movl(EDX, FieldAddress(EDI, ECX, TIMES_4, base));
-
- ASSERT(kIllegalCid == 0);
- __ testl(EDX, EDX);
- __ j(ZERO, &load_target_function, Assembler::kNearJump);
- __ cmpl(EDX, EAX);
- __ j(NOT_EQUAL, &update, Assembler::kNearJump);
-
- __ Bind(&load_target_function);
- // Call the target found in the cache. For a class id match, this is a
- // proper target for the given name and arguments descriptor. If the
- // illegal class id was found, the target is a cache miss handler that can
- // be invoked as a normal Dart function.
- __ movl(EAX, FieldAddress(EDI, ECX, TIMES_4, base + kWordSize));
- __ popl(ECX); // Restore MegamorphicCache.
- __ movl(EDX,
- FieldAddress(ECX, MegamorphicCache::arguments_descriptor_offset()));
- __ movl(EBX, FieldAddress(EAX, Function::entry_point_offset()));
-}
-
-
// Called from megamorphic calls.
// EBX: receiver
// ECX: MegamorphicCache (preserved)
@@ -2070,10 +1966,68 @@
// EBX: target entry point
// EDX: argument descriptor
void StubCode::GenerateMegamorphicLookupStub(Assembler* assembler) {
- EmitMegamorphicLookup(assembler);
- __ ret();
-}
+ // Jump if receiver is a smi.
+ Label smi_case;
+ // Check if object (in tmp) is a Smi.
+ __ testl(EBX, Immediate(kSmiTagMask));
+ // Jump out of line for smi case.
+ __ j(ZERO, &smi_case, Assembler::kNearJump);
+ // Loads the cid of the instance.
+ __ LoadClassId(EAX, EBX);
+
+ Label cid_loaded;
+ __ Bind(&cid_loaded);
+ __ movl(EBX, FieldAddress(ECX, MegamorphicCache::mask_offset()));
+ __ movl(EDI, FieldAddress(ECX, MegamorphicCache::buckets_offset()));
+ // EDI: cache buckets array.
+ // EBX: mask.
+
+ // Tag cid as a smi.
+ __ addl(EAX, EAX);
+
+ // Compute the table index.
+ ASSERT(MegamorphicCache::kSpreadFactor == 7);
+ // Use leal and subl multiply with 7 == 8 - 1.
+ __ leal(EDX, Address(EAX, TIMES_8, 0));
+ __ subl(EDX, EAX);
+
+ Label loop;
+ __ Bind(&loop);
+ __ andl(EDX, EBX);
+
+ const intptr_t base = Array::data_offset();
+ Label probe_failed;
+ // EDX is smi tagged, but table entries are two words, so TIMES_4.
+ __ cmpl(EAX, FieldAddress(EDI, EDX, TIMES_4, base));
+ __ j(NOT_EQUAL, &probe_failed, Assembler::kNearJump);
+
+ Label load_target;
+ __ Bind(&load_target);
+ // Call the target found in the cache. For a class id match, this is a
+ // proper target for the given name and arguments descriptor. If the
+ // illegal class id was found, the target is a cache miss handler that can
+ // be invoked as a normal Dart function.
+ __ movl(EAX, FieldAddress(EDI, EDX, TIMES_4, base + kWordSize));
+ __ movl(EDX,
+ FieldAddress(ECX, MegamorphicCache::arguments_descriptor_offset()));
+ __ movl(EBX, FieldAddress(EAX, Function::entry_point_offset()));
+ __ ret();
+
+ __ Bind(&probe_failed);
+ // Probe failed, check if it is a miss.
+ __ cmpl(FieldAddress(EDI, EDX, TIMES_4, base), Immediate(kIllegalCid));
+ __ j(ZERO, &load_target, Assembler::kNearJump);
+
+ // Try next extry in the table.
+ __ AddImmediate(EDX, Immediate(Smi::RawValue(1)));
+ __ jmp(&loop);
+
+ // Load cid for the Smi case.
+ __ Bind(&smi_case);
+ __ movl(EAX, Immediate(kSmiCid));
+ __ jmp(&cid_loaded);
+}
// Called from switchable IC calls.
// EBX: receiver
diff --git a/runtime/vm/stub_code_mips.cc b/runtime/vm/stub_code_mips.cc
index ef36894..f40dd22 100644
--- a/runtime/vm/stub_code_mips.cc
+++ b/runtime/vm/stub_code_mips.cc
@@ -1403,7 +1403,6 @@
intptr_t num_args,
const RuntimeEntry& handle_ic_miss,
Token::Kind kind,
- RangeCollectionMode range_collection_mode,
bool optimized) {
__ Comment("NArgsCheckInlineCacheStub");
ASSERT(num_args > 0);
@@ -1430,18 +1429,7 @@
__ Bind(&done_stepping);
}
- __ Comment("Range feedback collection");
Label not_smi_or_overflow;
- if (range_collection_mode == kCollectRanges) {
- ASSERT((num_args == 1) || (num_args == 2));
- if (num_args == 2) {
- __ lw(T0, Address(SP, 1 * kWordSize));
- __ UpdateRangeFeedback(T0, 0, S5, T1, ¬_smi_or_overflow);
- }
-
- __ lw(T0, Address(SP, 0 * kWordSize));
- __ UpdateRangeFeedback(T0, num_args - 1, S5, T1, ¬_smi_or_overflow);
- }
if (kind != Token::kILLEGAL) {
EmitFastSmiOp(assembler, kind, num_args, ¬_smi_or_overflow);
}
@@ -1589,35 +1577,8 @@
__ mov(T0, T3);
Label is_compiled;
__ lw(T4, FieldAddress(T0, Function::entry_point_offset()));
- if (range_collection_mode == kCollectRanges) {
- const intptr_t frame_size = num_args + 2;
- __ lw(T3, Address(SP, 0 * kWordSize));
- if (num_args == 2) {
- __ lw(T1, Address(SP, 1 * kWordSize));
- }
- __ EnterStubFrame();
- __ addiu(SP, SP, Immediate(- frame_size * kWordSize));
- __ sw(RA, Address(SP, (frame_size - 1) * kWordSize)); // Return address.
- __ sw(S5, Address(SP, (frame_size - 2) * kWordSize)); // Preserve IC data.
- __ sw(T3, Address(SP, 0 * kWordSize));
- if (num_args == 2) {
- __ sw(T1, Address(SP, 1 * kWordSize));
- }
- __ lw(CODE_REG, FieldAddress(T0, Function::code_offset()));
- __ jalr(T4);
- __ lw(S5, Address(SP, (frame_size - 2) * kWordSize));
- __ lw(RA, Address(SP, (frame_size - 1) * kWordSize));
- Label done;
- __ UpdateRangeFeedback(V0, 2, S5, T1, &done);
- __ Bind(&done);
- __ addiu(SP, SP, Immediate(frame_size * kWordSize));
- __ RestoreCodePointer();
- __ LeaveStubFrame();
- __ Ret();
- } else {
- __ lw(CODE_REG, FieldAddress(T0, Function::code_offset()));
- __ jr(T4);
- }
+ __ lw(CODE_REG, FieldAddress(T0, Function::code_offset()));
+ __ jr(T4);
// Call single step callback in debugger.
if (FLAG_support_debugger && !optimized) {
@@ -1650,60 +1611,35 @@
void StubCode::GenerateOneArgCheckInlineCacheStub(Assembler* assembler) {
GenerateUsageCounterIncrement(assembler, T0);
GenerateNArgsCheckInlineCacheStub(assembler, 1,
- kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL,
- kIgnoreRanges);
+ kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL);
}
void StubCode::GenerateTwoArgsCheckInlineCacheStub(Assembler* assembler) {
GenerateUsageCounterIncrement(assembler, T0);
GenerateNArgsCheckInlineCacheStub(assembler, 2,
- kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL,
- kIgnoreRanges);
+ kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL);
}
void StubCode::GenerateSmiAddInlineCacheStub(Assembler* assembler) {
GenerateUsageCounterIncrement(assembler, T0);
GenerateNArgsCheckInlineCacheStub(assembler, 2,
- kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kADD,
- kCollectRanges);
+ kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kADD);
}
void StubCode::GenerateSmiSubInlineCacheStub(Assembler* assembler) {
GenerateUsageCounterIncrement(assembler, T0);
GenerateNArgsCheckInlineCacheStub(assembler, 2,
- kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kSUB,
- kCollectRanges);
+ kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kSUB);
}
void StubCode::GenerateSmiEqualInlineCacheStub(Assembler* assembler) {
GenerateUsageCounterIncrement(assembler, T0);
GenerateNArgsCheckInlineCacheStub(assembler, 2,
- kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kEQ,
- kIgnoreRanges);
-}
-
-
-void StubCode::GenerateUnaryRangeCollectingInlineCacheStub(
- Assembler* assembler) {
- GenerateUsageCounterIncrement(assembler, T0);
- GenerateNArgsCheckInlineCacheStub(assembler, 1,
- kInlineCacheMissHandlerOneArgRuntimeEntry,
- Token::kILLEGAL,
- kCollectRanges);
-}
-
-
-void StubCode::GenerateBinaryRangeCollectingInlineCacheStub(
- Assembler* assembler) {
- GenerateUsageCounterIncrement(assembler, T0);
- GenerateNArgsCheckInlineCacheStub(assembler, 2,
- kInlineCacheMissHandlerTwoArgsRuntimeEntry,
- Token::kILLEGAL,
- kCollectRanges);
+ kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kEQ);
}
@@ -1712,7 +1648,7 @@
GenerateOptimizedUsageCounterIncrement(assembler);
GenerateNArgsCheckInlineCacheStub(assembler, 1,
kInlineCacheMissHandlerOneArgRuntimeEntry, Token::kILLEGAL,
- kIgnoreRanges, true /* optimized */);
+ true /* optimized */);
}
@@ -1721,7 +1657,7 @@
GenerateOptimizedUsageCounterIncrement(assembler);
GenerateNArgsCheckInlineCacheStub(assembler, 2,
kInlineCacheMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL,
- kIgnoreRanges, true /* optimized */);
+ true /* optimized */);
}
@@ -1801,16 +1737,14 @@
void StubCode::GenerateOneArgUnoptimizedStaticCallStub(Assembler* assembler) {
GenerateUsageCounterIncrement(assembler, T0);
GenerateNArgsCheckInlineCacheStub(
- assembler, 1, kStaticCallMissHandlerOneArgRuntimeEntry, Token::kILLEGAL,
- kIgnoreRanges);
+ assembler, 1, kStaticCallMissHandlerOneArgRuntimeEntry, Token::kILLEGAL);
}
void StubCode::GenerateTwoArgsUnoptimizedStaticCallStub(Assembler* assembler) {
GenerateUsageCounterIncrement(assembler, T0);
GenerateNArgsCheckInlineCacheStub(assembler, 2,
- kStaticCallMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL,
- kIgnoreRanges);
+ kStaticCallMissHandlerTwoArgsRuntimeEntry, Token::kILLEGAL);
}
@@ -2212,7 +2146,14 @@
}
-void StubCode::EmitMegamorphicLookup(Assembler* assembler) {
+// Called from megamorphic calls.
+// T0: receiver
+// S5: MegamorphicCache (preserved)
+// Result:
+// T1: target entry point
+// CODE_REG: target Code
+// S4: arguments descriptor
+void StubCode::GenerateMegamorphicLookupStub(Assembler* assembler) {
__ LoadTaggedClassIdMayBeSmi(T0, T0);
// T0: class ID of the receiver (smi).
__ lw(S4, FieldAddress(S5, MegamorphicCache::arguments_descriptor_offset()));
@@ -2253,18 +2194,6 @@
__ lw(T1, FieldAddress(T0, Function::entry_point_offset()));
__ lw(CODE_REG, FieldAddress(T0, Function::code_offset()));
-}
-
-
-// Called from megamorphic calls.
-// T0: receiver
-// S5: MegamorphicCache (preserved)
-// Result:
-// T1: target entry point
-// CODE_REG: target Code
-// S4: arguments descriptor
-void StubCode::GenerateMegamorphicLookupStub(Assembler* assembler) {
- EmitMegamorphicLookup(assembler);
__ Ret();
}
diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc
index 45edaf4..99393ac 100644
--- a/runtime/vm/stub_code_x64.cc
+++ b/runtime/vm/stub_code_x64.cc
@@ -783,7 +783,6 @@
// Set up arguments for the Dart call.
Label push_arguments;
Label done_push_arguments;
- __ testq(RBX, RBX); // check if there are arguments.
__ j(ZERO, &done_push_arguments, Assembler::kNearJump);
__ movq(RAX, Immediate(0));
__ Bind(&push_arguments);
@@ -1227,8 +1226,7 @@
static void EmitFastSmiOp(Assembler* assembler,
Token::Kind kind,
intptr_t num_args,
- Label* not_smi_or_overflow,
- bool should_update_result_range) {
+ Label* not_smi_or_overflow) {
__ Comment("Fast Smi op");
ASSERT(num_args == 2);
__ movq(RCX, Address(RSP, + 1 * kWordSize)); // Right
@@ -1262,14 +1260,6 @@
default: UNIMPLEMENTED();
}
-
- if (should_update_result_range) {
- Label done;
- __ movq(RSI, RAX);
- __ UpdateRangeFeedback(RSI, 2, RBX, RCX, &done);
- __ Bind(&done);
- }
-
// RBX: IC data object (preserved).
__ movq(R13, FieldAddress(RBX, ICData::ic_data_offset()));
// R13: ic_data_array with check entries: classes and target functions.
@@ -1318,7 +1308,6 @@
intptr_t num_args,
const RuntimeEntry& handle_ic_miss,
Token::Kind kind,
- RangeCollectionMode range_collection_mode,
bool optimized) {
ASSERT(num_args > 0);
#if defined(DEBUG)
@@ -1344,25 +1333,13 @@
__ Bind(&done_stepping);
}
- __ Comment("Range feedback collection");
Label not_smi_or_overflow;
- if (range_collection_mode == kCollectRanges) {
- ASSERT((num_args == 1) || (num_args == 2));
- if (num_args == 2) {
- __ movq(RAX, Address(RSP, + 2 * kWordSize));
- __ UpdateRangeFeedback(RAX, 0, RBX, RCX, ¬_smi_or_overflow);
- }
-
- __ movq(RAX, Address(RSP, + 1 * kWordSize));
- __ UpdateRangeFeedback(RAX, (num_args - 1), RBX, RCX, ¬_smi_or_overflow);
- }
if (kind != Token::kILLEGAL) {
EmitFastSmiOp(
assembler,
kind,
num_args,
- ¬_smi_or_overflow,
- range_collection_mode == kCollectRanges);
+ ¬_smi_or_overflow);
}
__ Bind(¬_smi_or_overflow);
@@ -1475,34 +1452,9 @@
__ Bind(&call_target_function);
// RAX: Target function.
Label is_compiled;
- if (range_collection_mode == kCollectRanges) {
- __ movq(R13, FieldAddress(RAX, Function::code_offset()));
- __ movq(RCX, FieldAddress(RAX, Function::entry_point_offset()));
- __ movq(R8, Address(RSP, + 1 * kWordSize));
- if (num_args == 2) {
- __ movq(R9, Address(RSP, + 2 * kWordSize));
- }
- __ EnterStubFrame();
- __ pushq(RBX);
- if (num_args == 2) {
- __ pushq(R9);
- }
- __ pushq(R8);
- __ movq(CODE_REG, R13);
- __ call(RCX);
-
- Label done;
- __ movq(RDX, RAX);
- __ movq(RBX, Address(RBP, kFirstLocalSlotFromFp * kWordSize));
- __ UpdateRangeFeedback(RDX, 2, RBX, RCX, &done);
- __ Bind(&done);
- __ LeaveStubFrame();
- __ ret();
- } else {
- __ movq(CODE_REG, FieldAddress(RAX, Function::code_offset()));
- __ movq(RCX, FieldAddress(RAX, Function::entry_point_offset()));
- __ jmp(RCX);
- }
+ __ movq(CODE_REG, FieldAddress(RAX, Function::code_offset()));
+ __ movq(RCX, FieldAddress(RAX, Function::entry_point_offset()));
+ __ jmp(RCX);
if (FLAG_support_debugger && !optimized) {
__ Bind(&stepping);
@@ -1531,8 +1483,7 @@
GenerateUsageCounterIncrement(assembler, RCX);
GenerateNArgsCheckInlineCacheStub(assembler, 1,
kInlineCacheMissHandlerOneArgRuntimeEntry,
- Token::kILLEGAL,
- kIgnoreRanges);
+ Token::kILLEGAL);
}
@@ -1540,8 +1491,7 @@
GenerateUsageCounterIncrement(assembler, RCX);
GenerateNArgsCheckInlineCacheStub(assembler, 2,
kInlineCacheMissHandlerTwoArgsRuntimeEntry,
- Token::kILLEGAL,
- kIgnoreRanges);
+ Token::kILLEGAL);
}
@@ -1549,8 +1499,7 @@
GenerateUsageCounterIncrement(assembler, RCX);
GenerateNArgsCheckInlineCacheStub(assembler, 2,
kInlineCacheMissHandlerTwoArgsRuntimeEntry,
- Token::kADD,
- kCollectRanges);
+ Token::kADD);
}
@@ -1558,8 +1507,7 @@
GenerateUsageCounterIncrement(assembler, RCX);
GenerateNArgsCheckInlineCacheStub(assembler, 2,
kInlineCacheMissHandlerTwoArgsRuntimeEntry,
- Token::kSUB,
- kCollectRanges);
+ Token::kSUB);
}
@@ -1567,28 +1515,7 @@
GenerateUsageCounterIncrement(assembler, RCX);
GenerateNArgsCheckInlineCacheStub(assembler, 2,
kInlineCacheMissHandlerTwoArgsRuntimeEntry,
- Token::kEQ,
- kIgnoreRanges);
-}
-
-
-void StubCode::GenerateUnaryRangeCollectingInlineCacheStub(
- Assembler* assembler) {
- GenerateUsageCounterIncrement(assembler, RCX);
- GenerateNArgsCheckInlineCacheStub(assembler, 1,
- kInlineCacheMissHandlerOneArgRuntimeEntry,
- Token::kILLEGAL,
- kCollectRanges);
-}
-
-
-void StubCode::GenerateBinaryRangeCollectingInlineCacheStub(
- Assembler* assembler) {
- GenerateUsageCounterIncrement(assembler, RCX);
- GenerateNArgsCheckInlineCacheStub(assembler, 2,
- kInlineCacheMissHandlerTwoArgsRuntimeEntry,
- Token::kILLEGAL,
- kCollectRanges);
+ Token::kEQ);
}
@@ -1609,7 +1536,7 @@
GenerateNArgsCheckInlineCacheStub(assembler, 1,
kInlineCacheMissHandlerOneArgRuntimeEntry,
Token::kILLEGAL,
- kIgnoreRanges, true /* optimized */);
+ true /* optimized */);
}
@@ -1619,7 +1546,7 @@
GenerateNArgsCheckInlineCacheStub(assembler, 2,
kInlineCacheMissHandlerTwoArgsRuntimeEntry,
Token::kILLEGAL,
- kIgnoreRanges, true /* optimized */);
+ true /* optimized */);
}
@@ -1702,8 +1629,7 @@
assembler,
1,
kStaticCallMissHandlerOneArgRuntimeEntry,
- Token::kILLEGAL,
- kIgnoreRanges);
+ Token::kILLEGAL);
}
@@ -1712,8 +1638,7 @@
GenerateNArgsCheckInlineCacheStub(assembler,
2,
kStaticCallMissHandlerTwoArgsRuntimeEntry,
- Token::kILLEGAL,
- kIgnoreRanges);
+ Token::kILLEGAL);
}
@@ -2083,47 +2008,6 @@
}
-void StubCode::EmitMegamorphicLookup(Assembler* assembler) {
- __ LoadTaggedClassIdMayBeSmi(RAX, RDI);
- // RAX: class ID of the receiver (smi).
- __ movq(R10,
- FieldAddress(RBX, MegamorphicCache::arguments_descriptor_offset()));
- __ movq(RDI, FieldAddress(RBX, MegamorphicCache::buckets_offset()));
- __ movq(R9, FieldAddress(RBX, MegamorphicCache::mask_offset()));
- // R10: arguments descriptor (result).
- // RDI: cache buckets array.
- // RBX: mask.
- __ movq(RCX, RAX);
- __ imulq(RCX, Immediate(MegamorphicCache::kSpreadFactor));
-
- Label loop, update, load_target_function;
- __ jmp(&loop);
-
- __ Bind(&update);
- __ AddImmediate(RCX, Immediate(Smi::RawValue(1)));
- __ Bind(&loop);
- __ andq(RCX, R9);
- const intptr_t base = Array::data_offset();
- // RCX is smi tagged, but table entries are two words, so TIMES_8.
- __ movq(RDX, FieldAddress(RDI, RCX, TIMES_8, base));
-
- ASSERT(kIllegalCid == 0);
- __ testq(RDX, RDX);
- __ j(ZERO, &load_target_function, Assembler::kNearJump);
- __ cmpq(RDX, RAX);
- __ j(NOT_EQUAL, &update, Assembler::kNearJump);
-
- __ Bind(&load_target_function);
- // Call the target found in the cache. For a class id match, this is a
- // proper target for the given name and arguments descriptor. If the
- // illegal class id was found, the target is a cache miss handler that can
- // be invoked as a normal Dart function.
- __ movq(RAX, FieldAddress(RDI, RCX, TIMES_8, base + kWordSize));
- __ movq(RCX, FieldAddress(RAX, Function::entry_point_offset()));
- __ movq(CODE_REG, FieldAddress(RAX, Function::code_offset()));
-}
-
-
// Called from megamorphic calls.
// RDI: receiver
// RBX: MegamorphicCache (preserved)
@@ -2132,8 +2016,68 @@
// CODE_REG: target Code
// R10: arguments descriptor
void StubCode::GenerateMegamorphicLookupStub(Assembler* assembler) {
- EmitMegamorphicLookup(assembler);
+ // Jump if receiver is a smi.
+ Label smi_case;
+ __ testq(RDI, Immediate(kSmiTagMask));
+ // Jump out of line for smi case.
+ __ j(ZERO, &smi_case, Assembler::kNearJump);
+
+ // Loads the cid of the object.
+ __ LoadClassId(RAX, RDI);
+
+ Label cid_loaded;
+ __ Bind(&cid_loaded);
+ __ movq(R9, FieldAddress(RBX, MegamorphicCache::mask_offset()));
+ __ movq(RDI, FieldAddress(RBX, MegamorphicCache::buckets_offset()));
+ // R9: mask.
+ // RDI: cache buckets array.
+
+ // Tag cid as a smi.
+ __ addq(RAX, RAX);
+
+ // Compute the table index.
+ ASSERT(MegamorphicCache::kSpreadFactor == 7);
+ // Use leaq and subq multiply with 7 == 8 - 1.
+ __ leaq(RCX, Address(RAX, TIMES_8, 0));
+ __ subq(RCX, RAX);
+
+ Label loop;
+ __ Bind(&loop);
+ __ andq(RCX, R9);
+
+ const intptr_t base = Array::data_offset();
+ // RCX is smi tagged, but table entries are two words, so TIMES_8.
+ Label probe_failed;
+ __ cmpq(RAX, FieldAddress(RDI, RCX, TIMES_8, base));
+ __ j(NOT_EQUAL, &probe_failed, Assembler::kNearJump);
+
+ Label load_target;
+ __ Bind(&load_target);
+ // Call the target found in the cache. For a class id match, this is a
+ // proper target for the given name and arguments descriptor. If the
+ // illegal class id was found, the target is a cache miss handler that can
+ // be invoked as a normal Dart function.
+ __ movq(RAX, FieldAddress(RDI, RCX, TIMES_8, base + kWordSize));
+ __ movq(R10,
+ FieldAddress(RBX, MegamorphicCache::arguments_descriptor_offset()));
+ __ movq(RCX, FieldAddress(RAX, Function::entry_point_offset()));
+ __ movq(CODE_REG, FieldAddress(RAX, Function::code_offset()));
+
__ ret();
+
+ // Probe failed, check if it is a miss.
+ __ Bind(&probe_failed);
+ __ cmpq(FieldAddress(RDI, RCX, TIMES_8, base), Immediate(kIllegalCid));
+ __ j(ZERO, &load_target, Assembler::kNearJump);
+
+ // Try next extry in the table.
+ __ AddImmediate(RCX, Immediate(Smi::RawValue(1)));
+ __ jmp(&loop);
+
+ // Load cid for the Smi case.
+ __ Bind(&smi_case);
+ __ movq(RAX, Immediate(kSmiCid));
+ __ jmp(&cid_loaded);
}
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 5e6a165..753594c 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -311,6 +311,9 @@
V(TwoNewlines, "\n\n") \
V(TwoSpaces, " ") \
V(_instanceOf, "_instanceOf") \
+ V(_simpleInstanceOf, "_simpleInstanceOf") \
+ V(_simpleInstanceOfTrue, "_simpleInstanceOfTrue") \
+ V(_simpleInstanceOfFalse, "_simpleInstanceOfFalse") \
V(_instanceOfSmi, "_instanceOfSmi") \
V(_instanceOfNum, "_instanceOfNum") \
V(_instanceOfInt, "_instanceOfInt") \
@@ -393,6 +396,7 @@
V(_runPendingImmediateCallback, "_runPendingImmediateCallback") \
V(DartLibrary, "dart.library.") \
V(DartLibraryMirrors, "dart.library.mirrors") \
+ V(_name, "_name") \
// Contains a list of frequently used strings in a canonicalized form. This
diff --git a/runtime/vm/tags.cc b/runtime/vm/tags.cc
index fa3cc67..ccb52ab 100644
--- a/runtime/vm/tags.cc
+++ b/runtime/vm/tags.cc
@@ -137,6 +137,7 @@
}
+#ifndef PRODUCT
void VMTagCounters::PrintToJSONObject(JSONObject* obj) {
if (!FLAG_support_service) {
return;
@@ -154,6 +155,7 @@
}
}
}
+#endif // !PRODUCT
const char* UserTags::TagName(uword tag_id) {
diff --git a/runtime/vm/tags.h b/runtime/vm/tags.h
index 3279c82..8c6ef65 100644
--- a/runtime/vm/tags.h
+++ b/runtime/vm/tags.h
@@ -98,7 +98,9 @@
int64_t count(uword tag);
+#ifndef PRODUCT
void PrintToJSONObject(JSONObject* obj);
+#endif // !PRODUCT
private:
int64_t counters_[VMTag::kNumVMTags];
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index 1ce083a..d9bef66 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -105,6 +105,8 @@
StubCode::UpdateStoreBuffer_entry()->EntryPoint(), 0) \
V(uword, call_to_runtime_entry_point_, \
StubCode::CallToRuntime_entry()->EntryPoint(), 0) \
+ V(uword, megamorphic_lookup_entry_point_, \
+ StubCode::MegamorphicLookup_entry()->EntryPoint(), 0) \
#endif
diff --git a/runtime/vm/thread_test.cc b/runtime/vm/thread_test.cc
index d0deba9..dc2edac 100644
--- a/runtime/vm/thread_test.cc
+++ b/runtime/vm/thread_test.cc
@@ -405,6 +405,25 @@
}
+// Test case for recursive safepoint operations.
+VM_TEST_CASE(RecursiveSafepointTest1) {
+ intptr_t count = 0;
+ {
+ SafepointOperationScope safepoint_scope(thread);
+ count += 1;
+ {
+ SafepointOperationScope safepoint_scope(thread);
+ count += 1;
+ {
+ SafepointOperationScope safepoint_scope(thread);
+ count += 1;
+ }
+ }
+ }
+ EXPECT(count == 3);
+}
+
+
VM_TEST_CASE(ThreadIterator_Count) {
intptr_t thread_count_0 = 0;
intptr_t thread_count_1 = 0;
@@ -525,6 +544,46 @@
}
+// Test recursive safepoint operation scopes with other threads trying
+// to also start a safepoint operation scope.
+VM_TEST_CASE(RecursiveSafepointTest2) {
+ Isolate* isolate = thread->isolate();
+ Monitor monitor;
+ 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, &monitor, &expected_count, &total_done, &exited));
+ }
+ bool all_helpers = false;
+ do {
+ SafepointOperationScope safepoint_scope(thread);
+ {
+ SafepointOperationScope safepoint_scope(thread);
+ MonitorLocker ml(&monitor);
+ if (expected_count == SafepointTestTask::kTaskCount) {
+ all_helpers = true;
+ }
+ }
+ } while (!all_helpers);
+ String& label = String::Handle(String::New("foo"));
+ UserTag& tag = UserTag::Handle(UserTag::New(label));
+ isolate->set_current_tag(tag);
+ bool all_exited = false;
+ do {
+ SafepointOperationScope safepoint_scope(thread);
+ {
+ SafepointOperationScope safepoint_scope(thread);
+ MonitorLocker ml(&monitor);
+ if (exited == SafepointTestTask::kTaskCount) {
+ all_exited = true;
+ }
+ }
+ } while (!all_exited);
+}
+
+
class AllocAndGCTask : public ThreadPool::Task {
public:
AllocAndGCTask(Isolate* isolate,
diff --git a/runtime/vm/unit_test.cc b/runtime/vm/unit_test.cc
index b0c773e..522974e 100644
--- a/runtime/vm/unit_test.cc
+++ b/runtime/vm/unit_test.cc
@@ -269,7 +269,7 @@
{
TransitionNativeToVM transition(Thread::Current());
- isolate->ReloadSources(/* test_mode = */ true);
+ isolate->ReloadSources(/* dont_delete_reload_context = */ true);
}
return Dart_FinalizeLoading(false);
@@ -279,9 +279,8 @@
Dart_Handle TestCase::GetReloadErrorOrRootLibrary() {
Isolate* isolate = Isolate::Current();
- if (isolate->reload_context() != NULL) {
- // We should only have a reload context hanging around if an error occurred.
- ASSERT(isolate->reload_context()->has_error());
+ if (isolate->reload_context() != NULL &&
+ isolate->reload_context()->has_error()) {
// Return a handle to the error.
return Api::NewHandle(Thread::Current(),
isolate->reload_context()->error());
@@ -298,7 +297,14 @@
return result;
}
- return GetReloadErrorOrRootLibrary();
+ result = GetReloadErrorOrRootLibrary();
+
+ Isolate* isolate = Isolate::Current();
+ if (isolate->reload_context() != NULL) {
+ isolate->DeleteReloadContext();
+ }
+
+ return result;
}
@@ -360,6 +366,7 @@
code_ = Code::FinalizeCode(function, assembler_);
code_.set_owner(function);
code_.set_exception_handlers(Object::empty_exception_handlers());
+#ifndef PRODUCT
if (FLAG_disassemble) {
OS::Print("Code for test '%s' {\n", name_);
const Instructions& instructions =
@@ -368,6 +375,7 @@
Disassembler::Disassemble(start, start + assembler_->CodeSize());
OS::Print("}\n");
}
+#endif // !PRODUCT
}
diff --git a/runtime/vm/verifier.cc b/runtime/vm/verifier.cc
index 18a7874..de125bf 100644
--- a/runtime/vm/verifier.cc
+++ b/runtime/vm/verifier.cc
@@ -82,4 +82,22 @@
delete allocated_set;
}
+
+#if defined(DEBUG)
+VerifyCanonicalVisitor::VerifyCanonicalVisitor(Thread* thread)
+ : thread_(thread),
+ instanceHandle_(Instance::Handle(thread->zone())) {
+}
+
+
+void VerifyCanonicalVisitor::VisitObject(RawObject* obj) {
+ if (obj->GetClassId() >= kInstanceCid) {
+ if (obj->IsCanonical()) {
+ instanceHandle_ ^= obj;
+ ASSERT(instanceHandle_.CheckIsCanonical(thread_));
+ }
+ }
+}
+#endif // defined(DEBUG)
+
} // namespace dart
diff --git a/runtime/vm/verifier.h b/runtime/vm/verifier.h
index a34d7f6..8ae222d 100644
--- a/runtime/vm/verifier.h
+++ b/runtime/vm/verifier.h
@@ -81,6 +81,21 @@
DISALLOW_COPY_AND_ASSIGN(VerifyWeakPointersVisitor);
};
+
+#if defined(DEBUG)
+class VerifyCanonicalVisitor : public ObjectVisitor {
+ public:
+ explicit VerifyCanonicalVisitor(Thread* thread);
+ virtual void VisitObject(RawObject* obj);
+
+ private:
+ Thread* thread_;
+ Instance& instanceHandle_;
+
+ DISALLOW_COPY_AND_ASSIGN(VerifyCanonicalVisitor);
+};
+#endif // defined(DEBUG)
+
} // namespace dart
#endif // VM_VERIFIER_H_
diff --git a/runtime/vm/virtual_memory.h b/runtime/vm/virtual_memory.h
index 270d3cf..6e43cb4 100644
--- a/runtime/vm/virtual_memory.h
+++ b/runtime/vm/virtual_memory.h
@@ -24,6 +24,7 @@
// The reserved memory is unmapped on destruction.
~VirtualMemory();
+ int32_t handle() const { return handle_; }
uword start() const { return region_.start(); }
uword end() const { return region_.end(); }
void* address() const { return region_.pointer(); }
@@ -82,9 +83,10 @@
// This constructor is only used internally when reserving new virtual spaces.
// It does not reserve any virtual address space on its own.
- explicit VirtualMemory(const MemoryRegion& region) :
+ explicit VirtualMemory(const MemoryRegion& region, int32_t handle = 0) :
region_(region.pointer(), region.size()),
reserved_size_(region.size()),
+ handle_(handle),
embedder_allocated_(false) { }
MemoryRegion region_;
@@ -93,6 +95,8 @@
// Its start coincides with region_, but its size might not, due to Truncate.
intptr_t reserved_size_;
+ int32_t handle_;
+
static uword page_size_;
// True for a region provided by the embedder.
diff --git a/runtime/vm/virtual_memory_fuchsia.cc b/runtime/vm/virtual_memory_fuchsia.cc
index da32045..933f494 100644
--- a/runtime/vm/virtual_memory_fuchsia.cc
+++ b/runtime/vm/virtual_memory_fuchsia.cc
@@ -7,9 +7,11 @@
#include "vm/virtual_memory.h"
+#include <magenta/syscalls.h>
#include <unistd.h> // NOLINT
#include "platform/assert.h"
+#include "vm/memory_region.h"
#include "vm/os.h"
namespace dart {
@@ -23,13 +25,45 @@
VirtualMemory* VirtualMemory::ReserveInternal(intptr_t size) {
- UNIMPLEMENTED();
- return NULL;
+ mx_handle_t vmo = mx_vm_object_create(size);
+ if (vmo <= 0) {
+ return NULL;
+ }
+
+ // TODO(zra): map with PERM_NONE, when that works, and relax with
+ // Commit and Protect when they are implemented.
+ // Issue MG-161.
+ const int prot = MX_VM_FLAG_PERM_READ |
+ MX_VM_FLAG_PERM_WRITE |
+ MX_VM_FLAG_PERM_EXECUTE;
+ uintptr_t addr;
+ mx_status_t status = mx_process_vm_map(0, vmo, 0, size, &addr, prot);
+ if (status != NO_ERROR) {
+ mx_handle_close(vmo);
+ FATAL("VirtualMemory::ReserveInternal FAILED");
+ return NULL;
+ }
+
+ MemoryRegion region(reinterpret_cast<void*>(addr), size);
+ return new VirtualMemory(region, vmo);
}
VirtualMemory::~VirtualMemory() {
- UNIMPLEMENTED();
+ if (!embedder_allocated()) {
+ // TODO(zra): Use reserved_size_.
+ // Issue MG-162.
+ mx_status_t status = mx_process_vm_unmap(
+ 0, reinterpret_cast<uintptr_t>(address()), 0 /*reserved_size_*/);
+ if (status != NO_ERROR) {
+ FATAL("VirtualMemory::~VirtualMemory: unamp FAILED");
+ }
+
+ status = mx_handle_close(handle());
+ if (status != NO_ERROR) {
+ FATAL("VirtualMemory::~VirtualMemory: handle_close FAILED");
+ }
+ }
}
@@ -40,14 +74,15 @@
bool VirtualMemory::Commit(uword addr, intptr_t size, bool executable) {
- UNIMPLEMENTED();
- return false;
+ // TODO(zra): Implement when the protections for a mapping can be changed.
+ // Issue MG-133.
+ return true;
}
bool VirtualMemory::Protect(void* address, intptr_t size, Protection mode) {
- UNIMPLEMENTED();
- return false;
+ // TODO(zra): Implement when Fuchsia has an mprotect-like call.
+ return true;
}
} // namespace dart
diff --git a/samples-dev/swarm/UIState.dart b/samples-dev/swarm/UIState.dart
index dffb1c7..2d40843 100644
--- a/samples-dev/swarm/UIState.dart
+++ b/samples-dev/swarm/UIState.dart
@@ -60,7 +60,8 @@
// TODO(jmesserly): [state] should be an Object, and we should pass it to
// the state parameter instead of as a #hash URL. Right now we're working
// around b/4582542.
- window.history.pushState(null, '${document.title}#$state');
+ window.history.pushState(null,
+ '${document.title}', '${document.title}#$state');
}
/**
diff --git a/samples-dev/swarm/swarm_ui_lib/touch/FxUtil.dart b/samples-dev/swarm/swarm_ui_lib/touch/FxUtil.dart
index 82d0a54..aa084e8 100644
--- a/samples-dev/swarm/swarm_ui_lib/touch/FxUtil.dart
+++ b/samples-dev/swarm/swarm_ui_lib/touch/FxUtil.dart
@@ -68,11 +68,18 @@
*/
static Coordinate computeRelativePosition(Element element, Element target) {
final testPoint = new Point(0, 0);
+ /*
final pagePoint =
window.convertPointFromNodeToPage(element, testPoint);
final pointRelativeToTarget =
window.convertPointFromPageToNode(target, pagePoint);
return new Coordinate(pointRelativeToTarget.x, pointRelativeToTarget.y);
+ */
+ // TODO(sra): Test this version that avoids the nonstandard
+ // `convertPointFromPageToNode`.
+ var eRect = element.getBoundingClientRect();
+ var tRect = target.getBoundingClientRect();
+ return new Coordinate(eRect.left - tRect.left, eRect.top - tRect.top);
}
/** Clear a -webkit-transform from an element. */
diff --git a/samples-dev/swarm/swarm_ui_lib/touch/Scrollbar.dart b/samples-dev/swarm/swarm_ui_lib/touch/Scrollbar.dart
index 1c2a6f2..1ac758c 100644
--- a/samples-dev/swarm/swarm_ui_lib/touch/Scrollbar.dart
+++ b/samples-dev/swarm/swarm_ui_lib/touch/Scrollbar.dart
@@ -155,7 +155,7 @@
}
}
- void _onStart(UIEvent e) {
+ void _onStart(/*MouseEvent | Touch*/ e) {
Element elementOver = e.target;
if (elementOver == _verticalElement ||
elementOver == _horizontalElement) {
@@ -196,7 +196,7 @@
}
}
- void _onMove(UIEvent e) {
+ void _onMove(/*MouseEvent | Touch*/ e) {
if (!_scrollBarDragInProgress) {
return;
}
diff --git a/samples-dev/swarm/swarm_ui_lib/touch/TouchUtil.dart b/samples-dev/swarm/swarm_ui_lib/touch/TouchUtil.dart
index d7992f7..8b82181 100644
--- a/samples-dev/swarm/swarm_ui_lib/touch/TouchUtil.dart
+++ b/samples-dev/swarm/swarm_ui_lib/touch/TouchUtil.dart
@@ -271,4 +271,5 @@
Point get page { throw new UnimplementedError(); }
List get path { throw new UnimplementedError(); }
Point get screen { throw new UnimplementedError(); }
+ /*InputDevice*/ get sourceDevice { throw new UnimplementedError(); }
}
diff --git a/sdk/bin/pub b/sdk/bin/pub
index 50f0d1d..a8514ea 100755
--- a/sdk/bin/pub
+++ b/sdk/bin/pub
@@ -29,6 +29,13 @@
unset VM_OPTIONS
declare -a VM_OPTIONS
+if [[ `uname` == 'Darwin' ]];
+then
+ OUT_DIR="$BIN_DIR"/../../xcodebuild/
+else
+ OUT_DIR="$BIN_DIR"/../../out/
+fi
+
# Allow extra VM options to be passed in through an environment variable.
if [[ $DART_VM_OPTIONS ]]; then
read -a OPTIONS <<< "$DART_VM_OPTIONS"
@@ -37,7 +44,29 @@
if [ -z "$DART_CONFIGURATION" ];
then
- DART_CONFIGURATION="ReleaseX64"
+ DIRS=$( ls "$OUT_DIR" )
+ # list of possible configurations in decreasing desirability
+ CONFIGS=("ReleaseX64" "ReleaseIA32" "DebugX64" "DebugIA32"
+ "ReleaseARM" "ReleaseARM64" "ReleaseARMV5TE" "ReleaseMIPS"
+ "DebugARM" "DebugARM64" "DebugARMV5TE" "DebugMIPS")
+ DART_CONFIGURATION="None"
+ for CONFIG in ${CONFIGS[*]}
+ do
+ for DIR in $DIRS;
+ do
+ if [ "$CONFIG" = "$DIR" ];
+ then
+ # choose most desirable configuration that is available and break
+ DART_CONFIGURATION="$DIR"
+ break 2
+ fi
+ done
+ done
+ if [ "$DART_CONFIGURATION" = "None" ]
+ then
+ echo "No valid dart configuration found in $OUT_DIR"
+ exit 1
+ fi
fi
if [[ `uname` == 'Darwin' ]];
diff --git a/sdk/lib/_internal/js_runtime/lib/js_number.dart b/sdk/lib/_internal/js_runtime/lib/js_number.dart
index 907da4e..1f9748c 100644
--- a/sdk/lib/_internal/js_runtime/lib/js_number.dart
+++ b/sdk/lib/_internal/js_runtime/lib/js_number.dart
@@ -66,20 +66,55 @@
int toInt() {
if (this >= _MIN_INT32 && this <= _MAX_INT32) {
+ // 0 and -0.0 handled here.
return JS('int', '# | 0', this);
}
if (JS('bool', r'isFinite(#)', this)) {
return JS('int', r'# + 0', truncateToDouble()); // Converts -0.0 to +0.0.
}
- // This is either NaN, Infinity or -Infinity.
- throw new UnsupportedError(JS("String", '"" + #', this));
+ // [this] is either NaN, Infinity or -Infinity.
+ throw new UnsupportedError(JS("String", '"" + # + ".toInt()"', this));
}
int truncate() => toInt();
- int ceil() => ceilToDouble().toInt();
+ int ceil() {
+ if (this >= 0) {
+ if (this <= _MAX_INT32) {
+ int truncated = JS('int', '# | 0', this); // converts -0.0 to 0.
+ return this == truncated ? truncated : truncated + 1;
+ }
+ } else {
+ if (this >= _MIN_INT32) {
+ return JS('int', '# | 0', this);
+ }
+ }
+ var d = JS('num', 'Math.ceil(#)', this);
+ if (JS('bool', r'isFinite(#)', d)) {
+ return JS('int', r'#', d);
+ }
+ // [this] is either NaN, Infinity or -Infinity.
+ throw new UnsupportedError(JS("String", '"" + # + ".ceil()"', this));
+ }
- int floor() => floorToDouble().toInt();
+ int floor() {
+ if (this >= 0) {
+ if (this <= _MAX_INT32) {
+ return JS('int', '# | 0', this);
+ }
+ } else {
+ if (this >= _MIN_INT32) {
+ int truncated = JS('int', '# | 0', this);
+ return this == truncated ? truncated : truncated - 1;
+ }
+ }
+ var d = JS('num', 'Math.floor(#)', this);
+ if (JS('bool', r'isFinite(#)', d)) {
+ return JS('int', r'#', d);
+ }
+ // [this] is either NaN, Infinity or -Infinity.
+ throw new UnsupportedError(JS("String", '"" + # + ".floor()"', this));
+ }
int round() {
if (this > 0) {
@@ -96,8 +131,8 @@
// some JavaScript VMs can be a slow path.
return JS('int', r'0 - Math.round(0 - #)', this);
}
- // This is either NaN, Infinity or -Infinity.
- throw new UnsupportedError(JS("String", '"" + #', this));
+ // [this] is either NaN, Infinity or -Infinity.
+ throw new UnsupportedError(JS("String", '"" + # + ".round()"', this));
}
double ceilToDouble() => JS('num', r'Math.ceil(#)', this);
@@ -246,23 +281,43 @@
bool _isInt32(value) => JS('bool', '(# | 0) === #', value, value);
int operator ~/(num other) {
+ if (other is !num) throw argumentErrorValue(other);
if (false) _tdivFast(other); // Ensure resolution.
- if (_isInt32(this) && _isInt32(other) && 0 != other && -1 != other) {
- return JS('int', r'(# / #) | 0', this, other);
- } else {
- return _tdivSlow(other);
+ if (_isInt32(this)) {
+ if (other >= 1 || other < -1) {
+ return JS('int', r'(# / #) | 0', this, other);
+ }
}
+ return _tdivSlow(other);
}
int _tdivFast(num other) {
+ // [other] is known to be a number outside the range [-1, 1).
return _isInt32(this)
? JS('int', r'(# / #) | 0', this, other)
- : (JS('num', r'# / #', this, other)).toInt();
+ : _tdivSlow(other);
}
int _tdivSlow(num other) {
- if (other is !num) throw argumentErrorValue(other);
- return (JS('num', r'# / #', this, other)).toInt();
+ var quotient = JS('num', r'# / #', this, other);
+ if (quotient >= _MIN_INT32 && quotient <= _MAX_INT32) {
+ // This path includes -0.0 and +0.0.
+ return JS('int', '# | 0', quotient);
+ }
+ if (quotient > 0) {
+ // This path excludes the special cases -0.0, NaN and -Infinity, leaving
+ // only +Infinity, for which a direct test is faster than [isFinite].
+ if (JS('bool', r'# !== (1/0)', quotient)) {
+ return JS('int', r'Math.floor(#)', quotient);
+ }
+ } else if (JS('bool', '# > (-1/0)', quotient)) {
+ // This test excludes NaN and -Infinity.
+ return JS('int', r'Math.ceil(#)', quotient);
+ }
+
+ // [quotient] is either NaN, Infinity or -Infinity.
+ throw new UnsupportedError(
+ "Result of truncating division is $quotient: $this ~/ $other");
}
// TODO(ngeoffray): Move the bit operations below to [JSInt] and
diff --git a/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart b/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart
index e304873..0ecb55805 100644
--- a/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart
+++ b/sdk/lib/_internal/sdk_library_metadata/lib/libraries.dart
@@ -116,6 +116,12 @@
maturity: Maturity.STABLE,
dart2jsPath: "js/dart2js/js_dart2js.dart"),
+ "js_util": const LibraryInfo(
+ "js_util/dartium/js_util_dartium.dart",
+ categories: "Client",
+ maturity: Maturity.STABLE,
+ dart2jsPath: "js_util/dart2js/js_util_dart2js.dart"),
+
"math": const LibraryInfo(
"math/math.dart",
categories: "Client,Server,Embedded",
diff --git a/sdk/lib/async/zone.dart b/sdk/lib/async/zone.dart
index 24f83f8..b81a7fe 100644
--- a/sdk/lib/async/zone.dart
+++ b/sdk/lib/async/zone.dart
@@ -194,14 +194,26 @@
}
/**
- * This class wraps zones for delegation.
+ * An adapted view of the parent zone.
*
- * When forwarding to parent zones one can't just invoke the parent zone's
- * exposed functions (like [Zone.run]), but one needs to provide more
- * information (like the zone the `run` was initiated). Zone callbacks thus
- * receive more information including this [ZoneDelegate] class. When delegating
- * to the parent zone one should go through the given instance instead of
- * directly invoking the parent zone.
+ * This class allows the implementation of a zone method to invoke methods on
+ * the parent zone while retaining knowledge of the originating zone.
+ *
+ * Custom zones (created through [Zone.fork] or [runZoned]) can provide
+ * implementations of most methods of zones. This is similar to overriding
+ * methods on [Zone], except that this mechanism doesn't require subclassing.
+ *
+ * A custom zone function (provided through a [ZoneSpecification]) typically
+ * records or wraps its parameters and then delegates the operation to its
+ * parent zone using the provided [ZoneDelegate].
+ *
+ * While zones have access to their parent zone (through [Zone.parent]) it is
+ * recommended to call the methods on the provided parent delegate for two
+ * reasons:
+ * 1. the delegate methods take an additional `zone` argument which is the
+ * zone the action has been initiated in.
+ * 2. delegate calls are more efficient, since the implementation knows how
+ * to skip zones that would just delegate to their parents.
*/
abstract class ZoneDelegate {
/*=R*/ handleUncaughtError/*<R>*/(
@@ -224,117 +236,266 @@
}
/**
- * A Zone represents the asynchronous version of a dynamic extent. Asynchronous
- * callbacks are executed in the zone they have been queued in. For example,
- * the callback of a `future.then` is executed in the same zone as the one where
- * the `then` was invoked.
+ * A zone represents an environment that remains stable across asynchronous
+ * calls.
+ *
+ * Code is always executed in the context of a zone, available as
+ * [Zone.current]. The initial `main` function runs in the context of the
+ * default zone ([Zone.ROOT]). Code can be run in a different zone using either
+ * [runZoned], to create a new zone, or [Zone.run] to run code in the context of
+ * an existing zone likely created using [Zone.fork].
+ *
+ * Developers can create a new zone that overrides some of the functionality of
+ * an existing zone. For example, custom zones can replace of modify the
+ * behavior of `print`, timers, microtasks or how uncaught errors are handled.
+ *
+ * The [Zone] class is not subclassable, but users can provide custom zones by
+ * forking an existing zone (usually [Zone.current]) with a [ZoneSpecification].
+ * This is similar to creating a new class that extends the base `Zone` class
+ * and that overrides some methods, except without actually creating a new
+ * class. Instead the overriding methods are provided as functions that
+ * explicitly take the equivalent of their own class, the "super" class and the
+ * `this` object as parameters.
+ *
+ * Asynchronous callbacks always run in the context of the zone where they were
+ * scheduled. This is implemented using two steps:
+ * 1. the callback is first registered using one of [registerCallback],
+ * [registerUnaryCallback], or [registerBinaryCallback]. This allows the zone
+ * to record that a callback exists and potentially modify it (by returning a
+ * different callback). The code doing the registration (e.g., `Future.then`)
+ * also remembers the current zone so that it can later run the callback in
+ * that zone.
+ * 2. At a later point the registered callback is run in the remembered zone.
+ *
+ * This is all handled internally by the platform code and most users don't need
+ * to worry about it. However, developers of new asynchronous operations,
+ * provided by the underlying system or through native extensions, must follow
+ * the protocol to be zone compatible.
+ *
+ * For convenience, zones provide [bindCallback] (and the corresponding
+ * [bindUnaryCallback] or [bindBinaryCallback]) to make it easier to respect the
+ * zone contract: these functions first invoke the corresponding `register`
+ * functions and then wrap the returned function so that it runs in the current
+ * zone when it is later asynchronously invoked.
*/
abstract class Zone {
// Private constructor so that it is not possible instantiate a Zone class.
Zone._();
- /** The root zone that is implicitly created. */
+ /**
+ * The root zone.
+ *
+ * All isolate entry functions (`main` or spawned functions) start running in
+ * the root zone (that is, [Zone.current] is identical to [Zone.ROOT] when the
+ * entry function is called). If no custom zone is created, the rest of the
+ * program always runs in the root zone.
+ *
+ * The root zone implements the default behavior of all zone operations.
+ * Many methods, like [registerCallback] do the bare minimum required of the
+ * function, and are only provided as a hook for custom zones. Others, like
+ * [scheduleMicrotask], interact with the underlying system to implement the
+ * desired behavior.
+ */
static const Zone ROOT = _ROOT_ZONE;
/** The currently running zone. */
static Zone _current = _ROOT_ZONE;
+ /** The zone that is currently active. */
static Zone get current => _current;
+ /**
+ * Handles uncaught asynchronous errors.
+ *
+ * There are two kind of asynchronous errors that are handled by this
+ * function:
+ * 1. Uncaught errors that were thrown in asynchronous callbacks, for example,
+ * a `throw` in the function passed to [Timer.run].
+ * 2. Asynchronous errors that are pushed through [Future] and [Stream]
+ * chains, but for which no child registered an error handler.
+ * Most asynchronous classes, like [Future] or [Stream] push errors to their
+ * listeners. Errors are propagated this way until either a listener handles
+ * the error (for example with [Future.catchError]), or no listener is
+ * available anymore. In the latter case, futures and streams invoke the
+ * zone's [handleUncaughtError].
+ *
+ * By default, when handled by the root zone, uncaught asynchronous errors are
+ * treated like uncaught synchronous exceptions.
+ */
/*=R*/ handleUncaughtError/*<R>*/(error, StackTrace stackTrace);
/**
- * Returns the parent zone.
+ * The parent zone of the this zone.
*
- * Returns `null` if `this` is the [ROOT] zone.
+ * Is `null` if `this` is the [ROOT] zone.
+ *
+ * Zones are created by [fork] on an existing zone, or by [runZoned] which
+ * forks the [current] zone. The new zone's parent zone is the zone it was
+ * forked from.
*/
Zone get parent;
/**
* The error zone is the one that is responsible for dealing with uncaught
* errors.
- * Errors are not allowed to cross between zones with different error-zones.
*
- * This is the closest parent or ancestor zone of this zone that has a custom
+ * This is the closest parent zone of this zone that provides a
* [handleUncaughtError] method.
+ *
+ * Asynchronous errors never cross zone boundaries between zones with
+ * different error handlers.
+ *
+ * Example:
+ * ```
+ * import 'dart:async';
+ *
+ * main() {
+ * var future;
+ * runZoned(() {
+ * // The asynchronous error is caught by the custom zone which prints
+ * // 'asynchronous error'.
+ * future = new Future.error("asynchronous error");
+ * }, onError: (e) { print(e); }); // Creates a zone with an error handler.
+ * // The following `catchError` handler is never invoked, because the
+ * // custom zone created by the call to `runZoned` provides an
+ * // error handler.
+ * future.catchError((e) { throw "is never reached"; });
+ * }
+ * ```
+ *
+ * Note that errors cannot enter a child zone with a different error handler
+ * either:
+ * ```
+ * import 'dart:async';
+ *
+ * main() {
+ * runZoned(() {
+ * // The following asynchronous error is *not* caught by the `catchError`
+ * // in the nested zone, since errors are not to cross zone boundaries
+ * // with different error handlers.
+ * // Instead the error is handled by the current error handler,
+ * // printing "Caught by outer zone: asynchronous error".
+ * var future = new Future.error("asynchronous error");
+ * runZoned(() {
+ * future.catchError((e) { throw "is never reached"; });
+ * }, onError: (e) { throw "is never reached"; });
+ * }, onError: (e) { print("Caught by outer zone: $e"); });
+ * }
+ * ```
*/
Zone get errorZone;
/**
* Returns true if `this` and [otherZone] are in the same error zone.
*
- * Two zones are in the same error zone if they inherit their
- * [handleUncaughtError] callback from the same [errorZone].
+ * Two zones are in the same error zone if they have the same [errorZone].
*/
bool inSameErrorZone(Zone otherZone);
/**
* Creates a new zone as a child of `this`.
*
- * The new zone will have behavior like the current zone, except where
- * overridden by functions in [specification].
+ * The new zone uses the closures in the given [specification] to override
+ * the current's zone behavior. All specification entries that are `null`
+ * inherit the behavior from the parent zone (`this`).
*
- * The new zone will have the same stored values (accessed through
- * `operator []`) as this zone, but updated with the keys and values
- * in [zoneValues]. If a key is in both this zone's values and in
- * `zoneValues`, the new zone will use the value from `zoneValues``.
+ * The new zone inherits the stored values (accessed through [operator []])
+ * of this zone and updates them with values from [zoneValues], which either
+ * adds new values or overrides existing ones.
+ *
+ * Note that the fork operation is interceptible. A zone can thus change
+ * the zone specification (or zone values), giving the forking zone full
+ * control over the child zone.
*/
- Zone fork({ ZoneSpecification specification,
- Map zoneValues });
+ Zone fork({ZoneSpecification specification,
+ Map zoneValues});
/**
- * Executes the given function [f] in this zone.
+ * Executes [action] in this zone.
+ *
+ * By default (as implemented in the [ROOT] zone), runs [action]
+ * with [current] set to this zone.
+ *
+ * If [action] throws, the synchronous exception is not caught by the zone's
+ * error handler. Use [runGuarded] to achieve that.
+ *
+ * Since the root zone is the only zone that can modify the value of
+ * [current], custom zones intercepting run should always delegate to their
+ * parent zone. They may take actions before and after the call.
*/
- /*=R*/ run/*<R>*/(/*=R*/ f());
+ /*=R*/ run/*<R>*/(/*=R*/ action());
/**
- * Executes the given callback [f] with argument [arg] in this zone.
+ * Executes the given [action] with [argument] in this zone.
+ *
+ * As [run] except that [action] is called with one [argument] instead of
+ * none.
*/
- /*=R*/ runUnary/*<R, T>*/(/*=R*/ f(/*=T*/ arg), /*=T*/ arg);
+ /*=R*/ runUnary/*<R, T>*/(/*=R*/ action(/*=T*/ argument), /*=T*/ argument);
/**
- * Executes the given callback [f] with argument [arg1] and [arg2] in this
+ * Executes the given [action] with [argument1] and [argument2] in this
* zone.
+ *
+ * As [run] except that [action] is called with two arguments instead of none.
*/
/*=R*/ runBinary/*<R, T1, T2>*/(
- /*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2), /*=T1*/ arg1, /*=T2*/ arg2);
+ /*=R*/ action(/*=T1*/ argument1, /*=T2*/ argument2), /*=T1*/ argument1,
+ /*=T2*/ argument2);
/**
- * Executes the given function [f] in this zone.
+ * Executes the given [action] in this zone and catches synchronous
+ * errors.
*
- * Same as [run] but catches uncaught errors and gives them to
- * [handleUncaughtError].
+ * This function is equivalent to:
+ * ```
+ * try {
+ * return this.run(action);
+ * } catch (e, s) {
+ * return this.handleUncaughtError(e, s);
+ * }
+ * ```
+ *
+ * See [run].
*/
- /*=R*/ runGuarded/*<R>*/(/*=R*/ f());
+ /*=R*/ runGuarded/*<R>*/(/*=R*/ action());
/**
- * Executes the given callback [f] in this zone.
+ * Executes the given [action] with [argument] in this zone and
+ * catches synchronous errors.
*
- * Same as [runUnary] but catches uncaught errors and gives them to
- * [handleUncaughtError].
+ * See [runGuarded].
*/
- /*=R*/ runUnaryGuarded/*<R, T>*/(/*=R*/ f(/*=T*/ arg), /*=T*/ arg);
+ /*=R*/ runUnaryGuarded/*<R, T>*/(/*=R*/ action(/*=T*/ argument),
+ /*=T*/ argument);
/**
- * Executes the given callback [f] in this zone.
+ * Executes the given [action] with [argument1] and [argument2] in this
+ * zone and catches synchronous errors.
*
- * Same as [runBinary] but catches uncaught errors and gives them to
- * [handleUncaughtError].
+ * See [runGuarded].
*/
/*=R*/ runBinaryGuarded/*<R, T1, T2>*/(
- /*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2), /*=T1*/ arg1, /*=T2*/ arg2);
+ /*=R*/ action(/*=T1*/ argument1, /*=T2*/ argument2), /*=T1*/ argument1,
+ /*=T2*/ argument2);
/**
* Registers the given callback in this zone.
*
- * It is good practice to register asynchronous or delayed callbacks before
- * invoking [run]. This gives the zone a chance to wrap the callback and
- * to store information with the callback. For example, a zone may decide
+ * When implementing an asynchronous primitive that uses callbacks, the
+ * callback must be registered using [registerCallback] at the point where the
+ * user provides the callback. This allows zones to record other information
+ * that they need at the same time, perhaps even wrapping the callback, so
+ * that the callback is prepared when it is later run in the same zones
+ * (using [run]). For example, a zone may decide
* to store the stack trace (at the time of the registration) with the
* callback.
*
- * Returns a potentially new callback that should be used in place of the
- * given [callback].
+ * Returns the callback that should be used in place of the provided
+ * [callback]. Frequently zones simply return the original callback.
+ *
+ * Custom zones may intercept this operation. The default implementation in
+ * [Zone.ROOT] returns the original callback unchanged.
*/
ZoneCallback/*<R>*/ registerCallback/*<R>*/(/*=R*/ callback());
@@ -357,58 +518,79 @@
/**
* Equivalent to:
*
- * ZoneCallback registered = registerCallback(f);
+ * ZoneCallback registered = this.registerCallback(action);
* if (runGuarded) return () => this.runGuarded(registered);
* return () => this.run(registered);
*
*/
ZoneCallback/*<R>*/ bindCallback/*<R>*/(
- /*=R*/ f(), { bool runGuarded: true });
+ /*=R*/ action(), { bool runGuarded: true });
/**
* Equivalent to:
*
- * ZoneCallback registered = registerUnaryCallback(f);
+ * ZoneCallback registered = this.registerUnaryCallback(action);
* if (runGuarded) return (arg) => this.runUnaryGuarded(registered, arg);
* return (arg) => thin.runUnary(registered, arg);
*/
ZoneUnaryCallback/*<R, T>*/ bindUnaryCallback/*<R, T>*/(
- /*=R*/ f(/*=T*/ arg), { bool runGuarded: true });
+ /*=R*/ action(/*=T*/ argument), { bool runGuarded: true });
/**
* Equivalent to:
*
- * ZoneCallback registered = registerBinaryCallback(f);
+ * ZoneCallback registered = registerBinaryCallback(action);
* if (runGuarded) {
* return (arg1, arg2) => this.runBinaryGuarded(registered, arg);
* }
* return (arg1, arg2) => thin.runBinary(registered, arg1, arg2);
*/
ZoneBinaryCallback/*<R, T1, T2>*/ bindBinaryCallback/*<R, T1, T2>*/(
- /*=R*/ f(/*=T1*/ arg1, /*=T2*/ arg2), { bool runGuarded: true });
+ /*=R*/ action(/*=T1*/ argument1, /*=T2*/ argument2),
+ { bool runGuarded: true });
/**
- * Intercepts errors when added programmatically to a `Future` or `Stream`.
+ * Intercepts errors when added programatically to a `Future` or `Stream`.
*
- * When caling [Completer.completeError], [Stream.addError],
- * or [Future] constructors that take an error or a callback that may throw,
- * the current zone is allowed to intercept and replace the error.
+ * When calling [Completer.completeError], [Stream.addError],
+ * or some [Future] constructors, the current zone is allowed to intercept
+ * and replace the error.
*
- * When other libraries use intermediate controllers or completers, such
- * calls may contain errors that have already been processed.
+ * Future constructors invoke this function when the error is received
+ * directly, for example with [Future.error], or when the error is caught
+ * synchronously, for example with [Future.sync].
*
- * Return `null` if no replacement is desired.
- * The original error is used unchanged in that case.
- * Otherwise return an instance of [AsyncError] holding
- * the new pair of error and stack trace.
- * If the [AsyncError.error] is `null`, it is replaced by a [NullThrownError].
+ * There is no guarantee that an error is only sent through [errorCallback]
+ * once. Libraries that use intermediate controllers or completers might
+ * end up invoking [errorCallback] multiple times.
+ *
+ * Returns `null` if no replacement is desired. Otherwise returns an instance
+ * of [AsyncError] holding the new pair of error and stack trace.
+ *
+ * Although not recommended, the returned instance may have its `error` member
+ * ([AsyncError.error]) be equal to `null` in which case the error should be
+ * replaced by a [NullThrownError].
+ *
+ * Custom zones may intercept this operation.
+ *
+ * Implementations of a new asynchronous primitive that converts synchronous
+ * errors to asynchronous errors rarely need to invoke [errorCallback], since
+ * errors are usually reported through future completers or stream
+ * controllers.
*/
AsyncError errorCallback(Object error, StackTrace stackTrace);
/**
- * Runs [f] asynchronously in this zone.
+ * Runs [action] asynchronously in this zone.
+ *
+ * The global `scheduleMicrotask` delegates to the current zone's
+ * [scheduleMicrotask]. The root zone's implementation interacts with the
+ * underlying system to schedule the given callback as a microtask.
+ *
+ * Custom zones may intercept this operation (for example to wrap the given
+ * callback [action]).
*/
- void scheduleMicrotask(void f());
+ void scheduleMicrotask(void action());
/**
* Creates a Timer where the callback is executed in this zone.
@@ -422,6 +604,24 @@
/**
* Prints the given [line].
+ *
+ * The global `print` function delegates to the current zone's [print]
+ * function which makes it possible to intercept printing.
+ *
+ * Example:
+ * ```
+ * import 'dart:async';
+ *
+ * main() {
+ * runZoned(() {
+ * // Ends up printing: "Intercepted: in zone".
+ * print("in zone");
+ * }, zoneSpecification: new ZoneSpecification(
+ * print: (Zone self, ZoneDelegate parent, Zone zone, String line) {
+ * parent.print(zone, "Intercepted: $line");
+ * }));
+ * }
+ * ```
*/
void print(String line);
diff --git a/sdk/lib/core/uri.dart b/sdk/lib/core/uri.dart
index 5718ca8..456bcb7 100644
--- a/sdk/lib/core/uri.dart
+++ b/sdk/lib/core/uri.dart
@@ -669,9 +669,9 @@
* With non-Windows semantics the slash ("/") is used to separate
* path segments.
*
- * With Windows semantics, backslash ("\") and forward-slash ("/")
+ * With Windows semantics, backslash ("\\") and forward-slash ("/")
* are used to separate path segments, except if the path starts
- * with "\\?\" in which case, only backslash ("\") separates path
+ * with "\\\\?\\" in which case, only backslash ("\\") separates path
* segments.
*
* If the path starts with a path separator an absolute URI is
@@ -1878,7 +1878,7 @@
* For non-Windows semantics the slash ("/") is used to separate
* path segments.
*
- * For Windows semantics the backslash ("\") separator is used to
+ * For Windows semantics the backslash ("\\") separator is used to
* separate path segments.
*
* If the URI is absolute the path starts with a path separator
diff --git a/sdk/lib/dart2dart.platform b/sdk/lib/dart2dart.platform
index fd9d8ed..d9aaa19 100644
--- a/sdk/lib/dart2dart.platform
+++ b/sdk/lib/dart2dart.platform
@@ -25,6 +25,7 @@
io: io/io.dart
isolate: isolate/isolate.dart
js: js/dart2js/js_dart2js.dart
+js_util: js_util/dart2js/js_util_dart2js.dart
math: math/math.dart
mirrors: mirrors/mirrors.dart
nativewrappers: html/dart2js/nativewrappers.dart
diff --git a/sdk/lib/dart_client.platform b/sdk/lib/dart_client.platform
index 2e01cd9..38442ef 100644
--- a/sdk/lib/dart_client.platform
+++ b/sdk/lib/dart_client.platform
@@ -26,6 +26,7 @@
io: unsupported:
isolate: isolate/isolate.dart
js: js/dart2js/js_dart2js.dart
+js_util: js_util/dart2js/js_util_dart2js.dart
math: math/math.dart
mirrors: mirrors/mirrors.dart
nativewrappers: html/dart2js/nativewrappers.dart
diff --git a/sdk/lib/dart_server.platform b/sdk/lib/dart_server.platform
index 821a175..f275aff 100644
--- a/sdk/lib/dart_server.platform
+++ b/sdk/lib/dart_server.platform
@@ -35,6 +35,7 @@
web_sql: unsupported:
_chrome: unsupported:
js: unsupported:
+js_util: unsupported:
_mirror_helper: unsupported:
_internal: internal/internal.dart
_js_helper: _internal/js_runtime/lib/js_helper.dart
diff --git a/sdk/lib/dart_shared.platform b/sdk/lib/dart_shared.platform
index 539b868..ae47359 100644
--- a/sdk/lib/dart_shared.platform
+++ b/sdk/lib/dart_shared.platform
@@ -24,6 +24,7 @@
io: io/io.dart
isolate: isolate/isolate.dart
js: js/dart2js/js_dart2js.dart
+js_util: js_util/dart2js/js_util_dart2js.dart
math: math/math.dart
mirrors: mirrors/mirrors.dart
nativewrappers: html/dart2js/nativewrappers.dart
diff --git a/sdk/lib/io/file.dart b/sdk/lib/io/file.dart
index 92d144f..73668e9 100644
--- a/sdk/lib/io/file.dart
+++ b/sdk/lib/io/file.dart
@@ -582,9 +582,9 @@
List<int> readSync(int bytes);
/**
- * Reads into an existing List<int> from the file. If [start] is present, the
- * bytes will be filled into [buffer] from at index [start], otherwise index
- * 0. If [end] is present, the [end] - [start] bytes will be read into
+ * Reads into an existing [List<int>] from the file. If [start] is present,
+ * the bytes will be filled into [buffer] from at index [start], otherwise
+ * index 0. If [end] is present, the [end] - [start] bytes will be read into
* [buffer], otherwise up to [buffer.length]. If [end] == [start] nothing
* happends.
*
@@ -593,8 +593,8 @@
Future<int> readInto(List<int> buffer, [int start = 0, int end]);
/**
- * Synchronously reads into an existing List<int> from the file. If [start] is
- * present, the bytes will be filled into [buffer] from at index [start],
+ * Synchronously reads into an existing [List<int>] from the file. If [start]
+ * is present, the bytes will be filled into [buffer] from at index [start],
* otherwise index 0. If [end] is present, the [end] - [start] bytes will be
* read into [buffer], otherwise up to [buffer.length]. If [end] == [start]
* nothing happends.
diff --git a/sdk/lib/io/file_system_entity.dart b/sdk/lib/io/file_system_entity.dart
index f39eafd..e0b22da 100644
--- a/sdk/lib/io/file_system_entity.dart
+++ b/sdk/lib/io/file_system_entity.dart
@@ -482,8 +482,8 @@
/**
* Returns a [bool] indicating whether this object's path is absolute.
*
- * On Windows, a path is absolute if it starts with \\ or a drive letter
- * between a and z (upper or lower case) followed by :\ or :/.
+ * On Windows, a path is absolute if it starts with \\\\ or a drive letter
+ * between a and z (upper or lower case) followed by :\\ or :/.
* On non-Windows, a path is absolute if it starts with /.
*/
bool get isAbsolute {
@@ -624,7 +624,7 @@
/**
* Removes the final path component of a path, using the platform's
* path separator to split the path. Will not remove the root component
- * of a Windows path, like "C:\" or "\\server_name\".
+ * of a Windows path, like "C:\\" or "\\\\server_name\\".
* Ignores trailing path separators, and leaves no trailing path separators.
*/
static String parentOf(String path) {
diff --git a/sdk/lib/js/dart2js/js_dart2js.dart b/sdk/lib/js/dart2js/js_dart2js.dart
index 4b3e4a6..61bf1da 100644
--- a/sdk/lib/js/dart2js/js_dart2js.dart
+++ b/sdk/lib/js/dart2js/js_dart2js.dart
@@ -707,7 +707,7 @@
return Function.apply(callback, [self]..addAll(arguments));
}
-Function /*=F*/ allowInterop/*<F extends Function>*/(Function /*=F*/ f) {
+Function/*=F*/ allowInterop/*<F extends Function>*/(Function/*=F*/ f) {
if (JS('bool', 'typeof(#) == "function"', f)) {
// Already supports interop, just use the existing function.
return f;
diff --git a/sdk/lib/js/dartium/js_dartium.dart b/sdk/lib/js/dartium/js_dartium.dart
index 4d1d682..4ac1197 100644
--- a/sdk/lib/js/dartium/js_dartium.dart
+++ b/sdk/lib/js/dartium/js_dartium.dart
@@ -106,6 +106,11 @@
final bool CHECK_JS_INVOCATIONS = true;
final String _DART_RESERVED_NAME_PREFIX = r'JS$';
+// If a private class is defined to use @JS we need to inject a non-private
+// class with a name that will not cause collisions in the library so we can
+// make JSObject implement that interface even though it is in a different
+// library.
+final String escapePrivateClassPrefix = r'$JSImplClass23402893498';
String _stripReservedNamePrefix(String name) =>
name.startsWith(_DART_RESERVED_NAME_PREFIX)
@@ -133,6 +138,114 @@
@Deprecated("Internal Use Only")
Iterable<mirrors.ClassMirror> get jsInterfaceTypes => _jsInterfaceTypes;
+class _StringLiteralEscape {
+ // Character code constants.
+ static const int BACKSPACE = 0x08;
+ static const int TAB = 0x09;
+ static const int NEWLINE = 0x0a;
+ static const int CARRIAGE_RETURN = 0x0d;
+ static const int FORM_FEED = 0x0c;
+ static const int QUOTE = 0x22;
+ static const int CHAR_$ = 0x24;
+ static const int CHAR_0 = 0x30;
+ static const int BACKSLASH = 0x5c;
+ static const int CHAR_b = 0x62;
+ static const int CHAR_f = 0x66;
+ static const int CHAR_n = 0x6e;
+ static const int CHAR_r = 0x72;
+ static const int CHAR_t = 0x74;
+ static const int CHAR_u = 0x75;
+
+ final StringSink _sink;
+
+ _StringLiteralEscape(this._sink);
+
+ void writeString(String string) {
+ _sink.write(string);
+ }
+
+ void writeStringSlice(String string, int start, int end) {
+ _sink.write(string.substring(start, end));
+ }
+
+ void writeCharCode(int charCode) {
+ _sink.writeCharCode(charCode);
+ }
+
+ /// ('0' + x) or ('a' + x - 10)
+ static int hexDigit(int x) => x < 10 ? 48 + x : 87 + x;
+
+ /// Write, and suitably escape, a string's content as a JSON string literal.
+ void writeStringContent(String s) {
+ // Identical to JSON string literal escaping except that we also escape $.
+ int offset = 0;
+ final int length = s.length;
+ for (int i = 0; i < length; i++) {
+ int charCode = s.codeUnitAt(i);
+ if (charCode > BACKSLASH) continue;
+ if (charCode < 32) {
+ if (i > offset) writeStringSlice(s, offset, i);
+ offset = i + 1;
+ writeCharCode(BACKSLASH);
+ switch (charCode) {
+ case BACKSPACE:
+ writeCharCode(CHAR_b);
+ break;
+ case TAB:
+ writeCharCode(CHAR_t);
+ break;
+ case NEWLINE:
+ writeCharCode(CHAR_n);
+ break;
+ case FORM_FEED:
+ writeCharCode(CHAR_f);
+ break;
+ case CARRIAGE_RETURN:
+ writeCharCode(CHAR_r);
+ break;
+ default:
+ writeCharCode(CHAR_u);
+ writeCharCode(CHAR_0);
+ writeCharCode(CHAR_0);
+ writeCharCode(hexDigit((charCode >> 4) & 0xf));
+ writeCharCode(hexDigit(charCode & 0xf));
+ break;
+ }
+ } else if (charCode == QUOTE ||
+ charCode == BACKSLASH ||
+ charCode == CHAR_$) {
+ if (i > offset) writeStringSlice(s, offset, i);
+ offset = i + 1;
+ writeCharCode(BACKSLASH);
+ writeCharCode(charCode);
+ }
+ }
+ if (offset == 0) {
+ writeString(s);
+ } else if (offset < length) {
+ writeStringSlice(s, offset, length);
+ }
+ }
+
+ /**
+ * Serialize a [num], [String], [bool], [Null], [List] or [Map] value.
+ *
+ * Returns true if the value is one of these types, and false if not.
+ * If a value is both a [List] and a [Map], it's serialized as a [List].
+ */
+ bool writeStringLiteral(String str) {
+ writeString('"');
+ writeStringContent(str);
+ writeString('"');
+ }
+}
+
+String _escapeString(String str) {
+ StringBuffer output = new StringBuffer();
+ new _StringLiteralEscape(output)..writeStringLiteral(str);
+ return output.toString();
+}
+
/// A collection of methods where all methods have the same name.
/// This class is intended to optimize whether a specific invocation is
/// appropritate for at least some of the methods in the collection.
@@ -183,8 +296,8 @@
// Not enough positional arguments.
return false;
}
- if (!_checkType(
- invocation.positionalArguments[i], parameters[i].type)) return false;
+ if (!_checkType(invocation.positionalArguments[i], parameters[i].type))
+ return false;
}
if (invocation.namedArguments.isNotEmpty) {
var startNamed;
@@ -203,8 +316,9 @@
for (var j = startNamed; j < parameters.length; j++) {
var p = parameters[j];
if (p.simpleName == name) {
- if (!_checkType(invocation.namedArguments[name],
- parameters[j].type)) return false;
+ if (!_checkType(
+ invocation.namedArguments[name], parameters[j].type))
+ return false;
match = true;
break;
}
@@ -340,7 +454,9 @@
_getJsMemberName(mirrors.DeclarationMirror mirror) {
var name = _getJsName(mirror);
- return name == null || name.isEmpty ? _getDeclarationName(mirror) : name;
+ return name == null || name.isEmpty
+ ? _stripReservedNamePrefix(_getDeclarationName(mirror))
+ : name;
}
// TODO(jacobr): handle setters correctyl.
@@ -350,7 +466,7 @@
assert(name.endsWith("="));
name = name.substring(0, name.length - 1);
}
- return _stripReservedNamePrefix(name);
+ return name;
}
final _JS_LIBRARY_PREFIX = "js_library";
@@ -364,7 +480,7 @@
..write('${_JS_LIBRARY_PREFIX}.JsNative.getProperty(' * parts.length)
..write("${_JS_LIBRARY_PREFIX}.context");
for (var p in parts) {
- sb.write(", '$p')");
+ sb.write(", ${_escapeString(p)})");
}
return sb.toString();
}
@@ -375,13 +491,13 @@
String _accessJsPathSetter(String path) {
var parts = path.split(".");
return "${_JS_LIBRARY_PREFIX}.JsNative.setProperty(${_accessJsPathHelper(parts.getRange(0, parts.length - 1))
- }, '${parts.last}', v)";
+ }, ${_escapeString(parts.last)}, v)";
}
String _accessJsPathCallMethodHelper(String path) {
var parts = path.split(".");
return "${_JS_LIBRARY_PREFIX}.JsNative.callMethod(${_accessJsPathHelper(parts.getRange(0, parts.length - 1))
- }, '${parts.last}',";
+ }, ${_escapeString(parts.last)},";
}
@Deprecated("Internal Use Only")
@@ -402,8 +518,7 @@
}
sb.write(" ");
if (declaration.isGetter) {
- sb.write(
- "get $name => ${_accessJsPath(path)};");
+ sb.write("get $name => ${_accessJsPath(path)};");
} else if (declaration.isSetter) {
sb.write("set $name(v) {\n"
" ${_JS_LIBRARY_PREFIX}.safeForTypedInterop(v);\n"
@@ -466,7 +581,8 @@
return false;
}
-List<String> _generateExternalMethods(List<String> libraryPaths, bool useCachedPatches) {
+List<String> _generateExternalMethods(
+ List<String> libraryPaths, bool useCachedPatches) {
var staticCodegen = <String>[];
if (libraryPaths.length == 0) {
@@ -484,7 +600,7 @@
// the patches for this file.
_generateLibraryCodegen(uri, library, staticCodegen);
}
- }); // End of library foreach
+ }); // End of library foreach
} else {
// Used to generate cached_patches.dart file for all IDL generated dart:
// files to the WebKit DOM.
@@ -500,133 +616,140 @@
}
_generateLibraryCodegen(uri, library, staticCodegen) {
- // Is it a dart generated library?
- var dartLibrary = uri.scheme == 'dart';
+ // Is it a dart generated library?
+ var dartLibrary = uri.scheme == 'dart';
- var sb = new StringBuffer();
- String jsLibraryName = _getJsName(library);
+ var sb = new StringBuffer();
+ String jsLibraryName = _getJsName(library);
- // Sort by patch file by its declaration name.
- var sortedDeclKeys = library.declarations.keys.toList();
- sortedDeclKeys.sort((a, b) => mirrors.MirrorSystem.getName(a).compareTo(mirrors.MirrorSystem.getName(b)));
+ // Sort by patch file by its declaration name.
+ var sortedDeclKeys = library.declarations.keys.toList();
+ sortedDeclKeys.sort((a, b) => mirrors.MirrorSystem
+ .getName(a)
+ .compareTo(mirrors.MirrorSystem.getName(b)));
- sortedDeclKeys.forEach((name) {
- var declaration = library.declarations[name];
- if (declaration is mirrors.MethodMirror) {
- if ((_hasJsName(declaration) || jsLibraryName != null) &&
- _isExternal(declaration)) {
- addMemberHelper(declaration, jsLibraryName, sb);
- }
- } else if (declaration is mirrors.ClassMirror) {
- mirrors.ClassMirror clazz = declaration;
- var isDom = dartLibrary ? hasDomName(clazz) : false;
- var isJsInterop = _hasJsName(clazz);
- if (isDom || isJsInterop) {
- // TODO(jacobr): verify class implements JavaScriptObject.
- var className = mirrors.MirrorSystem.getName(clazz.simpleName);
- var classNameImpl = '${className}Impl';
- var sbPatch = new StringBuffer();
- if (isJsInterop) {
- String jsClassName = _getJsMemberName(clazz);
+ sortedDeclKeys.forEach((name) {
+ var declaration = library.declarations[name];
+ if (declaration is mirrors.MethodMirror) {
+ if ((_hasJsName(declaration) || jsLibraryName != null) &&
+ _isExternal(declaration)) {
+ addMemberHelper(declaration, jsLibraryName, sb);
+ }
+ } else if (declaration is mirrors.ClassMirror) {
+ mirrors.ClassMirror clazz = declaration;
+ var isDom = dartLibrary ? hasDomName(clazz) : false;
+ var isJsInterop = _hasJsName(clazz);
+ if (isDom || isJsInterop) {
+ // TODO(jacobr): verify class implements JavaScriptObject.
+ var className = mirrors.MirrorSystem.getName(clazz.simpleName);
+ bool isPrivate = className.startsWith('_');
+ var classNameImpl = '${className}Impl';
+ var sbPatch = new StringBuffer();
+ if (isJsInterop) {
+ String jsClassName = _getJsMemberName(clazz);
- jsInterfaceTypes.add(clazz);
- clazz.declarations.forEach((name, declaration) {
- if (declaration is! mirrors.MethodMirror ||
- !_isExternal(declaration)) return;
- if (declaration.isFactoryConstructor &&
- _isAnonymousClass(clazz)) {
- sbPatch.write(" factory ${className}(");
- int i = 0;
- var args = <String>[];
- for (var p in declaration.parameters) {
- args.add(mirrors.MirrorSystem.getName(p.simpleName));
- i++;
- }
- if (args.isNotEmpty) {
- sbPatch
- ..write('{')
- ..write(args
- .map((name) => '$name:${_UNDEFINED_VAR}')
- .join(", "))
- ..write('}');
- }
- sbPatch.write(") {\n"
- " var ret = ${_JS_LIBRARY_PREFIX}.JsNative.newObject();\n");
- i = 0;
- for (var p in declaration.parameters) {
- assert(p.isNamed); // TODO(jacobr): throw.
- var name = args[i];
- var jsName = _stripReservedNamePrefix(
- mirrors.MirrorSystem.getName(p.simpleName));
- sbPatch.write(" if($name != ${_UNDEFINED_VAR}) {\n"
- " ${_JS_LIBRARY_PREFIX}.safeForTypedInterop($name);\n"
- " ${_JS_LIBRARY_PREFIX}.JsNative.setProperty(ret, '$jsName', $name);\n"
- " }\n");
- i++;
- }
+ jsInterfaceTypes.add(clazz);
+ clazz.declarations.forEach((name, declaration) {
+ if (declaration is! mirrors.MethodMirror ||
+ !_isExternal(declaration)) return;
+ if (declaration.isFactoryConstructor && _isAnonymousClass(clazz)) {
+ sbPatch.write(" factory ${className}(");
+ int i = 0;
+ var args = <String>[];
+ for (var p in declaration.parameters) {
+ args.add(mirrors.MirrorSystem.getName(p.simpleName));
+ i++;
+ }
+ if (args.isNotEmpty) {
+ sbPatch
+ ..write('{')
+ ..write(
+ args.map((name) => '$name:${_UNDEFINED_VAR}').join(", "))
+ ..write('}');
+ }
+ sbPatch.write(") {\n"
+ " var ret = ${_JS_LIBRARY_PREFIX}.JsNative.newObject();\n");
+ i = 0;
+ for (var p in declaration.parameters) {
+ assert(p.isNamed); // TODO(jacobr): throw.
+ var name = args[i];
+ var jsName = _stripReservedNamePrefix(
+ mirrors.MirrorSystem.getName(p.simpleName));
+ sbPatch.write(" if($name != ${_UNDEFINED_VAR}) {\n"
+ " ${_JS_LIBRARY_PREFIX}.safeForTypedInterop($name);\n"
+ " ${_JS_LIBRARY_PREFIX}.JsNative.setProperty(ret, ${_escapeString(jsName)}, $name);\n"
+ " }\n");
+ i++;
+ }
- sbPatch.write(
- " return ret;"
+ sbPatch.write(" return ret;"
"}\n");
- } else if (declaration.isConstructor ||
- declaration.isFactoryConstructor) {
- sbPatch.write(" ");
- addMemberHelper(
- declaration,
- (jsLibraryName != null && jsLibraryName.isNotEmpty)
- ? "${jsLibraryName}.${jsClassName}"
- : jsClassName,
- sbPatch,
- isStatic: true,
- memberName: className);
- }
- }); // End of clazz.declarations.forEach
-
- clazz.staticMembers.forEach((memberName, member) {
- if (_isExternal(member)) {
- sbPatch.write(" ");
- addMemberHelper(
- member,
- (jsLibraryName != null && jsLibraryName.isNotEmpty)
- ? "${jsLibraryName}.${jsClassName}"
- : jsClassName,
- sbPatch,
- isStatic: true);
- }
- });
- }
- if (isDom) {
- sbPatch.write(" static Type get instanceRuntimeType => ${classNameImpl};\n");
- }
- if (sbPatch.isNotEmpty) {
- var typeVariablesClause = '';
- if (!clazz.typeVariables.isEmpty) {
- typeVariablesClause =
- '<${clazz.typeVariables.map((m) => mirrors.MirrorSystem.getName(m.simpleName)).join(',')}>';
+ } else if (declaration.isConstructor ||
+ declaration.isFactoryConstructor) {
+ sbPatch.write(" ");
+ addMemberHelper(
+ declaration,
+ (jsLibraryName != null && jsLibraryName.isNotEmpty)
+ ? "${jsLibraryName}.${jsClassName}"
+ : jsClassName,
+ sbPatch,
+ isStatic: true,
+ memberName: className);
}
- sb.write("""
+ }); // End of clazz.declarations.forEach
+
+ clazz.staticMembers.forEach((memberName, member) {
+ if (_isExternal(member)) {
+ sbPatch.write(" ");
+ addMemberHelper(
+ member,
+ (jsLibraryName != null && jsLibraryName.isNotEmpty)
+ ? "${jsLibraryName}.${jsClassName}"
+ : jsClassName,
+ sbPatch,
+ isStatic: true);
+ }
+ });
+ }
+ if (isDom) {
+ sbPatch.write(
+ " static Type get instanceRuntimeType => ${classNameImpl};\n");
+ }
+ if (isPrivate) {
+ sb.write("""
+class ${escapePrivateClassPrefix}${className} implements $className {}
+""");
+ }
+
+ if (sbPatch.isNotEmpty) {
+ var typeVariablesClause = '';
+ if (!clazz.typeVariables.isEmpty) {
+ typeVariablesClause =
+ '<${clazz.typeVariables.map((m) => mirrors.MirrorSystem.getName(m.simpleName)).join(',')}>';
+ }
+ sb.write("""
patch class $className$typeVariablesClause {
$sbPatch
}
""");
- if (isDom) {
- sb.write("""
+ if (isDom) {
+ sb.write("""
class $classNameImpl$typeVariablesClause extends $className implements ${_JS_LIBRARY_PREFIX}.JSObjectInterfacesDom {
${classNameImpl}.internal_() : super.internal_();
get runtimeType => $className;
toString() => super.toString();
}
""");
- }
}
}
}
- });
- if (sb.isNotEmpty) {
- staticCodegen
- ..add(uri.toString())
- ..add("${uri}_js_interop_patch.dart")
- ..add("""
+ }
+ });
+ if (sb.isNotEmpty) {
+ staticCodegen
+ ..add(uri.toString())
+ ..add("${uri}_js_interop_patch.dart")
+ ..add("""
import 'dart:js' as ${_JS_LIBRARY_PREFIX};
/**
@@ -637,7 +760,7 @@
${sb}
""");
- }
+ }
}
// Remember the @JS type to compare annotation type.
@@ -667,11 +790,13 @@
* signal to generate and emit the patches to stdout to be captured and put into
* the file sdk/lib/js/dartium/cached_patches.dart
*/
-List<String> _generateInteropPatchFiles(List<String> libraryPaths, genCachedPatches) {
+List<String> _generateInteropPatchFiles(
+ List<String> libraryPaths, genCachedPatches) {
// Cache the @JS Type.
if (_atJsType == -1) setupJsTypeCache();
- var ret = _generateExternalMethods(libraryPaths, genCachedPatches ? false : true);
+ var ret =
+ _generateExternalMethods(libraryPaths, genCachedPatches ? false : true);
var libraryPrefixes = new Map<mirrors.LibraryMirror, String>();
var prefixNames = new Set<String>();
var sb = new StringBuffer();
@@ -705,8 +830,10 @@
var isArray = typeMirror.isSubtypeOf(listMirror);
var isFunction = typeMirror.isSubtypeOf(functionMirror);
var isJSObject = typeMirror.isSubtypeOf(jsObjectMirror);
- var fullName =
- '${prefixName}.${mirrors.MirrorSystem.getName(typeMirror.simpleName)}';
+ var className = mirrors.MirrorSystem.getName(typeMirror.simpleName);
+ var isPrivate = className.startsWith('_');
+ if (isPrivate) className = '${escapePrivateClassPrefix}${className}';
+ var fullName = '${prefixName}.${className}';
(isArray ? implementsArray : implements).add(fullName);
if (!isArray && !isFunction && !isJSObject) {
// For DOM classes we need to be a bit more conservative at tagging them
@@ -945,25 +1072,27 @@
_lookupType(o, bool isCrossFrame, bool isElement) {
try {
- var type = html_common.lookupType(o, isElement);
- var typeMirror = mirrors.reflectType(type);
- var legacyInteropConvertToNative = typeMirror.isSubtypeOf(mirrors.reflectType(html.Blob)) ||
- typeMirror.isSubtypeOf(mirrors.reflectType(html.Event)) ||
- typeMirror.isSubtypeOf(mirrors.reflectType(indexed_db.KeyRange)) ||
- typeMirror.isSubtypeOf(mirrors.reflectType(html.ImageData)) ||
- typeMirror.isSubtypeOf(mirrors.reflectType(html.Node)) ||
+ var type = html_common.lookupType(o, isElement);
+ var typeMirror = mirrors.reflectType(type);
+ var legacyInteropConvertToNative =
+ typeMirror.isSubtypeOf(mirrors.reflectType(html.Blob)) ||
+ typeMirror.isSubtypeOf(mirrors.reflectType(html.Event)) ||
+ typeMirror.isSubtypeOf(mirrors.reflectType(indexed_db.KeyRange)) ||
+ typeMirror.isSubtypeOf(mirrors.reflectType(html.ImageData)) ||
+ typeMirror.isSubtypeOf(mirrors.reflectType(html.Node)) ||
// TypedData is removed from this list as it is converted directly
// rather than flowing through the interceptor code path.
// typeMirror.isSubtypeOf(mirrors.reflectType(typed_data.TypedData)) ||
- typeMirror.isSubtypeOf(mirrors.reflectType(html.Window));
- if (isCrossFrame && !typeMirror.isSubtypeOf(mirrors.reflectType(html.Window))) {
+ typeMirror.isSubtypeOf(mirrors.reflectType(html.Window));
+ if (isCrossFrame &&
+ !typeMirror.isSubtypeOf(mirrors.reflectType(html.Window))) {
// TODO(jacobr): evaluate using the true cross frame Window class, etc.
// as well as triggering that legacy JS Interop returns raw JsObject
// instances.
legacyInteropConvertToNative = false;
}
return [type, legacyInteropConvertToNative];
- } catch (e) { }
+ } catch (e) {}
return [JSObject.instanceRuntimeType, false];
}
@@ -1045,7 +1174,8 @@
static JsObject _jsify(object) native "JsObject_jsify";
- static JsObject _fromBrowserObject(object) native "JsObject_fromBrowserObject";
+ static JsObject _fromBrowserObject(object)
+ native "JsObject_fromBrowserObject";
/**
* Returns the value associated with [property] from the proxied JavaScript
@@ -1088,8 +1218,7 @@
return _identityEquality(this, other);
}
- static bool _identityEquality(a, b)
- native "JsObject_identityEquality";
+ static bool _identityEquality(a, b) native "JsObject_identityEquality";
/**
* Returns `true` if the JavaScript object contains the specified property
@@ -1148,7 +1277,6 @@
_callMethodLegacy(String name, List args) native "JsObject_callMethodLegacy";
}
-
/// Base class for all JS objects used through dart:html and typed JS interop.
@Deprecated("Internal Use Only")
class JSObject extends _JSObjectBase {
@@ -1185,8 +1313,8 @@
if (matches != null) return ret;
if (ret is Function ||
(ret is JsFunction /* shouldn't be needed in the future*/) &&
- _allowedMethods.containsKey(
- invocation.memberName)) return ret; // Warning: we have not bound "this"... we could type check on the Function but that is of little value in Dart.
+ _allowedMethods.containsKey(invocation.memberName))
+ return ret; // Warning: we have not bound "this"... we could type check on the Function but that is of little value in Dart.
throwError();
} else {
// TODO(jacobr): should we throw if the JavaScript object doesn't have the property?
@@ -1195,8 +1323,8 @@
} else if (invocation.isSetter) {
if (CHECK_JS_INVOCATIONS) {
var matches = _allowedSetters[invocation.memberName];
- if (matches == null ||
- !matches.checkInvocation(invocation)) throwError();
+ if (matches == null || !matches.checkInvocation(invocation))
+ throwError();
}
assert(name.endsWith("="));
name = name.substring(0, name.length - 1);
@@ -1206,8 +1334,8 @@
var matches;
if (CHECK_JS_INVOCATIONS) {
matches = _allowedMethods[invocation.memberName];
- if (matches == null ||
- !matches.checkInvocation(invocation)) throwError();
+ if (matches == null || !matches.checkInvocation(invocation))
+ throwError();
}
var ret = _callMethod(name, _buildArgs(invocation));
if (CHECK_JS_INVOCATIONS) {
@@ -1287,7 +1415,8 @@
a8 = _UNDEFINED,
a9 = _UNDEFINED,
a10 = _UNDEFINED]) {
- return _apply(_stripUndefinedArgs([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10]));
+ return _apply(
+ _stripUndefinedArgs([a1, a2, a3, a4, a5, a6, a7, a8, a9, a10]));
}
noSuchMethod(Invocation invocation) {
@@ -1299,7 +1428,8 @@
dynamic _apply(List args, {thisArg}) native "JSFunction_apply";
- static JSFunction _createWithThis(Function f) native "JSFunction_createWithThis";
+ static JSFunction _createWithThis(Function f)
+ native "JSFunction_createWithThis";
static JSFunction _create(Function f) native "JSFunction_create";
}
@@ -1314,11 +1444,16 @@
static hasProperty(_JSObjectBase o, name) => o._hasProperty(name);
static getProperty(_JSObjectBase o, name) => o._operator_getter(name);
- static setProperty(_JSObjectBase o, name, value) => o._operator_setter(name, value);
- static callMethod(_JSObjectBase o, String method, List args) => o._callMethod(method, args);
- static instanceof(_JSObjectBase o, /*JsFunction|JSFunction*/ type) => o._instanceof(type);
- static callConstructor0(_JSObjectBase constructor) native "JSNative_callConstructor0";
- static callConstructor(_JSObjectBase constructor, List args) native "JSNative_callConstructor";
+ static setProperty(_JSObjectBase o, name, value) =>
+ o._operator_setter(name, value);
+ static callMethod(_JSObjectBase o, String method, List args) =>
+ o._callMethod(method, args);
+ static instanceof(_JSObjectBase o, /*JsFunction|JSFunction*/ type) =>
+ o._instanceof(type);
+ static callConstructor0(_JSObjectBase constructor)
+ native "JSNative_callConstructor0";
+ static callConstructor(_JSObjectBase constructor, List args)
+ native "JSNative_callConstructor";
static toTypedObject(JsObject o) native "JSNative_toTypedObject";
@@ -1329,7 +1464,6 @@
static JSFunction withThis(Function f) native "JsFunction_withThisNoWrap";
}
-
/**
* Proxies a JavaScript Function object.
*/
@@ -1346,8 +1480,7 @@
* Invokes the JavaScript function with arguments [args]. If [thisArg] is
* supplied it is the value of `this` for the invocation.
*/
- dynamic apply(List args, {thisArg}) =>
- _apply(args, thisArg: thisArg);
+ dynamic apply(List args, {thisArg}) => _apply(args, thisArg: thisArg);
dynamic _apply(List args, {thisArg}) native "JsFunction_apply";
@@ -1528,7 +1661,7 @@
/// JavaScript. We may remove the need to call this method completely in the
/// future if Dart2Js is refactored so that its function calling conventions
/// are more compatible with JavaScript.
-Function /*=F*/ allowInterop/*<F extends Function>*/(Function /*=F*/ f) {
+Function/*=F*/ allowInterop/*<F extends Function>*/(Function/*=F*/ f) {
if (f is JSFunction) {
// The function is already a JSFunction... no need to do anything.
return f;
@@ -1563,5 +1696,3 @@
return ret;
}
}
-
-debugPrint(_) {}
\ No newline at end of file
diff --git a/sdk/lib/js_util/dart2js/js_util_dart2js.dart b/sdk/lib/js_util/dart2js/js_util_dart2js.dart
new file mode 100644
index 0000000..a587459
--- /dev/null
+++ b/sdk/lib/js_util/dart2js/js_util_dart2js.dart
@@ -0,0 +1,126 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Utility methods to efficiently manipulate typed JSInterop objects in cases
+/// where the name to call is not known at runtime. You should only use these
+/// methods when the same effect cannot be achieved with @JS annotations.
+/// These methods would be extension methods on JSObject if Dart supported
+/// extension methods.
+library dart.js_util;
+
+import 'dart:_foreign_helper' show JS;
+import 'dart:collection' show HashMap;
+
+/// WARNING: performance of this method is much worse than other uitil
+/// methods in this library. Only use this method as a last resort.
+///
+/// Recursively converts a JSON-like collection of Dart objects to a
+/// collection of JavaScript objects and returns a [JsObject] proxy to it.
+///
+/// [object] must be a [Map] or [Iterable], the contents of which are also
+/// converted. Maps and Iterables are copied to a new JavaScript object.
+/// Primitives and other transferrable values are directly converted to their
+/// JavaScript type, and all other objects are proxied.
+jsify(object) {
+ if ((object is! Map) && (object is! Iterable)) {
+ throw new ArgumentError("object must be a Map or Iterable");
+ }
+ return _convertDataTree(object);
+}
+
+_convertDataTree(data) {
+ var _convertedObjects = new HashMap.identity();
+
+ _convert(o) {
+ if (_convertedObjects.containsKey(o)) {
+ return _convertedObjects[o];
+ }
+ if (o is Map) {
+ final convertedMap = JS('=Object', '{}');
+ _convertedObjects[o] = convertedMap;
+ for (var key in o.keys) {
+ JS('=Object', '#[#]=#', convertedMap, key, _convert(o[key]));
+ }
+ return convertedMap;
+ } else if (o is Iterable) {
+ var convertedList = [];
+ _convertedObjects[o] = convertedList;
+ convertedList.addAll(o.map(_convert));
+ return convertedList;
+ } else {
+ return o;
+ }
+ }
+
+ return _convert(data);
+}
+
+newObject() => JS('=Object', '{}');
+
+hasProperty(o, name) => JS('bool', '# in #', name, o);
+getProperty(o, name) => JS('Object', '#[#]', o, name);
+setProperty(o, name, value) => JS('', '#[#]=#', o, name, value);
+
+callMethod(o, String method, List args) =>
+ JS('Object', '#[#].apply(#, #)', o, method, o, args);
+
+instanceof(o, Function type) => JS('bool', '# instanceof #', o, type);
+callConstructor(Function constr, List arguments) {
+ if (arguments == null) {
+ return JS('Object', 'new #()', constr);
+ }
+
+ if (JS('bool', '# instanceof Array', arguments)) {
+ int argumentCount = JS('int', '#.length', arguments);
+ switch (argumentCount) {
+ case 0:
+ return JS('Object', 'new #()', constr);
+
+ case 1:
+ var arg0 = JS('', '#[0]', arguments);
+ return JS('Object', 'new #(#)', constr, arg0);
+
+ case 2:
+ var arg0 = JS('', '#[0]', arguments);
+ var arg1 = JS('', '#[1]', arguments);
+ return JS('Object', 'new #(#, #)', constr, arg0, arg1);
+
+ case 3:
+ var arg0 = JS('', '#[0]', arguments);
+ var arg1 = JS('', '#[1]', arguments);
+ var arg2 = JS('', '#[2]', arguments);
+ return JS('Object', 'new #(#, #, #)', constr, arg0, arg1, arg2);
+
+ case 4:
+ var arg0 = JS('', '#[0]', arguments);
+ var arg1 = JS('', '#[1]', arguments);
+ var arg2 = JS('', '#[2]', arguments);
+ var arg3 = JS('', '#[3]', arguments);
+ return JS(
+ 'Object', 'new #(#, #, #, #)', constr, arg0, arg1, arg2, arg3);
+ }
+ }
+
+ // The following code solves the problem of invoking a JavaScript
+ // constructor with an unknown number arguments.
+ // First bind the constructor to the argument list using bind.apply().
+ // The first argument to bind() is the binding of 't', so add 'null' to
+ // the arguments list passed to apply().
+ // After that, use the JavaScript 'new' operator which overrides any binding
+ // of 'this' with the new instance.
+ var args = [null]..addAll(arguments);
+ var factoryFunction = JS('', '#.bind.apply(#, #)', constr, constr, args);
+ // Without this line, calling factoryFunction as a constructor throws
+ JS('String', 'String(#)', factoryFunction);
+ // This could return an UnknownJavaScriptObject, or a native
+ // object for which there is an interceptor
+ return JS('Object', 'new #()', factoryFunction);
+
+ // TODO(sra): Investigate:
+ //
+ // var jsObj = JS('', 'Object.create(#.prototype)', constr);
+ // JS('', '#.apply(#, #)', constr, jsObj,
+ // []..addAll(arguments.map(_convertToJS)));
+ // return _wrapToDart(jsObj);
+}
diff --git a/sdk/lib/js_util/dartium/js_util_dartium.dart b/sdk/lib/js_util/dartium/js_util_dartium.dart
new file mode 100644
index 0000000..5f1226d
--- /dev/null
+++ b/sdk/lib/js_util/dartium/js_util_dartium.dart
@@ -0,0 +1,38 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Utility methods to efficiently manipulate typed JSInterop objects in cases
+/// where the name to call is not known at runtime. You should only use these
+/// methods when the same effect cannot be achieved with @JS annotations.
+/// These methods would be extension methods on JSObject if Dart supported
+/// extension methods.
+library dart.js_util;
+
+import 'dart:js';
+
+/// WARNING: performance of this method is much worse than other uitil
+/// methods in this library. Only use this method as a last resort.
+///
+/// Recursively converts a JSON-like collection of Dart objects to a
+/// collection of JavaScript objects and returns a [JsObject] proxy to it.
+///
+/// [object] must be a [Map] or [Iterable], the contents of which are also
+/// converted. Maps and Iterables are copied to a new JavaScript object.
+/// Primitives and other transferrable values are directly converted to their
+/// JavaScript type, and all other objects are proxied.
+jsify(object) {
+ if ((object is! Map) && (object is! Iterable)) {
+ throw new ArgumentError("object must be a Map or Iterable");
+ }
+ return JsNative.jsify(object);
+}
+
+JSObject newObject() => JsNative.newObject();
+
+hasProperty(JSObject o, name) => JsNative.hasProperty(o, name);
+getProperty(JSObject o, name) => JsNative.getProperty(o, name);
+setProperty(JSObject o, name, value) => JsNative.setProperty(o, name, value);
+callMethod(JSObject o, String method, List args) => JsNative.callMethod(o, method, args);
+instanceof(JSObject o, Function type) => JsNative.instanceof(o, type);
+callConstructor(JSObject constructor, List args) => JsNative.callConstructor(constructor, args);
diff --git a/sdk/lib/vmservice/message.dart b/sdk/lib/vmservice/message.dart
index 08bb5b1..295214c 100644
--- a/sdk/lib/vmservice/message.dart
+++ b/sdk/lib/vmservice/message.dart
@@ -130,6 +130,7 @@
case '_writeDevFSFile':
case '_writeDevFSFiles':
case '_readDevFSFile':
+ case '_spawnUri':
return true;
default:
return false;
@@ -182,4 +183,4 @@
external bool sendIsolateServiceMessage(SendPort sp, List m);
external void sendRootServiceMessage(List m);
-external void sendObjectRootServiceMessage(List m);
\ No newline at end of file
+external void sendObjectRootServiceMessage(List m);
diff --git a/sdk/lib/vmservice/vmservice.dart b/sdk/lib/vmservice/vmservice.dart
index 4101023..df5642b 100644
--- a/sdk/lib/vmservice/vmservice.dart
+++ b/sdk/lib/vmservice/vmservice.dart
@@ -295,6 +295,37 @@
return encodeSuccess(message);
}
+ Future<String> _spawnUri(Message message) async {
+ var token = message.params['token'];
+ if (token == null) {
+ return encodeMissingParamError(message, 'token');
+ }
+ if (token is! String) {
+ return encodeInvalidParamError(message, 'token');
+ }
+ var uri = message.params['uri'];
+ if (uri == null) {
+ return encodeMissingParamError(message, 'uri');
+ }
+ if (uri is! String) {
+ return encodeInvalidParamError(message, 'uri');
+ }
+ var args = message.params['args'];
+ if (args != null &&
+ args is! List<String>) {
+ return encodeInvalidParamError(message, 'args');
+ }
+ var msg = message.params['message'];
+
+ Isolate.spawnUri(Uri.parse(uri), args, msg).then((isolate) {
+ _spawnUriNotify(isolate.controlPort, token);
+ }).catchError((e) {
+ _spawnUriNotify(e.toString(), token);
+ });
+
+ return encodeSuccess(message);
+ }
+
// TODO(johnmccutchan): Turn this into a command line tool that uses the
// service library.
Future<String> _getCrashDump(Message message) async {
@@ -367,6 +398,9 @@
if (message.method == 'streamCancel') {
return _streamCancel(message);
}
+ if (message.method == '_spawnUri') {
+ return _spawnUri(message);
+ }
if (_devfs.shouldHandleMessage(message)) {
return _devfs.handleMessage(message);
}
@@ -404,3 +438,6 @@
/// Get the bytes to the tar archive.
external Uint8List _requestAssets();
+
+/// Notify the vm service that an isolate has been spawned via rpc.
+external void _spawnUriNotify(obj, String token);
diff --git a/sdk/lib/web_gl/dart2js/web_gl_dart2js.dart b/sdk/lib/web_gl/dart2js/web_gl_dart2js.dart
index ac38baa..3dd54a8 100644
--- a/sdk/lib/web_gl/dart2js/web_gl_dart2js.dart
+++ b/sdk/lib/web_gl/dart2js/web_gl_dart2js.dart
@@ -354,7 +354,7 @@
@DocsEditable()
@DomName('ANGLEInstancedArrays')
@Experimental() // untriaged
-@Native("ANGLEInstancedArrays")
+@Native("ANGLEInstancedArrays,ANGLE_instanced_arrays")
class AngleInstancedArrays extends Interceptor {
// To suppress missing implicit constructor warnings.
factory AngleInstancedArrays._() { throw new UnsupportedError("Not supported"); }
@@ -469,7 +469,7 @@
@DomName('WebGLCompressedTextureATC')
// http://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_atc/
@Experimental()
-@Native("WebGLCompressedTextureATC")
+@Native("WebGLCompressedTextureATC,WEBGL_compressed_texture_atc")
class CompressedTextureAtc extends Interceptor {
// To suppress missing implicit constructor warnings.
factory CompressedTextureAtc._() { throw new UnsupportedError("Not supported"); }
@@ -494,7 +494,7 @@
@DocsEditable()
@DomName('WebGLCompressedTextureETC1')
@Experimental() // untriaged
-@Native("WebGLCompressedTextureETC1")
+@Native("WebGLCompressedTextureETC1,WEBGL_compressed_texture_etc1")
class CompressedTextureETC1 extends Interceptor {
// To suppress missing implicit constructor warnings.
factory CompressedTextureETC1._() { throw new UnsupportedError("Not supported"); }
@@ -513,7 +513,7 @@
@DomName('WebGLCompressedTexturePVRTC')
// http://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_pvrtc/
@Experimental() // experimental
-@Native("WebGLCompressedTexturePVRTC")
+@Native("WebGLCompressedTexturePVRTC,WEBGL_compressed_texture_pvrtc")
class CompressedTexturePvrtc extends Interceptor {
// To suppress missing implicit constructor warnings.
factory CompressedTexturePvrtc._() { throw new UnsupportedError("Not supported"); }
@@ -543,7 +543,7 @@
@DomName('WebGLCompressedTextureS3TC')
// http://www.khronos.org/registry/webgl/extensions/WEBGL_compressed_texture_s3tc/
@Experimental() // experimental
-@Native("WebGLCompressedTextureS3TC")
+@Native("WebGLCompressedTextureS3TC,WEBGL_compressed_texture_s3tc")
class CompressedTextureS3TC extends Interceptor {
// To suppress missing implicit constructor warnings.
factory CompressedTextureS3TC._() { throw new UnsupportedError("Not supported"); }
@@ -602,7 +602,7 @@
@DomName('WebGLDebugRendererInfo')
// http://www.khronos.org/registry/webgl/extensions/WEBGL_debug_renderer_info/
@Experimental() // experimental
-@Native("WebGLDebugRendererInfo")
+@Native("WebGLDebugRendererInfo,WEBGL_debug_renderer_info")
class DebugRendererInfo extends Interceptor {
// To suppress missing implicit constructor warnings.
factory DebugRendererInfo._() { throw new UnsupportedError("Not supported"); }
@@ -624,7 +624,7 @@
@DomName('WebGLDebugShaders')
// http://www.khronos.org/registry/webgl/extensions/WEBGL_debug_shaders/
@Experimental() // experimental
-@Native("WebGLDebugShaders")
+@Native("WebGLDebugShaders,WEBGL_debug_shaders")
class DebugShaders extends Interceptor {
// To suppress missing implicit constructor warnings.
factory DebugShaders._() { throw new UnsupportedError("Not supported"); }
@@ -642,7 +642,7 @@
@DomName('WebGLDepthTexture')
// http://www.khronos.org/registry/webgl/extensions/WEBGL_depth_texture/
@Experimental() // experimental
-@Native("WebGLDepthTexture")
+@Native("WebGLDepthTexture,WEBGL_depth_texture")
class DepthTexture extends Interceptor {
// To suppress missing implicit constructor warnings.
factory DepthTexture._() { throw new UnsupportedError("Not supported"); }
@@ -660,7 +660,7 @@
@DomName('WebGLDrawBuffers')
// http://www.khronos.org/registry/webgl/specs/latest/
@Experimental() // stable
-@Native("WebGLDrawBuffers")
+@Native("WebGLDrawBuffers,WEBGL_draw_buffers")
class DrawBuffers extends Interceptor {
// To suppress missing implicit constructor warnings.
factory DrawBuffers._() { throw new UnsupportedError("Not supported"); }
@@ -814,7 +814,7 @@
@DocsEditable()
@DomName('EXTsRGB')
@Experimental() // untriaged
-@Native("EXTsRGB")
+@Native("EXTsRGB,EXT_sRGB")
class EXTsRgb extends Interceptor {
// To suppress missing implicit constructor warnings.
factory EXTsRgb._() { throw new UnsupportedError("Not supported"); }
@@ -847,7 +847,7 @@
@DocsEditable()
@DomName('EXTBlendMinMax')
@Experimental() // untriaged
-@Native("EXTBlendMinMax")
+@Native("EXTBlendMinMax,EXT_blend_minmax")
class ExtBlendMinMax extends Interceptor {
// To suppress missing implicit constructor warnings.
factory ExtBlendMinMax._() { throw new UnsupportedError("Not supported"); }
@@ -871,7 +871,7 @@
@DomName('EXTFragDepth')
// http://www.khronos.org/registry/webgl/extensions/EXT_frag_depth/
@Experimental()
-@Native("EXTFragDepth")
+@Native("EXTFragDepth,EXT_frag_depth")
class ExtFragDepth extends Interceptor {
// To suppress missing implicit constructor warnings.
factory ExtFragDepth._() { throw new UnsupportedError("Not supported"); }
@@ -884,7 +884,7 @@
@DocsEditable()
@DomName('EXTShaderTextureLOD')
@Experimental() // untriaged
-@Native("EXTShaderTextureLOD")
+@Native("EXTShaderTextureLOD,EXT_shader_texture_lod")
class ExtShaderTextureLod extends Interceptor {
// To suppress missing implicit constructor warnings.
factory ExtShaderTextureLod._() { throw new UnsupportedError("Not supported"); }
@@ -898,7 +898,7 @@
@DomName('EXTTextureFilterAnisotropic')
// http://www.khronos.org/registry/webgl/extensions/EXT_texture_filter_anisotropic/
@Experimental()
-@Native("EXTTextureFilterAnisotropic")
+@Native("EXTTextureFilterAnisotropic,EXT_texture_filter_anisotropic")
class ExtTextureFilterAnisotropic extends Interceptor {
// To suppress missing implicit constructor warnings.
factory ExtTextureFilterAnisotropic._() { throw new UnsupportedError("Not supported"); }
@@ -933,7 +933,7 @@
@DomName('WebGLLoseContext')
// http://www.khronos.org/registry/webgl/extensions/WEBGL_lose_context/
@Experimental()
-@Native("WebGLLoseContext,WebGLExtensionLoseContext")
+@Native("WebGLLoseContext,WebGLExtensionLoseContext,WEBGL_lose_context")
class LoseContext extends Interceptor {
// To suppress missing implicit constructor warnings.
factory LoseContext._() { throw new UnsupportedError("Not supported"); }
@@ -955,7 +955,7 @@
@DomName('OESElementIndexUint')
// http://www.khronos.org/registry/webgl/extensions/OES_element_index_uint/
@Experimental() // experimental
-@Native("OESElementIndexUint")
+@Native("OESElementIndexUint,OES_element_index_uint")
class OesElementIndexUint extends Interceptor {
// To suppress missing implicit constructor warnings.
factory OesElementIndexUint._() { throw new UnsupportedError("Not supported"); }
@@ -969,7 +969,7 @@
@DomName('OESStandardDerivatives')
// http://www.khronos.org/registry/webgl/extensions/OES_standard_derivatives/
@Experimental() // experimental
-@Native("OESStandardDerivatives")
+@Native("OESStandardDerivatives,OES_standard_derivatives")
class OesStandardDerivatives extends Interceptor {
// To suppress missing implicit constructor warnings.
factory OesStandardDerivatives._() { throw new UnsupportedError("Not supported"); }
@@ -987,7 +987,7 @@
@DomName('OESTextureFloat')
// http://www.khronos.org/registry/webgl/extensions/OES_texture_float/
@Experimental() // experimental
-@Native("OESTextureFloat")
+@Native("OESTextureFloat,OES_texture_float")
class OesTextureFloat extends Interceptor {
// To suppress missing implicit constructor warnings.
factory OesTextureFloat._() { throw new UnsupportedError("Not supported"); }
@@ -1001,7 +1001,7 @@
@DomName('OESTextureFloatLinear')
// http://www.khronos.org/registry/webgl/extensions/OES_texture_float_linear/
@Experimental()
-@Native("OESTextureFloatLinear")
+@Native("OESTextureFloatLinear,OES_texture_float_linear")
class OesTextureFloatLinear extends Interceptor {
// To suppress missing implicit constructor warnings.
factory OesTextureFloatLinear._() { throw new UnsupportedError("Not supported"); }
@@ -1015,7 +1015,7 @@
@DomName('OESTextureHalfFloat')
// http://www.khronos.org/registry/webgl/extensions/OES_texture_half_float/
@Experimental() // experimental
-@Native("OESTextureHalfFloat")
+@Native("OESTextureHalfFloat,OES_texture_half_float")
class OesTextureHalfFloat extends Interceptor {
// To suppress missing implicit constructor warnings.
factory OesTextureHalfFloat._() { throw new UnsupportedError("Not supported"); }
@@ -1033,7 +1033,7 @@
@DomName('OESTextureHalfFloatLinear')
// http://www.khronos.org/registry/webgl/extensions/OES_texture_half_float_linear/
@Experimental()
-@Native("OESTextureHalfFloatLinear")
+@Native("OESTextureHalfFloatLinear,OES_texture_half_float_linear")
class OesTextureHalfFloatLinear extends Interceptor {
// To suppress missing implicit constructor warnings.
factory OesTextureHalfFloatLinear._() { throw new UnsupportedError("Not supported"); }
@@ -1047,7 +1047,7 @@
@DomName('OESVertexArrayObject')
// http://www.khronos.org/registry/webgl/extensions/OES_vertex_array_object/
@Experimental() // experimental
-@Native("OESVertexArrayObject")
+@Native("OESVertexArrayObject,OES_vertex_array_object")
class OesVertexArrayObject extends Interceptor {
// To suppress missing implicit constructor warnings.
factory OesVertexArrayObject._() { throw new UnsupportedError("Not supported"); }
diff --git a/tests/co19/co19-analyzer2.status b/tests/co19/co19-analyzer2.status
index 1845277..12e0ed9 100644
--- a/tests/co19/co19-analyzer2.status
+++ b/tests/co19/co19-analyzer2.status
@@ -4,6 +4,15 @@
[ $compiler == dart2analyzer ]
+# Trailing commas are now allowed by the language - issue #26644
+Language/Functions/Formal_Parameters/syntax_t12: MissingCompileTimeError
+Language/Functions/Formal_Parameters/syntax_t05: MissingCompileTimeError
+Language/Functions/Formal_Parameters/syntax_t04: MissingCompileTimeError
+Language/Expressions/Function_Invocation/Actual_Argument_List_Evaluation/syntax_t05: MissingCompileTimeError
+Language/Expressions/Method_Invocation/Ordinary_Invocation/syntax_t05: MissingCompileTimeError
+Language/Expressions/Method_Invocation/Ordinary_Invocation/syntax_t10: MissingCompileTimeError
+Language/Expressions/Method_Invocation/Super_Invocation/syntax_t05: MissingCompileTimeError
+
WebPlatformTest/html/semantics/forms/the-textarea-element/textarea-type_t01: fail
LayoutTests/fast/events/event-creation_t01: Skip # Roll 45 OverflowEvent removed
LayoutTests/fast/forms/checkValidity-001_t01: fail
diff --git a/tests/co19/co19-co19.status b/tests/co19/co19-co19.status
index 80a6317..9d68884 100644
--- a/tests/co19/co19-co19.status
+++ b/tests/co19/co19-co19.status
@@ -76,7 +76,7 @@
[ $runtime == dartium || $compiler == dart2js ]
LibTest/async/Future/Future.delayed_A01_t02: Pass, Fail # Issue 15524
-[ ($compiler == none || $compiler == precompiler) && ($runtime == vm || $runtime == drt || $runtime == dartium || $runtime == dart_precompiled) ]
+[ ($compiler == none || $compiler == precompiler || $compiler == dart2appjit) && ($runtime == vm || $runtime == drt || $runtime == dartium || $runtime == dart_precompiled || $runtime == dart_app) ]
# Optional trailing commas for argument and parameter lists added to language.
# https://github.com/dart-lang/co19/issues/68
Language/Expressions/Function_Invocation/Actual_Argument_List_Evaluation/syntax_t05: Fail, OK
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index 2740bdf..d1662c9 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -3,6 +3,15 @@
# BSD-style license that can be found in the LICENSE file.
[ $compiler == dart2js ]
+# Trailing commas are now allowed by the language - issue #26644
+Language/Functions/Formal_Parameters/syntax_t12: MissingCompileTimeError
+Language/Functions/Formal_Parameters/syntax_t05: MissingCompileTimeError
+Language/Functions/Formal_Parameters/syntax_t04: MissingCompileTimeError
+Language/Expressions/Function_Invocation/Actual_Argument_List_Evaluation/syntax_t05: MissingCompileTimeError
+Language/Expressions/Method_Invocation/Ordinary_Invocation/syntax_t05: MissingCompileTimeError
+Language/Expressions/Method_Invocation/Ordinary_Invocation/syntax_t10: MissingCompileTimeError
+Language/Expressions/Method_Invocation/Super_Invocation/syntax_t05: MissingCompileTimeError
+
Language/Classes/Constructors/Generative_Constructors/execution_of_a_superinitializer_t01: RuntimeError # compiler cancelled: cannot resolve type T
Language/Classes/Constructors/Generative_Constructors/execution_of_a_superinitializer_t01: RuntimeError, OK # co19 issue 258
Language/Classes/Constructors/Generative_Constructors/execution_of_an_initializer_t02: fail # Issue 13363
@@ -876,6 +885,7 @@
LayoutTests/fast/css/counters/complex-before_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/css-escaped-identifier_t01: RuntimeError # co19 issue 14
LayoutTests/fast/css/css-properties-case-insensitive_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/css/cssText-shorthand_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/css3-nth-tokens-style_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/csstext-of-content-string_t01: Pass, RuntimeError # Please triage this failure
LayoutTests/fast/css/deprecated-flexbox-auto-min-size_t01: RuntimeError # Please triage this failure
@@ -890,11 +900,13 @@
LayoutTests/fast/css/font-face-unicode-range-overlap-load_t01: Pass, RuntimeError # Please triage this failure
LayoutTests/fast/css/font-family-trailing-bracket-gunk_t01: RuntimeError # Please triage this failure
LayoutTests/fast/css/font-shorthand-from-longhands_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/css/fontfaceset-download-error_t01: 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-border-image_t01: RuntimeError # co19 issue 14
LayoutTests/fast/css/getComputedStyle/computed-style-cross-fade_t01: RuntimeError # co19 issue 14
LayoutTests/fast/css/getComputedStyle/font-family-fallback-reset_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/css/getPropertyValue-border_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/implicit-attach-marking_t01: Skip # Times out. Please triage this failure
@@ -1028,6 +1040,7 @@
LayoutTests/fast/dom/characterdata-api-arguments_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/click-method-on-html-element_t01: RuntimeError # Issue 25155
LayoutTests/fast/dom/client-width-height-quirks_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/dom/css-shorthand-common-value_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/custom/document-register-basic_t01: RuntimeError # Dartium JSInterop failure
LayoutTests/fast/dom/custom/document-register-svg-extends_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/custom/element-names_t01: Pass, RuntimeError # Please triage this failure
@@ -1063,7 +1076,6 @@
LayoutTests/fast/dom/shadow/shadowdom-for-input-type-change_t01: RuntimeError # Issue 26729
LayoutTests/fast/dom/shadow/shadowroot-clonenode_t01: RuntimeError # Issue 26729
LayoutTests/fast/dom/shadow/shadowroot-host_t01: RuntimeError # Issue 26729
-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
LayoutTests/fast/dom/shadow/pseudoclass-update-disabled-optgroup_t01: RuntimeError # Please triage this failure
LayoutTests/fast/dom/shadow/pseudoclass-update-disabled-option_t01: RuntimeError # Please triage this failure
@@ -1089,6 +1101,7 @@
LayoutTests/fast/events/clipboard-dataTransferItemList_t01: Skip # Times out. Please triage this failure
LayoutTests/fast/events/div-focus_t01: Pass, RuntimeError # Please triage this failure
LayoutTests/fast/events/document-elementFromPoint_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/events/event-attributes-after-exception_t01: RuntimeError # Please triage this failure
LayoutTests/fast/events/event-creation_t01: RuntimeError # Please triage this failure
LayoutTests/fast/events/event-listener-html-non-html-confusion_t01: RuntimeError # Please triage this failure
LayoutTests/fast/events/event-trace_t01: RuntimeError # Please triage this failure
@@ -1482,8 +1495,10 @@
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/kind_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/kind_t01: RuntimeError # 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_t01: RuntimeError # Please triage this failure
WebPlatformTest/html/semantics/forms/textfieldselection/textfieldselection-setRangeText_t01: RuntimeError # Please triage this failure
@@ -1524,7 +1539,6 @@
WebPlatformTest/html/semantics/selectors/pseudo-classes/enabled_t01: RuntimeError # Please triage this failure
WebPlatformTest/html/semantics/selectors/pseudo-classes/focus_t01: Pass, RuntimeError # Please triage this failure
WebPlatformTest/html/semantics/selectors/pseudo-classes/indeterminate_t01: RuntimeError # Please triage this failure
-WebPlatformTest/html/semantics/selectors/pseudo-classes/inrange-outofrange_t01: RuntimeError # Please triage this failure
WebPlatformTest/html/semantics/selectors/pseudo-classes/link_t01: RuntimeError # Please triage this failure
WebPlatformTest/html/semantics/selectors/pseudo-classes/valid-invalid_t01: Pass, RuntimeError # Please triage this failure
WebPlatformTest/html/semantics/tabular-data/the-table-element/table-rows_t01: RuntimeError # Please triage this failure
@@ -1869,10 +1883,9 @@
LayoutTests/fast/canvas/rgba-parsing_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/WebGLContextEvent_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/context-attributes-alpha-depth-stencil-antialias-t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/context-destroyed-crash_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/context-lost-restored_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/context-lost_t01: RuntimeError # Please triage this failure
-LayoutTests/fast/canvas/webgl/oes-vertex-array-object_t01: RuntimeError # Please triage this failure
+LayoutTests/fast/canvas/webgl/context-destroyed-crash_t01: Pass, RuntimeError # Issue 26898
+LayoutTests/fast/canvas/webgl/context-lost-restored_t01: Pass, RuntimeError # Issue 26898
+LayoutTests/fast/canvas/webgl/context-lost_t01: Pass, RuntimeError # Issue 26898
LayoutTests/fast/canvas/webgl/renderer-and-vendor-strings_t01: RuntimeError # Please triage this failure
LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-array-buffer-view_t01: Skip # Times out.
LayoutTests/fast/canvas/webgl/tex-image-and-sub-image-2d-with-image_t01: RuntimeError # Please triage this failure
diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status
index 941a1d8..1af71e5 100644
--- a/tests/co19/co19-runtime.status
+++ b/tests/co19/co19-runtime.status
@@ -158,11 +158,13 @@
Language/Metadata/*: SkipByDesign # Uses dart:mirrors
Language/Expressions/Null/instance_of_class_null_t01: Skip # Uses dart:mirrors
+[ $noopt || $compiler == precompiler || $compiler == dart2appjit || $mode == product ]
+Language/Libraries_and_Scripts/Imports/deferred_import_t02: Skip # Eager loading
+Language/Libraries_and_Scripts/Imports/invalid_uri_deferred_t01: Skip # Eager loading
+Language/Libraries_and_Scripts/Imports/invalid_uri_deferred_t02: Skip # Eager loading
+
[ $runtime == dart_precompiled || $runtime == dart_app ]
LibTest/isolate/Isolate/spawnUri*: Skip # Isolate.spawnUri
-Language/Libraries_and_Scripts/Imports/invalid_uri_deferred_t01: CompileTimeError # spawnUri
-Language/Libraries_and_Scripts/Imports/invalid_uri_deferred_t02: RuntimeError # spawnUri
-Language/Libraries_and_Scripts/Imports/deferred_import_t02: RuntimeError # Unsupported
[ $noopt || $compiler == precompiler ]
LibTest/collection/ListBase/ListBase_class_A01_t02: Pass, Timeout
@@ -192,21 +194,41 @@
LibTest/typed_data/Float32x4/operator_division_A01_t02: RuntimeError # Issue #26675
[ $hot_reload ]
-LibTest/collection/DoubleLinkedQueue/DoubleLinkedQueue_class_A01_t01: Pass, Crash
-LibTest/collection/HashSet/HashSet_class_A01_t01: Crash
-LibTest/collection/IterableBase/IterableBase_class_A01_t02: Crash
-LibTest/collection/LinkedHashSet/LinkedHashSet_class_A01_t01: Crash
-LibTest/collection/LinkedList/iterator_current_A01_t01: Crash
-LibTest/collection/ListBase/ListBase_class_A01_t01: Pass, Timeout, Crash
+Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/getter_closurization_t08: Pass, Fail # Closure identity
+Language/Expressions/Property_Extraction/Ordinary_Member_Closurization/method_identical_t03: Pass, Fail # Closure identity
+Language/Expressions/Property_Extraction/conditional_t05: Pass, Fail # Closure identity
+Language/Expressions/Assignment/prefix_object_t02: Crash # Requires deferred libraries
+Language/Expressions/Constants/constant_constructor_t03: Crash # Requires deferred libraries
+Language/Expressions/Constants/identifier_denotes_a_constant_t06: Crash # Requires deferred libraries
+Language/Expressions/Constants/identifier_denotes_a_constant_t07: Crash # Requires deferred libraries
+Language/Expressions/Constants/static_constant_t06: Crash # Requires deferred libraries
+Language/Expressions/Constants/static_constant_t07: Crash # Requires deferred libraries
+Language/Expressions/Constants/top_level_function_t04: Crash # Requires deferred libraries
+Language/Expressions/Constants/top_level_function_t05: Crash # Requires deferred libraries
+Language/Expressions/Instance_Creation/Const/deferred_type_t01: Crash # Requires deferred libraries
+Language/Expressions/Instance_Creation/Const/deferred_type_t02: Crash # Requires deferred libraries
+Language/Expressions/Instance_Creation/New/evaluation_t19: Crash # Requires deferred libraries
+Language/Expressions/Instance_Creation/New/evaluation_t20: Crash # Requires deferred libraries
+Language/Expressions/Property_Extraction/Anonymous_Constructor_Extraction/deferred_type_t01: Crash # Requires deferred libraries
+Language/Expressions/Property_Extraction/Named_Constructor_Extraction/deferred_type_t01: Crash # Requires deferred libraries
+Language/Expressions/Type_Cast/evaluation_t10: Crash # Requires deferred libraries
+Language/Expressions/Type_Test/evaluation_t10: Crash # Requires deferred libraries
+Language/Libraries_and_Scripts/Imports/deferred_import_t01: Crash # Requires deferred libraries
+Language/Libraries_and_Scripts/Imports/deferred_import_t02: Crash # Requires deferred libraries
+Language/Libraries_and_Scripts/Imports/invalid_uri_deferred_t01: Crash # Requires deferred libraries
+Language/Libraries_and_Scripts/Imports/invalid_uri_deferred_t02: Crash # Requires deferred libraries
+Language/Libraries_and_Scripts/Imports/invalid_uri_deferred_t03: Crash # Requires deferred libraries
+Language/Libraries_and_Scripts/Imports/static_type_t01: Crash # Requires deferred libraries
+Language/Types/Dynamic_Type_System/deferred_type_error_t01: Crash # Requires deferred libraries
+Language/Types/Static_Types/deferred_type_t01: Crash # Requires deferred libraries
+LibTest/async/DeferredLibrary/DeferredLibrary_A01_t01: Crash # Requires deferred libraries
+LibTest/collection/ListBase/ListBase_class_A01_t01: Pass, Timeout
LibTest/collection/ListBase/ListBase_class_A01_t02: Pass, Timeout
-LibTest/collection/ListMixin/ListMixin_class_A01_t01: Pass, Timeout, Crash
+LibTest/collection/ListMixin/ListMixin_class_A01_t01: Pass, Timeout
LibTest/collection/ListMixin/ListMixin_class_A01_t02: Pass, Timeout
-LibTest/collection/ListQueue/ListQueue_class_A01_t01: Pass, Crash
-LibTest/collection/Queue/Queue_class_A01_t01: Pass, Crash
-LibTest/core/List/List.from_A01_t01: Crash
-LibTest/core/List/List_class_A01_t01: Pass, Crash
-LibTest/core/List/List_class_A01_t02: Pass, Timeout, Crash
+LibTest/core/List/List_class_A01_t02: Pass, Timeout
LibTest/core/Map/Map_class_A01_t04: Pass, Timeout
-LibTest/core/Set/IterableBase_A01_t01: Pass, Crash
LibTest/core/Uri/Uri_A06_t03: Pass, Timeout
LibTest/core/Uri/encodeQueryComponent_A01_t02: Pass, Timeout
+LibTest/isolate/Isolate/spawn_A01_t04: Pass, Timeout
+
diff --git a/tests/compiler/dart2js/async_await_js_transform_test.dart b/tests/compiler/dart2js/async_await_js_transform_test.dart
index 40c9eb6..e934d28 100644
--- a/tests/compiler/dart2js/async_await_js_transform_test.dart
+++ b/tests/compiler/dart2js/async_await_js_transform_test.dart
@@ -73,8 +73,6 @@
v1 = 0;
if (v1 < 0 || v1 >= v0.length)
H.ioore(v0, v1);
- else
- ;
v2 = 4;
v3 = 2;
P.print(v0[v1].call$2(v2, v3));
diff --git a/tests/compiler/dart2js/constant_expression_evaluate_test.dart b/tests/compiler/dart2js/constant_expression_evaluate_test.dart
index 49f3b51..3dd05ac 100644
--- a/tests/compiler/dart2js/constant_expression_evaluate_test.dart
+++ b/tests/compiler/dart2js/constant_expression_evaluate_test.dart
@@ -61,6 +61,8 @@
const ConstantData('identical(0, 1)',
const { const {} : 'BoolConstant(false)' }),
const ConstantData('"a" "b"', const { const {} : 'StringConstant("ab")' }),
+ const ConstantData(r'"${null}"',
+ const { const {} : 'StringConstant("null")' }),
const ConstantData('identical',
const { const {} : 'FunctionConstant(identical)' }),
const ConstantData('true ? 0 : 1', const { const {} : 'IntConstant(0)' }),
@@ -79,6 +81,9 @@
const { const {} :
'MapConstant(<int, int>{IntConstant(0): IntConstant(1), '
'IntConstant(2): IntConstant(3)})' }),
+ const ConstantData('const <int, int>{0: 1, 0: 2}',
+ const { const {} :
+ 'MapConstant(<int, int>{IntConstant(0): IntConstant(2)})' }),
const ConstantData(
'const bool.fromEnvironment("foo", defaultValue: false)',
const { const {} : 'BoolConstant(false)',
diff --git a/tests/compiler/dart2js/dart2js.status b/tests/compiler/dart2js/dart2js.status
index d4ef503..7b4c8f9 100644
--- a/tests/compiler/dart2js/dart2js.status
+++ b/tests/compiler/dart2js/dart2js.status
@@ -75,6 +75,7 @@
serialization*: Slow, Pass
uri_retention_test: Pass, Slow
value_range_test: Pass, Slow
+jsinterop/world_test: Pass, Slow
[ $mode == debug ]
check_elements_invariants_test: Skip # Slow and only needs to be run in one
diff --git a/tests/compiler/dart2js/elide_callthrough_stub_test.dart b/tests/compiler/dart2js/elide_callthrough_stub_test.dart
new file mode 100644
index 0000000..bdb9667
--- /dev/null
+++ b/tests/compiler/dart2js/elide_callthrough_stub_test.dart
@@ -0,0 +1,60 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Check that calls through fields elide the call-through stub. This
+// optimization is done by the simplifier, so inlining does not need to be
+// enabled.
+
+import 'package:async_helper/async_helper.dart';
+import 'package:expect/expect.dart';
+import 'compiler_helper.dart';
+
+const String TEST1 = r'''
+class W {
+ final Function _fun;
+ W(this._fun);
+ foo(zzz) => _fun(zzz); // this._fun$1(zzz) --> this._fun.call$1(zzz)
+}
+add1(x) => x + 1;
+main() {
+ var w = new W(add1);
+ var x = w.foo(42);
+}
+''';
+
+const String TEST2 = r'''
+class W {
+ final Function __fun;
+ Function get _fun => __fun;
+ W(this.__fun);
+ foo(zzz) => _fun(zzz); // this._fun$1(zzz) stays same.
+}
+add1(x) => x + 1;
+main() {
+ var w = new W(add1);
+ var x = w.foo(42);
+}
+''';
+
+main() {
+ asyncTest(() => compileAll(TEST1).then((generated) {
+ // Direct call through field.
+ Expect.isTrue(generated.contains(r'this._fun.call$1(zzz)'));
+ // No stub.
+ Expect.isFalse(generated.contains(r'_fun$1:'));
+ // No call to stub.
+ Expect.isFalse(generated.contains(r'_fun$1('));
+ }));
+
+ asyncTest(() => compileAll(TEST2).then((generated) {
+ // No call through field.
+ Expect.isFalse(generated.contains(r'this._fun.call$1(zzz)'));
+ // Call through stub.
+ Expect.isTrue(generated.contains(r'this._fun$1(zzz)'));
+ // Stub is generated.
+ Expect.isTrue(generated.contains(r'_fun$1:'));
+ // Call through getter (inside stub).
+ Expect.isTrue(generated.contains(r'get$_fun().call$1'));
+ }));
+}
diff --git a/tests/compiler/dart2js/exit_code_test.dart b/tests/compiler/dart2js/exit_code_test.dart
index ff419c7..bf3cdeb 100644
--- a/tests/compiler/dart2js/exit_code_test.dart
+++ b/tests/compiler/dart2js/exit_code_test.dart
@@ -150,10 +150,15 @@
}
class TestResolver extends ResolverTask {
- TestResolver(TestCompiler compiler, ConstantCompiler constantCompiler)
- : super(compiler, constantCompiler);
+ final TestCompiler compiler;
- TestCompiler get compiler => super.compiler;
+ TestResolver(TestCompiler compiler, ConstantCompiler constantCompiler)
+ : this.compiler = compiler,
+ super(
+ compiler.resolution,
+ constantCompiler,
+ compiler.world,
+ compiler.measurer);
void computeClassMembers(ClassElement element) {
compiler.test('ResolverTask.computeClassMembers');
diff --git a/tests/compiler/dart2js/jsinterop/world_test.dart b/tests/compiler/dart2js/jsinterop/world_test.dart
new file mode 100644
index 0000000..f196b8e
--- /dev/null
+++ b/tests/compiler/dart2js/jsinterop/world_test.dart
@@ -0,0 +1,161 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library jsinterop.world_test;
+
+import 'package:expect/expect.dart';
+import 'package:async_helper/async_helper.dart';
+import 'package:compiler/src/common.dart';
+import 'package:compiler/src/elements/elements.dart'
+ show Element, ClassElement;
+import 'package:compiler/src/js_backend/js_backend.dart';
+import 'package:compiler/src/world.dart';
+import '../type_test_helper.dart';
+
+void main() {
+ asyncTest(() async {
+ await testClasses();
+ });
+}
+
+testClasses() async {
+ test(String mainSource,
+ {List<String> directlyInstantiated: const <String>[],
+ List<String> indirectlyInstantiated: const <String>[]}) async {
+ TypeEnvironment env = await TypeEnvironment.create(r"""
+@JS()
+class A {
+ get foo;
+
+ external A(var foo);
+}
+
+@JS()
+class B {
+ get foo;
+
+ external B(var foo);
+}
+
+@JS()
+@anonymous
+class C {
+ final foo;
+
+ external factory C({foo});
+}
+
+@JS()
+@anonymous
+class D {
+ final foo;
+
+ external factory D({foo});
+}
+
+class E {
+ final foo;
+
+ E(this.foo);
+}
+
+class F {
+ final foo;
+
+ F(this.foo);
+}
+
+newA() => new A(0);
+newB() => new B(1);
+newC() => new C(foo: 2);
+newD() => new D(foo: 3);
+newE() => new E(4);
+newF() => new F(5);
+""", mainSource: """
+import 'package:js/js.dart';
+
+$mainSource
+""", useMockCompiler: false);
+ Map<String, ClassElement> classEnvironment = <String, ClassElement>{};
+
+ ClassElement registerClass(ClassElement cls) {
+ classEnvironment[cls.name] = cls;
+ return cls;
+ }
+
+ ClassWorld world = env.compiler.world;
+ JavaScriptBackend backend = env.compiler.backend;
+ ClassElement Object_ = registerClass(env.compiler.coreClasses.objectClass);
+ ClassElement Interceptor =
+ registerClass(backend.helpers.jsInterceptorClass);
+ ClassElement JavaScriptObject =
+ registerClass(backend.helpers.jsJavaScriptObjectClass);
+ ClassElement A = registerClass(env.getElement('A'));
+ ClassElement B = registerClass(env.getElement('B'));
+ ClassElement C = registerClass(env.getElement('C'));
+ ClassElement D = registerClass(env.getElement('D'));
+ ClassElement E = registerClass(env.getElement('E'));
+ ClassElement F = registerClass(env.getElement('F'));
+
+ Expect.equals(Interceptor.superclass, Object_);
+ Expect.equals(JavaScriptObject.superclass, Interceptor);
+
+ Expect.equals(A.superclass, JavaScriptObject);
+ Expect.equals(B.superclass, JavaScriptObject);
+ Expect.equals(C.superclass, JavaScriptObject);
+ Expect.equals(D.superclass, JavaScriptObject);
+ Expect.equals(E.superclass, Object_);
+ Expect.equals(F.superclass, Object_);
+
+ for (String name in classEnvironment.keys) {
+ ClassElement cls = classEnvironment[name];
+ bool isInstantiated = false;
+ if (directlyInstantiated.contains(name)) {
+ isInstantiated = true;
+ Expect.isTrue(world.isDirectlyInstantiated(cls),
+ "Expected $name to be directly instantiated in `${mainSource}`:"
+ "\n${world.dump(cls)}");
+ }
+ if (indirectlyInstantiated.contains(name)) {
+ isInstantiated = true;
+ Expect.isTrue(world.isIndirectlyInstantiated(cls),
+ "Expected $name to be indirectly instantiated in `${mainSource}`:"
+ "\n${world.dump(cls)}");
+ }
+ if (!isInstantiated && (name != 'Object' && name != 'Interceptor')) {
+ Expect.isFalse(world.isInstantiated(cls),
+ "Expected $name to be uninstantiated in `${mainSource}`:"
+ "\n${world.dump(cls)}");
+ }
+ }
+ }
+
+ await test('main() {}');
+
+ await test('main() => newA();',
+ directlyInstantiated: ['A', 'B', 'C', 'D'],
+ indirectlyInstantiated: ['Object', 'Interceptor', 'JavaScriptObject']);
+
+ await test('main() => newB();',
+ directlyInstantiated: ['A', 'B', 'C', 'D'],
+ indirectlyInstantiated: ['Object', 'Interceptor', 'JavaScriptObject']);
+
+ await test('main() => newC();',
+ directlyInstantiated: ['A', 'B', 'C', 'D'],
+ indirectlyInstantiated: ['Object', 'Interceptor', 'JavaScriptObject']);
+
+ await test('main() => newD();',
+ directlyInstantiated: ['A', 'B', 'C', 'D'],
+ indirectlyInstantiated: ['Object', 'Interceptor', 'JavaScriptObject']);
+
+ await test('main() => newE();',
+ directlyInstantiated: ['E']);
+
+ await test('main() => newF();',
+ directlyInstantiated: ['F']);
+
+ await test('main() => [newD(), newE()];',
+ directlyInstantiated: ['A', 'B', 'C', 'D', 'E'],
+ indirectlyInstantiated: ['Object', 'Interceptor', 'JavaScriptObject']);
+}
diff --git a/tests/compiler/dart2js/memory_source_file_helper.dart b/tests/compiler/dart2js/memory_source_file_helper.dart
index 2efa806..c6b3b3c 100644
--- a/tests/compiler/dart2js/memory_source_file_helper.dart
+++ b/tests/compiler/dart2js/memory_source_file_helper.dart
@@ -33,7 +33,8 @@
}
String source = memorySourceFiles[resourceUri.path];
if (source == null) {
- return new Future.error(new Exception('No such file $resourceUri'));
+ return new Future.error(new Exception(
+ 'No such memory file $resourceUri in ${memorySourceFiles.keys}'));
}
this.sourceFiles[resourceUri] =
new StringSourceFile.fromUri(resourceUri, source);
@@ -48,7 +49,8 @@
}
String source = memorySourceFiles[resourceUri.path];
if (source == null) {
- throw new Exception('No such file $resourceUri');
+ throw new Exception(
+ 'No such memory file $resourceUri in ${memorySourceFiles.keys}');
}
return new StringSourceFile.fromUri(resourceUri, source);
}
diff --git a/tests/compiler/dart2js/minimal_resolution_test.dart b/tests/compiler/dart2js/minimal_resolution_test.dart
index 7de35a3..ddc1eaf 100644
--- a/tests/compiler/dart2js/minimal_resolution_test.dart
+++ b/tests/compiler/dart2js/minimal_resolution_test.dart
@@ -29,19 +29,17 @@
bool isProcessed = enqueuer.isClassProcessed(cls);
Expect.equals(expected, isInstantiated,
'Unexpected instantiation state of class $cls.');
- Expect.equals(expected, isProcessed,
- 'Unexpected processing state of class $cls.');
+ Expect.equals(
+ expected, isProcessed, 'Unexpected processing state of class $cls.');
}
analyze(String code,
- {bool proxyConstant: false,
- bool deprecatedClass: false}) async {
+ {bool proxyConstant: false, bool deprecatedClass: false}) async {
CompilationResult result = await runCompiler(
- memorySourceFiles: {'main.dart': code},
- options: ['--analyze-only']);
+ memorySourceFiles: {'main.dart': code}, options: ['--analyze-only']);
Expect.isTrue(result.isSuccess);
Compiler compiler = result.compiler;
- Expect.equals(proxyConstant, compiler.proxyConstant != null,
+ Expect.equals(proxyConstant, compiler.resolution.proxyConstant != null,
"Unexpected computation of proxy constant.");
checkInstantiated(
diff --git a/tests/compiler/dart2js/mock_compiler.dart b/tests/compiler/dart2js/mock_compiler.dart
index 9c5b770..cf612bf 100644
--- a/tests/compiler/dart2js/mock_compiler.dart
+++ b/tests/compiler/dart2js/mock_compiler.dart
@@ -228,9 +228,9 @@
ExecutableElement element) {
ResolverVisitor visitor =
new ResolverVisitor(
- this,
+ this.resolution,
element,
- new ResolutionRegistry(this,
+ new ResolutionRegistry(this.backend,
new CollectingTreeElements(element)),
scope: new MockTypeVariablesScope(
element.enclosingElement.buildScope()));
@@ -247,10 +247,10 @@
Element mockElement = new MockElement(mainApp.entryCompilationUnit);
ResolverVisitor visitor =
new ResolverVisitor(
- this,
+ this.resolution,
mockElement,
new ResolutionRegistry(
- this, new CollectingTreeElements(mockElement)),
+ this.backend, new CollectingTreeElements(mockElement)),
scope: mockElement.enclosingElement.buildScope());
visitor.scope = new MethodScope(visitor.scope, mockElement);
return visitor;
diff --git a/tests/compiler/dart2js/patch_test.dart b/tests/compiler/dart2js/patch_test.dart
index 2130f06..607fae9 100644
--- a/tests/compiler/dart2js/patch_test.dart
+++ b/tests/compiler/dart2js/patch_test.dart
@@ -1023,13 +1023,17 @@
class A {
A() : super();
factory A.forward() = B.patchTarget;
+ factory A.forwardOne() = B.patchFactory;
factory A.forwardTwo() = B.reflectBack;
+ factory A.forwardThree() = B.patchInjected;
}
class B extends A {
B() : super();
external B.patchTarget();
+ external factory B.patchFactory();
external factory B.reflectBack();
B.originTarget() : super();
+ external factory B.patchInjected();
}
""";
String patch = """
@@ -1037,7 +1041,14 @@
@patch
B.patchTarget() : super();
@patch
+ factory B.patchFactory() => new B.patchTarget();
+ @patch
factory B.reflectBack() = B.originTarget;
+ @patch
+ factory B.patchInjected() = _C.injected;
+ }
+ class _C extends B {
+ _C.injected() : super.patchTarget();
}
""";
@@ -1048,14 +1059,28 @@
ConstructorElement forward = clsA.lookupConstructor("forward");
ConstructorElement target = forward.effectiveTarget;
- Expect.isTrue(target.isPatch);
+ Expect.isTrue(target.isPatched, "Unexpected target $target for $forward");
+ Expect.isFalse(target.isPatch, "Unexpected target $target for $forward");
Expect.equals("patchTarget", target.name);
+ ConstructorElement forwardOne = clsA.lookupConstructor("forwardOne");
+ target = forwardOne.effectiveTarget;
+ Expect.isFalse(forwardOne.isMalformed);
+ Expect.isFalse(target.isPatch, "Unexpected target $target for $forwardOne");
+ Expect.equals("patchFactory", target.name);
+
ConstructorElement forwardTwo = clsA.lookupConstructor("forwardTwo");
target = forwardTwo.effectiveTarget;
Expect.isFalse(forwardTwo.isMalformed);
- Expect.isFalse(target.isPatch);
+ Expect.isFalse(target.isPatch, "Unexpected target $target for $forwardTwo");
Expect.equals("originTarget", target.name);
+
+ ConstructorElement forwardThree = clsA.lookupConstructor("forwardThree");
+ target = forwardThree.effectiveTarget;
+ Expect.isFalse(forwardThree.isMalformed);
+ Expect.isTrue(target.isInjected,
+ "Unexpected target $target for $forwardThree");
+ Expect.equals("injected", target.name);
}
Future testTypecheckPatchedMembers() async {
diff --git a/tests/compiler/dart2js/resolver_test.dart b/tests/compiler/dart2js/resolver_test.dart
index 2e1868a..5ddf37c 100644
--- a/tests/compiler/dart2js/resolver_test.dart
+++ b/tests/compiler/dart2js/resolver_test.dart
@@ -223,9 +223,11 @@
FunctionElement fooA = classA.lookupLocalMember("foo");
ResolverVisitor visitor = new ResolverVisitor(
- compiler,
+ compiler.resolution,
fooB,
- new ResolutionRegistry(compiler, new CollectingTreeElements(fooB)),
+ new ResolutionRegistry(
+ compiler.backend,
+ new CollectingTreeElements(fooB)),
scope: new MockTypeVariablesScope(classB.buildScope()));
FunctionExpression node =
(fooB as FunctionElementX).parseNode(compiler.parsingContext);
@@ -268,10 +270,10 @@
ClassElement fooElement = compiler.mainApp.find("Foo");
FunctionElement funElement = fooElement.lookupLocalMember("foo");
ResolverVisitor visitor = new ResolverVisitor(
- compiler,
+ compiler.resolution,
funElement,
new ResolutionRegistry(
- compiler, new CollectingTreeElements(funElement)),
+ compiler.backend, new CollectingTreeElements(funElement)),
scope: new MockTypeVariablesScope(fooElement.buildScope()));
FunctionExpression function =
(funElement as FunctionElementX).parseNode(compiler.parsingContext);
@@ -296,10 +298,10 @@
ClassElement fooElement = compiler.mainApp.find("Foo");
FunctionElement funElement = fooElement.lookupLocalMember("foo");
ResolverVisitor visitor = new ResolverVisitor(
- compiler,
+ compiler.resolution,
funElement,
new ResolutionRegistry(
- compiler, new CollectingTreeElements(funElement)),
+ compiler.backend, new CollectingTreeElements(funElement)),
scope: new MockTypeVariablesScope(fooElement.buildScope()));
FunctionExpression function =
(funElement as FunctionElementX).parseNode(compiler.parsingContext);
@@ -588,9 +590,11 @@
compiler.parseScript("abstract class Bar {}");
ResolverVisitor visitor = new ResolverVisitor(
- compiler,
+ compiler.resolution,
null,
- new ResolutionRegistry(compiler, new CollectingTreeElements(null)));
+ new ResolutionRegistry(
+ compiler.backend,
+ new CollectingTreeElements(null)));
compiler.resolveStatement("Foo bar;");
ClassElement fooElement = compiler.mainApp.find('Foo');
@@ -707,9 +711,11 @@
element = classElement.lookupConstructor(constructor);
FunctionExpression tree = (element as FunctionElement).node;
ResolverVisitor visitor = new ResolverVisitor(
- compiler,
+ compiler.resolution,
element,
- new ResolutionRegistry(compiler, new CollectingTreeElements(element)),
+ new ResolutionRegistry(
+ compiler.backend,
+ new CollectingTreeElements(element)),
scope: classElement.buildScope());
new InitializerResolver(visitor, element, tree).resolveInitializers();
visitor.visit(tree.body);
diff --git a/tests/compiler/dart2js/serialization/analysis1_test.dart b/tests/compiler/dart2js/serialization/analysis1_test.dart
index 1b8532e..e78f634 100644
--- a/tests/compiler/dart2js/serialization/analysis1_test.dart
+++ b/tests/compiler/dart2js/serialization/analysis1_test.dart
@@ -5,8 +5,8 @@
library dart2js.serialization.analysis1_test;
import 'analysis_test_helper.dart' as test;
-import 'test_data.dart';
+import 'test_helper.dart';
main() {
- test.main(['0', '${TESTS.length ~/ 2}']);
+ test.main(testSegment(1, test.SPLIT_COUNT, test.SKIP_COUNT));
}
diff --git a/tests/compiler/dart2js/serialization/analysis2_test.dart b/tests/compiler/dart2js/serialization/analysis2_test.dart
index b13a6a3..05c3339 100644
--- a/tests/compiler/dart2js/serialization/analysis2_test.dart
+++ b/tests/compiler/dart2js/serialization/analysis2_test.dart
@@ -5,8 +5,8 @@
library dart2js.serialization.analysis2_test;
import 'analysis_test_helper.dart' as test;
-import 'test_data.dart';
+import 'test_helper.dart';
main() {
- test.main(['${TESTS.length ~/ 2}']);
+ test.main(testSegment(2, test.SPLIT_COUNT, test.SKIP_COUNT));
}
diff --git a/tests/compiler/dart2js/serialization/analysis_test_helper.dart b/tests/compiler/dart2js/serialization/analysis_test_helper.dart
index 152972b..52b0271 100644
--- a/tests/compiler/dart2js/serialization/analysis_test_helper.dart
+++ b/tests/compiler/dart2js/serialization/analysis_test_helper.dart
@@ -14,6 +14,12 @@
import 'helper.dart';
import 'test_data.dart';
+/// Number of tests that are not part of the automatic test grouping.
+int SKIP_COUNT = 0;
+
+/// Number of groups that the [TESTS] are split into.
+int SPLIT_COUNT = 2;
+
main(List<String> args) {
asyncTest(() async {
Arguments arguments = new Arguments.from(args);
@@ -27,6 +33,7 @@
} else {
await arguments.forEachTest(serializedData, TESTS, analyze);
}
+ printMeasurementResults();
});
}
@@ -39,27 +46,27 @@
bool verbose: false}) async {
String testDescription = test != null ? test.name : '${entryPoint}';
String id = index != null ? '$index: ' : '';
- print('------------------------------------------------------------------');
- print('analyze ${id}${testDescription}');
- print('------------------------------------------------------------------');
- DiagnosticCollector diagnosticCollector = new DiagnosticCollector();
- await runCompiler(
- entryPoint: entryPoint,
- resolutionInputs: resolutionInputs,
- memorySourceFiles: sourceFiles,
- options: [Flags.analyzeOnly],
- diagnosticHandler: diagnosticCollector);
- if (test != null) {
- Expect.equals(test.expectedErrorCount, diagnosticCollector.errors.length,
- "Unexpected error count.");
- Expect.equals(
- test.expectedWarningCount,
- diagnosticCollector.warnings.length,
- "Unexpected warning count.");
- Expect.equals(test.expectedHintCount, diagnosticCollector.hints.length,
- "Unexpected hint count.");
- Expect.equals(test.expectedInfoCount, diagnosticCollector.infos.length,
- "Unexpected info count.");
- }
+ String title = '${id}${testDescription}';
+ await measure(title, 'analyze', () async {
+ DiagnosticCollector diagnosticCollector = new DiagnosticCollector();
+ await runCompiler(
+ entryPoint: entryPoint,
+ resolutionInputs: resolutionInputs,
+ memorySourceFiles: sourceFiles,
+ options: [Flags.analyzeOnly],
+ diagnosticHandler: diagnosticCollector);
+ if (test != null) {
+ Expect.equals(test.expectedErrorCount, diagnosticCollector.errors.length,
+ "Unexpected error count.");
+ Expect.equals(
+ test.expectedWarningCount,
+ diagnosticCollector.warnings.length,
+ "Unexpected warning count.");
+ Expect.equals(test.expectedHintCount, diagnosticCollector.hints.length,
+ "Unexpected hint count.");
+ Expect.equals(test.expectedInfoCount, diagnosticCollector.infos.length,
+ "Unexpected info count.");
+ }
+ });
}
diff --git a/tests/compiler/dart2js/serialization/compilation0_test.dart b/tests/compiler/dart2js/serialization/compilation0_test.dart
index 9df7f53..3e68dd2 100644
--- a/tests/compiler/dart2js/serialization/compilation0_test.dart
+++ b/tests/compiler/dart2js/serialization/compilation0_test.dart
@@ -5,8 +5,8 @@
library dart2js.serialization.compilation0_test;
import 'compilation_test_helper.dart' as test;
-import 'test_data.dart';
+import 'test_helper.dart';
main() {
- test.main(['0', '0']);
+ test.main(testSkipped(0, test.SKIP_COUNT));
}
diff --git a/tests/compiler/dart2js/serialization/compilation1_test.dart b/tests/compiler/dart2js/serialization/compilation1_test.dart
index e3f6176..f59e0a0 100644
--- a/tests/compiler/dart2js/serialization/compilation1_test.dart
+++ b/tests/compiler/dart2js/serialization/compilation1_test.dart
@@ -5,8 +5,8 @@
library dart2js.serialization.compilation1_test;
import 'compilation_test_helper.dart' as test;
-import 'test_data.dart';
+import 'test_helper.dart';
main() {
- test.main(['1', '${TESTS.length ~/ 4}']);
+ test.main(testSegment(1, test.SPLIT_COUNT, test.SKIP_COUNT));
}
diff --git a/tests/compiler/dart2js/serialization/compilation2_test.dart b/tests/compiler/dart2js/serialization/compilation2_test.dart
index 6141cbb..1947010 100644
--- a/tests/compiler/dart2js/serialization/compilation2_test.dart
+++ b/tests/compiler/dart2js/serialization/compilation2_test.dart
@@ -5,8 +5,8 @@
library dart2js.serialization.compilation2_test;
import 'compilation_test_helper.dart' as test;
-import 'test_data.dart';
+import 'test_helper.dart';
main() {
- test.main(['${TESTS.length ~/ 4}', '${2 * TESTS.length ~/ 4}']);
+ test.main(testSegment(2, test.SPLIT_COUNT, test.SKIP_COUNT));
}
diff --git a/tests/compiler/dart2js/serialization/compilation3_test.dart b/tests/compiler/dart2js/serialization/compilation3_test.dart
index c168f22..90bc6ff 100644
--- a/tests/compiler/dart2js/serialization/compilation3_test.dart
+++ b/tests/compiler/dart2js/serialization/compilation3_test.dart
@@ -5,8 +5,8 @@
library dart2js.serialization.compilation3_test;
import 'compilation_test_helper.dart' as test;
-import 'test_data.dart';
+import 'test_helper.dart';
main() {
- test.main(['${2 * TESTS.length ~/ 4}', '${3 * TESTS.length ~/ 4}']);
+ test.main(testSegment(3, test.SPLIT_COUNT, test.SKIP_COUNT));
}
diff --git a/tests/compiler/dart2js/serialization/compilation4_test.dart b/tests/compiler/dart2js/serialization/compilation4_test.dart
index 7e2dc7c..809f62b 100644
--- a/tests/compiler/dart2js/serialization/compilation4_test.dart
+++ b/tests/compiler/dart2js/serialization/compilation4_test.dart
@@ -5,8 +5,8 @@
library dart2js.serialization.compilation4_test;
import 'compilation_test_helper.dart' as test;
-import 'test_data.dart';
+import 'test_helper.dart';
main() {
- test.main(['${3 * TESTS.length ~/ 4}']);
+ test.main(testSegment(4, test.SPLIT_COUNT, test.SKIP_COUNT));
}
diff --git a/tests/compiler/dart2js/serialization/compilation_1_test.dart b/tests/compiler/dart2js/serialization/compilation_1_test.dart
new file mode 100644
index 0000000..355cddc
--- /dev/null
+++ b/tests/compiler/dart2js/serialization/compilation_1_test.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart2js.serialization.compilation_1_test;
+
+import 'compilation_test_helper.dart' as test;
+import 'test_helper.dart';
+
+main() {
+ test.main(testSkipped(1, test.SKIP_COUNT));
+}
diff --git a/tests/compiler/dart2js/serialization/compilation_test_helper.dart b/tests/compiler/dart2js/serialization/compilation_test_helper.dart
index 9889bf4..5eda517 100644
--- a/tests/compiler/dart2js/serialization/compilation_test_helper.dart
+++ b/tests/compiler/dart2js/serialization/compilation_test_helper.dart
@@ -6,13 +6,19 @@
import 'dart:async';
import 'package:async_helper/async_helper.dart';
-import 'package:compiler/src/compiler.dart';
+import 'package:compiler/src/commandline_options.dart';
import 'package:compiler/src/filenames.dart';
import '../memory_compiler.dart';
import 'helper.dart';
import 'test_data.dart';
import '../output_collector.dart';
+/// Number of tests that are not part of the automatic test grouping.
+int SKIP_COUNT = 2;
+
+/// Number of groups that the [TESTS] are split into.
+int SPLIT_COUNT = 4;
+
main(List<String> args) {
asyncTest(() async {
Arguments arguments = new Arguments.from(args);
@@ -28,6 +34,7 @@
Uri entryPoint = Uri.parse('memory:main.dart');
await arguments.forEachTest(serializedData, TESTS, compile);
}
+ printMeasurementResults();
});
}
@@ -40,16 +47,20 @@
bool verbose: false}) async {
String testDescription = test != null ? test.name : '${entryPoint}';
String id = index != null ? '$index: ' : '';
- print('------------------------------------------------------------------');
- print('compile ${id}${testDescription}');
- print('------------------------------------------------------------------');
+ String title = '${id}${testDescription}';
OutputCollector outputCollector = new OutputCollector();
- await runCompiler(
- entryPoint: entryPoint,
- memorySourceFiles: sourceFiles,
- resolutionInputs: resolutionInputs,
- options: [],
- outputProvider: outputCollector);
+ await measure(title, 'compile', () async {
+ List<String> options = [];
+ if (test.checkedMode) {
+ options.add(Flags.enableCheckedMode);
+ }
+ await runCompiler(
+ entryPoint: entryPoint,
+ memorySourceFiles: sourceFiles,
+ resolutionInputs: resolutionInputs,
+ options: options,
+ outputProvider: outputCollector);
+ });
if (verbose) {
print(outputCollector.getOutput('', 'js'));
}
diff --git a/tests/compiler/dart2js/serialization/equivalence_test.dart b/tests/compiler/dart2js/serialization/equivalence_test.dart
index 4e3d6e2..ee110f6 100644
--- a/tests/compiler/dart2js/serialization/equivalence_test.dart
+++ b/tests/compiler/dart2js/serialization/equivalence_test.dart
@@ -27,9 +27,34 @@
const TEST_SOURCES = const <String, String>{
'main.dart': '''
-import 'a.dart' deferred as a;
+import 'library.dart';
+import 'deferred_library.dart' deferred as prefix;
+
+asyncMethod() async {}
+asyncStarMethod() async* {}
+syncStarMethod() sync* {}
+get asyncGetter async {}
+get asyncStarGetter async* {}
+get syncStarGetter sync* {}
+
+genericMethod<T>() {}
+
+class Class1 {
+ factory Class1.deferred() = prefix.DeferredClass;
+ factory Class1.unresolved() = Unresolved;
+}
''',
- 'a.dart': '''
+ 'deferred_library.dart': '''
+class DeferredClass {
+}
+
+get getter => 0;
+set setter(_) {}
+get property => 0;
+set property(_) {}
+''',
+ 'library.dart': '''
+class Type {}
''',
};
@@ -65,7 +90,7 @@
CompilationResult result = await runCompiler(
memorySourceFiles: sourceFiles,
entryPoint: entryPoint,
- options: [Flags.analyzeAll]);
+ options: [Flags.analyzeAll, Flags.genericMethodSyntax]);
Compiler compiler = result.compiler;
testSerialization(
compiler.libraryLoader.libraries,
@@ -277,6 +302,9 @@
void visit(Element element1, Element element2) {
if (element1 == null && element2 == null) return;
+ if (element1 == null || element2 == null) {
+ throw currentCheck;
+ }
element1 = element1.declaration;
element2 = element2.declaration;
if (element1 == element2) return;
@@ -333,22 +361,35 @@
LibrarySerializer.getCompilationUnits(element1),
LibrarySerializer.getCompilationUnits(element2));
- checkElementListIdentities(
+ checkElementLists(
element1, element2, 'imports',
LibrarySerializer.getImports(element1),
LibrarySerializer.getImports(element2));
- checkElementListIdentities(
+ checkElementLists(
element1, element2, 'exports', element1.exports, element2.exports);
+ List<Element> imported1 = LibrarySerializer.getImportedElements(element1);
+ List<Element> imported2 = LibrarySerializer.getImportedElements(element2);
checkElementListIdentities(
- element1, element2, 'importScope',
- LibrarySerializer.getImportedElements(element1),
- LibrarySerializer.getImportedElements(element2));
+ element1, element2, 'importScope', imported1, imported2);
checkElementListIdentities(
element1, element2, 'exportScope',
LibrarySerializer.getExportedElements(element1),
LibrarySerializer.getExportedElements(element2));
+
+ for (int index = 0; index < imported1.length; index++) {
+ checkImportsFor(element1, element2, imported1[index], imported2[index]);
+ }
+ }
+
+ void checkImportsFor(Element element1, Element element2,
+ Element import1, Element import2) {
+ List<ImportElement> imports1 = element1.library.getImportsFor(import1);
+ List<ImportElement> imports2 = element2.library.getImportsFor(import2);
+ checkElementListIdentities(
+ element1, element2, 'importsFor($import1/$import2)',
+ imports1, imports2);
}
@override
@@ -639,6 +680,8 @@
element1, element2, 'functionSignature.orderedOptionalParameters',
element1.functionSignature.orderedOptionalParameters,
element2.functionSignature.orderedOptionalParameters);
+ checkTypeLists(element1, element2, 'typeVariables',
+ element1.typeVariables, element2.typeVariables);
}
@override
@@ -678,6 +721,17 @@
element1.isRedirectingFactory, element2.isRedirectingFactory);
checkElementIdentities(element1, element2, 'effectiveTarget',
element1.effectiveTarget, element2.effectiveTarget);
+ if (element1.isRedirectingFactory) {
+ checkElementIdentities(element1, element2, 'immediateRedirectionTarget',
+ element1.immediateRedirectionTarget,
+ element2.immediateRedirectionTarget);
+ checkElementIdentities(element1, element2, 'redirectionDeferredPrefix',
+ element1.redirectionDeferredPrefix,
+ element2.redirectionDeferredPrefix);
+ check(element1, element2, 'isEffectiveTargetMalformed',
+ element1.isEffectiveTargetMalformed,
+ element2.isEffectiveTargetMalformed);
+ }
checkElementIdentities(element1, element2, 'definingConstructor',
element1.definingConstructor, element2.definingConstructor);
check(
@@ -817,6 +871,19 @@
checkElementProperties(element1, element2,
'loadLibrary', element1.loadLibrary, element2.loadLibrary);
}
- // TODO(johnniwinther): Check members.
+ element1.forEachLocalMember((Element member1) {
+ String name = member1.name;
+ Element member2 = element2.lookupLocalMember(name);
+ checkElementIdentities(element1, element2, 'lookupLocalMember:$name',
+ member1, member2);
+ checkImportsFor(element1, element2, member1, member2);
+ });
+ }
+
+ @override
+ void visitErroneousElement(
+ ErroneousElement element1, ErroneousElement element2) {
+ check(element1, element2, 'messageKind',
+ element1.messageKind, element2.messageKind);
}
}
diff --git a/tests/compiler/dart2js/serialization/helper.dart b/tests/compiler/dart2js/serialization/helper.dart
index e5fab48..44d3786 100644
--- a/tests/compiler/dart2js/serialization/helper.dart
+++ b/tests/compiler/dart2js/serialization/helper.dart
@@ -77,9 +77,9 @@
TestFunction testFunction) async {
Uri entryPoint = Uri.parse('memory:main.dart');
int first = start ?? 0;
- int last = end ?? tests.length - 1;
+ int last = end ?? tests.length;
- for (int index = first; index <= last; index++) {
+ for (int index = first; index < last; index++) {
Test test = TESTS[index];
List<SerializedData> dataList =
await preserializeData(serializedData, test);
@@ -115,28 +115,28 @@
bool verbose});
Future<SerializedData> serializeDartCore(
- {Arguments arguments: const Arguments()}) async {
- Uri uri = Uri.parse('memory:${arguments.serializedDataFileName}');
- print('------------------------------------------------------------------');
- print('serialize dart:core');
- print('------------------------------------------------------------------');
- SerializedData serializedData;
- if (arguments.loadSerializedData) {
- File file = new File(arguments.serializedDataFileName);
- if (file.existsSync()) {
- print('Loading data from $file');
- serializedData = new SerializedData(uri, file.readAsStringSync());
+ {Arguments arguments: const Arguments()}) {
+ return measure('dart:core', 'serialize', () async {
+ Uri uri = Uri.parse('memory:${arguments.serializedDataFileName}');
+ SerializedData serializedData;
+ if (arguments.loadSerializedData) {
+ File file = new File(arguments.serializedDataFileName);
+ if (file.existsSync()) {
+ print('Loading data from $file');
+ serializedData = new SerializedData(uri, file.readAsStringSync());
+ }
+ } else {
+ SerializationResult result =
+ await serialize(Uris.dart_core, dataUri: uri);
+ serializedData = result.serializedData;
}
- } else {
- SerializationResult result = await serialize(Uris.dart_core, dataUri: uri);
- serializedData = result.serializedData;
- }
- if (arguments.saveSerializedData) {
- File file = new File(arguments.serializedDataFileName);
- print('Saving data to $file');
- file.writeAsStringSync(serializedData.data);
- }
- return serializedData;
+ if (arguments.saveSerializedData) {
+ File file = new File(arguments.serializedDataFileName);
+ print('Saving data to $file');
+ file.writeAsStringSync(serializedData.data);
+ }
+ return serializedData;
+ });
}
class SerializationResult {
@@ -153,16 +153,15 @@
if (dataUri == null) {
dataUri = Uri.parse('memory:${DEFAULT_DATA_FILE_NAME}');
}
+ OutputCollector outputCollector = new OutputCollector();
Compiler compiler = compilerFor(
- options: [Flags.analyzeAll],
+ options: [Flags.resolveOnly],
memorySourceFiles: memorySourceFiles,
- resolutionInputs: resolutionInputs);
- compiler.serialization.supportSerialization = true;
+ resolutionInputs: resolutionInputs,
+ outputProvider: outputCollector);
await compiler.run(entryPoint);
- BufferedEventSink sink = new BufferedEventSink();
- compiler.serialization.serializeToSink(
- sink, compiler.libraryLoader.libraries);
- SerializedData serializedData = new SerializedData(dataUri, sink.text);
+ SerializedData serializedData = new SerializedData(
+ dataUri, outputCollector.getOutput('', 'data'));
return new SerializationResult(compiler, serializedData);
}
@@ -170,7 +169,10 @@
final Uri uri;
final String data;
- SerializedData(this.uri, this.data);
+ SerializedData(this.uri, this.data) {
+ assert(uri != null);
+ assert(data != null);
+ }
Map<String, String> toMemorySourceFiles([Map<String, String> input]) {
Map<String, String> sourceFiles = <String, String>{};
@@ -201,13 +203,6 @@
}
}
-String extractSerializedData(
- Compiler compiler, Iterable<LibraryElement> libraries) {
- BufferedEventSink sink = new BufferedEventSink();
- compiler.serialization.serializeToSink(sink, libraries);
- return sink.text;
-}
-
Future<List<SerializedData>> preserializeData(
SerializedData serializedData, Test test) async {
if (test == null ||
@@ -224,19 +219,76 @@
if (test.unserializedSourceFiles != null) {
sourceFiles.addAll(test.unserializedSourceFiles);
}
+ OutputCollector outputCollector = new OutputCollector();
Compiler compiler = compilerFor(
memorySourceFiles: sourceFiles,
resolutionInputs: serializedData.toUris(),
- options: [Flags.analyzeOnly, Flags.analyzeMain]);
+ options: [Flags.resolveOnly],
+ outputProvider: outputCollector);
compiler.librariesToAnalyzeWhenRun = uriList;
- compiler.serialization.supportSerialization = true;
await compiler.run(null);
List<LibraryElement> libraries = <LibraryElement>[];
for (Uri uri in uriList) {
libraries.add(compiler.libraryLoader.lookupLibrary(uri));
}
- SerializedData additionalSerializedData =
- new SerializedData(Uri.parse('memory:additional.data'),
- extractSerializedData(compiler, libraries));
+ SerializedData additionalSerializedData = new SerializedData(
+ Uri.parse('memory:additional.data'),
+ outputCollector.getOutput('', 'data'));
return <SerializedData>[serializedData, additionalSerializedData];
}
+
+class MeasurementResult {
+ final String title;
+ final String taskTitle;
+ final int elapsedMilliseconds;
+
+ MeasurementResult(this.title, this.taskTitle, this.elapsedMilliseconds);
+}
+
+final List<MeasurementResult> measurementResults = <MeasurementResult>[];
+
+/// Print all store [measurementResults] grouped by title and sorted by
+/// decreasing execution time.
+void printMeasurementResults() {
+ Map<String, int> totals = <String, int>{};
+
+ for (MeasurementResult result in measurementResults) {
+ totals.putIfAbsent(result.title, () => 0);
+ totals[result.title] += result.elapsedMilliseconds;
+ }
+
+ List<String> sorted = totals.keys.toList();
+ sorted.sort((a, b) => -totals[a].compareTo(totals[b]));
+
+ int paddingLength = '${totals[sorted.first]}'.length;
+
+ String pad(int value) {
+ String text = '$value';
+ return '${' ' * (paddingLength - text.length)}$text';
+ }
+
+ print('================================================================');
+ print('Summary:');
+ for (String task in sorted) {
+ int time = totals[task];
+ print('${pad(time)}ms $task');
+ }
+
+ measurementResults.clear();
+}
+
+/// Measure execution of [task], print the result and store it in
+/// [measurementResults] for a summary.
+Future measure(String title, String taskTitle, Future task()) async {
+ Stopwatch stopwatch = new Stopwatch()..start();
+ print('================================================================');
+ print('$taskTitle: $title');
+ print('----------------------------------------------------------------');
+ var result = await task();
+ stopwatch.stop();
+ int elapsedMilliseconds = stopwatch.elapsedMilliseconds;
+ print('$taskTitle: $title: ${elapsedMilliseconds}ms');
+ measurementResults.add(
+ new MeasurementResult(title, taskTitle, elapsedMilliseconds));
+ return result;
+}
\ No newline at end of file
diff --git a/tests/compiler/dart2js/serialization/model0_test.dart b/tests/compiler/dart2js/serialization/model0_test.dart
new file mode 100644
index 0000000..c4ef537
--- /dev/null
+++ b/tests/compiler/dart2js/serialization/model0_test.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart2js.serialization.model0_test;
+
+import 'model_test_helper.dart' as test;
+import 'test_helper.dart';
+
+main() {
+ test.main(testSkipped(0, test.SKIP_COUNT));
+}
diff --git a/tests/compiler/dart2js/serialization/model1_test.dart b/tests/compiler/dart2js/serialization/model1_test.dart
index 9582274..aec8489 100644
--- a/tests/compiler/dart2js/serialization/model1_test.dart
+++ b/tests/compiler/dart2js/serialization/model1_test.dart
@@ -5,8 +5,8 @@
library dart2js.serialization.model1_test;
import 'model_test_helper.dart' as test;
-import 'test_data.dart';
+import 'test_helper.dart';
main() {
- test.main(['0', '${TESTS.length ~/ 2}']);
+ test.main(testSegment(1, test.SPLIT_COUNT, test.SKIP_COUNT));
}
diff --git a/tests/compiler/dart2js/serialization/model2_test.dart b/tests/compiler/dart2js/serialization/model2_test.dart
index 369e4a1..8f02334 100644
--- a/tests/compiler/dart2js/serialization/model2_test.dart
+++ b/tests/compiler/dart2js/serialization/model2_test.dart
@@ -5,8 +5,8 @@
library dart2js.serialization.model2_test;
import 'model_test_helper.dart' as test;
-import 'test_data.dart';
+import 'test_helper.dart';
main() {
- test.main(['${TESTS.length ~/ 2}']);
+ test.main(testSegment(2, test.SPLIT_COUNT, test.SKIP_COUNT));
}
diff --git a/tests/compiler/dart2js/serialization/model3_test.dart b/tests/compiler/dart2js/serialization/model3_test.dart
new file mode 100644
index 0000000..d3a2ff1
--- /dev/null
+++ b/tests/compiler/dart2js/serialization/model3_test.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart2js.serialization.model3_test;
+
+import 'model_test_helper.dart' as test;
+import 'test_helper.dart';
+
+main() {
+ test.main(testSegment(3, test.SPLIT_COUNT, test.SKIP_COUNT));
+}
diff --git a/tests/compiler/dart2js/serialization/model4_test.dart b/tests/compiler/dart2js/serialization/model4_test.dart
new file mode 100644
index 0000000..5871fc2
--- /dev/null
+++ b/tests/compiler/dart2js/serialization/model4_test.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart2js.serialization.model4_test;
+
+import 'model_test_helper.dart' as test;
+import 'test_helper.dart';
+
+main() {
+ test.main(testSegment(4, test.SPLIT_COUNT, test.SKIP_COUNT));
+}
diff --git a/tests/compiler/dart2js/serialization/model_1_test.dart b/tests/compiler/dart2js/serialization/model_1_test.dart
new file mode 100644
index 0000000..e74bd17
--- /dev/null
+++ b/tests/compiler/dart2js/serialization/model_1_test.dart
@@ -0,0 +1,12 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library dart2js.serialization.model_1_test;
+
+import 'model_test_helper.dart' as test;
+import 'test_helper.dart';
+
+main() {
+ test.main(testSkipped(1, test.SKIP_COUNT));
+}
diff --git a/tests/compiler/dart2js/serialization/model_test_helper.dart b/tests/compiler/dart2js/serialization/model_test_helper.dart
index 2c6d861..daf68663 100644
--- a/tests/compiler/dart2js/serialization/model_test_helper.dart
+++ b/tests/compiler/dart2js/serialization/model_test_helper.dart
@@ -10,7 +10,9 @@
import 'package:expect/expect.dart';
import 'package:compiler/src/closure.dart';
import 'package:compiler/src/commandline_options.dart';
+import 'package:compiler/src/common.dart';
import 'package:compiler/src/compiler.dart';
+import 'package:compiler/src/deferred_load.dart';
import 'package:compiler/src/elements/elements.dart';
import 'package:compiler/src/filenames.dart';
import 'package:compiler/src/js_backend/js_backend.dart';
@@ -22,6 +24,12 @@
import 'test_data.dart';
import 'test_helper.dart';
+/// Number of tests that are not part of the automatic test grouping.
+int SKIP_COUNT = 2;
+
+/// Number of groups that the [TESTS] are split into.
+int SPLIT_COUNT = 4;
+
main(List<String> args) {
asyncTest(() async {
Arguments arguments = new Arguments.from(args);
@@ -29,13 +37,24 @@
await serializeDartCore(arguments: arguments);
if (arguments.filename != null) {
Uri entryPoint = Uri.base.resolve(nativeToUriPath(arguments.filename));
+ SerializationResult result = await measure(
+ '${entryPoint}', 'serialize', () {
+ return serialize(
+ entryPoint,
+ memorySourceFiles: serializedData.toMemorySourceFiles(),
+ resolutionInputs: serializedData.toUris(),
+ dataUri: Uri.parse('memory:test.data'));
+ });
await checkModels(entryPoint,
- sourceFiles: serializedData.toMemorySourceFiles(),
- resolutionInputs: serializedData.toUris());
+ sourceFiles: serializedData.toMemorySourceFiles(
+ result.serializedData.toMemorySourceFiles()),
+ resolutionInputs: serializedData.toUris(
+ result.serializedData.toUris()));
} else {
Uri entryPoint = Uri.parse('memory:main.dart');
await arguments.forEachTest(serializedData, TESTS, checkModels);
}
+ printMeasurementResults();
});
}
@@ -48,88 +67,101 @@
bool verbose: false}) async {
String testDescription = test != null ? test.name : '${entryPoint}';
String id = index != null ? '$index: ' : '';
- print('------------------------------------------------------------------');
- print('compile normal ${id}${testDescription}');
- print('------------------------------------------------------------------');
- Compiler compilerNormal = compilerFor(
- memorySourceFiles: sourceFiles,
- options: [Flags.analyzeOnly]);
- compilerNormal.resolution.retainCachesForTesting = true;
- await compilerNormal.run(entryPoint);
- compilerNormal.phase = Compiler.PHASE_DONE_RESOLVING;
- compilerNormal.world.populate();
- compilerNormal.backend.onResolutionComplete();
+ String title = '${id}${testDescription}';
+ Compiler compilerNormal = await measure(
+ title, 'compile normal', () async {
+ Compiler compilerNormal = compilerFor(
+ memorySourceFiles: sourceFiles,
+ options: [Flags.analyzeOnly]);
+ compilerNormal.resolution.retainCachesForTesting = true;
+ await compilerNormal.run(entryPoint);
+ compilerNormal.phase = Compiler.PHASE_DONE_RESOLVING;
+ compilerNormal.world.populate();
+ compilerNormal.backend.onResolutionComplete();
+ compilerNormal.deferredLoadTask.onResolutionComplete(
+ compilerNormal.mainFunction);
+ return compilerNormal;
+ });
- print('------------------------------------------------------------------');
- print('compile deserialized ${id}${testDescription}');
- print('------------------------------------------------------------------');
- Compiler compilerDeserialized = compilerFor(
- memorySourceFiles: sourceFiles,
- resolutionInputs: resolutionInputs,
- options: [Flags.analyzeOnly]);
- compilerDeserialized.resolution.retainCachesForTesting = true;
- await compilerDeserialized.run(entryPoint);
- compilerDeserialized.phase = Compiler.PHASE_DONE_RESOLVING;
- compilerDeserialized.world.populate();
- compilerDeserialized.backend.onResolutionComplete();
+ Compiler compilerDeserialized = await measure(
+ title, 'compile deserialized', () async {
+ Compiler compilerDeserialized = compilerFor(
+ memorySourceFiles: sourceFiles,
+ resolutionInputs: resolutionInputs,
+ options: [Flags.analyzeOnly]);
+ compilerDeserialized.resolution.retainCachesForTesting = true;
+ await compilerDeserialized.run(entryPoint);
+ compilerDeserialized.phase = Compiler.PHASE_DONE_RESOLVING;
+ compilerDeserialized.world.populate();
+ compilerDeserialized.backend.onResolutionComplete();
+ compilerDeserialized.deferredLoadTask.onResolutionComplete(
+ compilerDeserialized.mainFunction);
+ return compilerDeserialized;
+ });
- checkAllImpacts(
- compilerNormal, compilerDeserialized,
- verbose: verbose);
+ return measure(title, 'check models', () async {
+ checkAllImpacts(
+ compilerNormal, compilerDeserialized,
+ verbose: verbose);
- checkSets(
- compilerNormal.resolverWorld.directlyInstantiatedClasses,
- compilerDeserialized.resolverWorld.directlyInstantiatedClasses,
- "Directly instantiated classes mismatch",
- areElementsEquivalent,
- verbose: verbose);
+ checkSets(
+ compilerNormal.resolverWorld.directlyInstantiatedClasses,
+ compilerDeserialized.resolverWorld.directlyInstantiatedClasses,
+ "Directly instantiated classes mismatch",
+ areElementsEquivalent,
+ verbose: verbose);
- checkSets(
- compilerNormal.resolverWorld.instantiatedTypes,
- compilerDeserialized.resolverWorld.instantiatedTypes,
- "Instantiated types mismatch",
- areTypesEquivalent,
- verbose: verbose);
+ checkSets(
+ compilerNormal.resolverWorld.instantiatedTypes,
+ compilerDeserialized.resolverWorld.instantiatedTypes,
+ "Instantiated types mismatch",
+ areTypesEquivalent,
+ verbose: verbose);
- checkSets(
- compilerNormal.resolverWorld.isChecks,
- compilerDeserialized.resolverWorld.isChecks,
- "Is-check mismatch",
- areTypesEquivalent,
- verbose: verbose);
+ checkSets(
+ compilerNormal.resolverWorld.isChecks,
+ compilerDeserialized.resolverWorld.isChecks,
+ "Is-check mismatch",
+ areTypesEquivalent,
+ verbose: verbose);
- checkSets(
- compilerNormal.enqueuer.resolution.processedElements,
- compilerDeserialized.enqueuer.resolution.processedElements,
- "Processed element mismatch",
- areElementsEquivalent,
- onSameElement: (a, b) {
- checkElements(
- compilerNormal, compilerDeserialized, a, b, verbose: verbose);
- },
- verbose: verbose);
+ checkSets(
+ compilerNormal.enqueuer.resolution.processedElements,
+ compilerDeserialized.enqueuer.resolution.processedElements,
+ "Processed element mismatch",
+ areElementsEquivalent,
+ onSameElement: (a, b) {
+ checkElements(
+ compilerNormal, compilerDeserialized, a, b, verbose: verbose);
+ },
+ verbose: verbose);
- checkClassHierarchyNodes(
- compilerNormal,
- compilerDeserialized,
- compilerNormal.world.getClassHierarchyNode(
- compilerNormal.coreClasses.objectClass),
- compilerDeserialized.world.getClassHierarchyNode(
- compilerDeserialized.coreClasses.objectClass),
- verbose: verbose);
+ checkClassHierarchyNodes(
+ compilerNormal,
+ compilerDeserialized,
+ compilerNormal.world.getClassHierarchyNode(
+ compilerNormal.coreClasses.objectClass),
+ compilerDeserialized.world.getClassHierarchyNode(
+ compilerDeserialized.coreClasses.objectClass),
+ verbose: verbose);
- Expect.equals(compilerNormal.enabledInvokeOn,
- compilerDeserialized.enabledInvokeOn,
- "Compiler.enabledInvokeOn mismatch");
- Expect.equals(compilerNormal.enabledFunctionApply,
- compilerDeserialized.enabledFunctionApply,
- "Compiler.enabledFunctionApply mismatch");
- Expect.equals(compilerNormal.enabledRuntimeType,
- compilerDeserialized.enabledRuntimeType,
- "Compiler.enabledRuntimeType mismatch");
- Expect.equals(compilerNormal.hasIsolateSupport,
- compilerDeserialized.hasIsolateSupport,
- "Compiler.hasIsolateSupport mismatch");
+ Expect.equals(compilerNormal.enabledInvokeOn,
+ compilerDeserialized.enabledInvokeOn,
+ "Compiler.enabledInvokeOn mismatch");
+ Expect.equals(compilerNormal.enabledFunctionApply,
+ compilerDeserialized.enabledFunctionApply,
+ "Compiler.enabledFunctionApply mismatch");
+ Expect.equals(compilerNormal.enabledRuntimeType,
+ compilerDeserialized.enabledRuntimeType,
+ "Compiler.enabledRuntimeType mismatch");
+ Expect.equals(compilerNormal.hasIsolateSupport,
+ compilerDeserialized.hasIsolateSupport,
+ "Compiler.hasIsolateSupport mismatch");
+ Expect.equals(
+ compilerNormal.deferredLoadTask.isProgramSplit,
+ compilerDeserialized.deferredLoadTask.isProgramSplit,
+ "isProgramSplit mismatch");
+ });
}
void checkElements(
@@ -182,6 +214,28 @@
"$element1.variablesUsedInTryOrGenerator",
areLocalsEquivalent,
verbose: verbose);
+ if (element1 is MemberElement && element2 is MemberElement) {
+ MemberElement member1 = element1.implementation;
+ MemberElement member2 = element2.implementation;
+ checkSets(
+ member1.nestedClosures,
+ member2.nestedClosures,
+ "$member1.nestedClosures",
+ areElementsEquivalent,
+ verbose: verbose,
+ onSameElement: (a, b) {
+ LocalFunctionElement localFunction1 = a.expression;
+ LocalFunctionElement localFunction2 = b.expression;
+ checkElementIdentities(
+ localFunction1, localFunction2,
+ 'enclosingClass',
+ localFunction1.enclosingClass, localFunction2.enclosingClass);
+ testResolvedAstEquivalence(
+ localFunction1.resolvedAst,
+ localFunction2.resolvedAst,
+ const CheckStrategy());
+ });
+ }
}
JavaScriptBackend backend1 = compiler1.backend;
JavaScriptBackend backend2 = compiler2.backend;
@@ -189,6 +243,8 @@
backend1.inlineCache.getCurrentCacheDecisionForTesting(element1),
backend2.inlineCache.getCurrentCacheDecisionForTesting(element2),
"Inline cache decision mismatch for $element1 vs $element2");
+
+ checkOutputUnits(compiler1, compiler2, element1, element2);
}
void checkMixinUses(
@@ -302,4 +358,19 @@
return '(${node.runtimeType}) ${text.substring(0, 37)}...';
}
return '(${node.runtimeType}) $text';
+}
+
+void checkOutputUnits(Compiler compiler1, Compiler compiler2, Element element1,
+ Element element2) {
+ OutputUnit outputUnit1 =
+ compiler1.deferredLoadTask.outputUnitForElement(element1);
+ OutputUnit outputUnit2 =
+ compiler2.deferredLoadTask.outputUnitForElement(element2);
+ check(outputUnit1, outputUnit2,
+ 'OutputUnit.isMainOutput for $element1 vs $element2',
+ outputUnit1.isMainOutput, outputUnit2.isMainOutput);
+ checkSetEquivalence(outputUnit1, outputUnit2,
+ 'OutputUnit.imports for $element1 vs $element2',
+ outputUnit1.imports, outputUnit2.imports,
+ (a, b) => areElementsEquivalent(a.declaration, b.declaration));
}
\ No newline at end of file
diff --git a/tests/compiler/dart2js/serialization/test_data.dart b/tests/compiler/dart2js/serialization/test_data.dart
index 83cf2da..568b453 100644
--- a/tests/compiler/dart2js/serialization/test_data.dart
+++ b/tests/compiler/dart2js/serialization/test_data.dart
@@ -5,8 +5,8 @@
library dart2js.serialization_test_data;
const List<Test> TESTS = const <Test>[
- // This test is very long-running and put here first to compile it on its own
- // in compilation0_test.dart
+ // These tests are very long-running and put here first to compile them on
+ // their own tests.
const Test('Disable tree shaking through reflection', const {
'main.dart': '''
import 'dart:mirrors';
@@ -17,6 +17,19 @@
''',
}, expectedWarningCount: 1),
+ const Test('Use of dart:indexed_db', const {
+ 'main.dart': '''
+import 'a.dart';
+
+main() {}
+''',
+ }, preserializedSourceFiles: const {
+ 'a.dart': '''
+import 'dart:indexed_db';
+''',
+ }),
+
+ // These tests
const Test('Empty program', const {
'main.dart': 'main() {}'
}),
@@ -122,7 +135,7 @@
},
expectedWarningCount: 1),
- const Test('Impliment Comparable with incompatible parameter types', const {
+ const Test('Implement Comparable with incompatible parameter types', const {
'main.dart': r'''
class Class implements Comparable<Class> {
int compareTo(String other) => 0;
@@ -134,7 +147,7 @@
expectedWarningCount: 1,
expectedInfoCount: 1),
- const Test('Impliment Comparable with incompatible parameter count', const {
+ const Test('Implement Comparable with incompatible parameter count', const {
'main.dart': r'''
class Class implements Comparable {
bool compareTo(a, b) => true;
@@ -457,6 +470,18 @@
''',
}),
+ const Test('Index set if null', const {
+ 'main.dart': '''
+import 'a.dart';
+
+main() => m(null, null, null);
+''',
+ }, preserializedSourceFiles: const {
+ 'a.dart': '''
+m(a, b, c) => a[b] ??= c;
+''',
+ }),
+
const Test('If-null expression in constant constructor', const {
'main.dart': '''
import 'a.dart';
@@ -546,6 +571,79 @@
'c.dart': '''
''',
}, expectedErrorCount: 1),
+
+ const Test('Closure in operator function', const {
+ 'main.dart': '''
+import 'a.dart';
+
+main() {
+ test();
+}
+''',
+ }, preserializedSourceFiles: const {
+ 'a.dart': '''
+class C {
+ operator ==(other) => () {};
+}
+
+test() => new C() == null;
+''',
+ }),
+
+ const Test('Checked setter', const {
+ 'main.dart': '''
+import 'a.dart';
+
+main() {
+ test();
+}
+''',
+ }, preserializedSourceFiles: const {
+ 'a.dart': '''
+class C {
+ set foo(int i) {}
+}
+
+test() => new C().foo = 0;
+''',
+ }, checkedMode: true),
+
+ const Test('Deferred access', const {
+ 'main.dart': '''
+import 'a.dart';
+
+main() {
+ test();
+}
+''',
+ }, preserializedSourceFiles: const {
+ 'a.dart': '''
+import 'b.dart' deferred as b;
+
+test() => b.loadLibrary().then((_) => b.test2());
+''',
+ 'b.dart': '''
+test2() {}
+''',
+ }),
+
+ const Test('Deferred access of dart:core', const {
+ 'main.dart': '''
+import 'a.dart';
+
+main() {
+ test();
+}
+''',
+ }, preserializedSourceFiles: const {
+ 'a.dart': '''
+import "dart:core" deferred as core;
+
+test() {
+ core.loadLibrary().then((_) => null);
+}
+''',
+ }),
];
class Test {
@@ -557,6 +655,7 @@
final int expectedWarningCount;
final int expectedHintCount;
final int expectedInfoCount;
+ final bool checkedMode;
const Test(
this.name,
@@ -566,5 +665,6 @@
this.expectedErrorCount: 0,
this.expectedWarningCount: 0,
this.expectedHintCount: 0,
- this.expectedInfoCount: 0});
+ this.expectedInfoCount: 0,
+ this.checkedMode: false});
}
diff --git a/tests/compiler/dart2js/serialization/test_helper.dart b/tests/compiler/dart2js/serialization/test_helper.dart
index 9d3115f..2c74a07 100644
--- a/tests/compiler/dart2js/serialization/test_helper.dart
+++ b/tests/compiler/dart2js/serialization/test_helper.dart
@@ -13,6 +13,7 @@
import 'package:compiler/src/serialization/equivalence.dart';
import 'package:compiler/src/tree/nodes.dart';
import 'package:expect/expect.dart';
+import 'test_data.dart';
Check currentCheck;
@@ -589,3 +590,33 @@
testResolvedAstEquivalence(
resolvedAst1, resolvedAst2, const CheckStrategy());
}
+
+/// Returns the test arguments for testing the [index]th skipped test. The
+/// [skip] count is used to check that [index] is a valid index.
+List<String> testSkipped(int index, int skip) {
+ if (index < 0 || index >= skip) {
+ throw new ArgumentError('Invalid skip index $index');
+ }
+ return ['${index}', '${index + 1}'];
+}
+
+/// Return the test arguments for testing the [index]th segment (1-based) of
+/// the [TESTS] split into [count] groups. The first [skip] tests are excluded
+/// from the automatic grouping.
+List<String> testSegment(int index, int count, int skip) {
+ if (index < 0 || index > count) {
+ throw new ArgumentError('Invalid segment index $index');
+ }
+
+ String segmentNumber(int i) {
+ return '${skip + i * (TESTS.length - skip) ~/ count}';
+ }
+
+ if (index == 1 && skip != 0) {
+ return ['${skip}', segmentNumber(index)];
+ } else if (index == count) {
+ return [segmentNumber(index - 1)];
+ } else {
+ return [segmentNumber(index - 1), segmentNumber(index)];
+ }
+}
diff --git a/tests/compiler/dart2js_extra/invalid_annotation2_test.dart b/tests/compiler/dart2js_extra/invalid_annotation2_test.dart
index d8dafd5..5b1f41a 100644
--- a/tests/compiler/dart2js_extra/invalid_annotation2_test.dart
+++ b/tests/compiler/dart2js_extra/invalid_annotation2_test.dart
@@ -14,7 +14,7 @@
import 'dart:mirrors';
@Deprecated("m"
-, /// 01: compile-time error
+,, /// 01: compile-time error
)
class A {
}
diff --git a/tests/compiler/dart2js_extra/invalid_annotation_test.dart b/tests/compiler/dart2js_extra/invalid_annotation_test.dart
index 5e0285a8..50e8e6f 100644
--- a/tests/compiler/dart2js_extra/invalid_annotation_test.dart
+++ b/tests/compiler/dart2js_extra/invalid_annotation_test.dart
@@ -8,7 +8,7 @@
// annotation had a syntax error.
@Deprecated("m"
-, /// 01: compile-time error
+,, /// 01: compile-time error
)
class A {}
diff --git a/tests/compiler/dart2js_extra/truncation_errors_test.dart b/tests/compiler/dart2js_extra/truncation_errors_test.dart
new file mode 100644
index 0000000..1e3767c
--- /dev/null
+++ b/tests/compiler/dart2js_extra/truncation_errors_test.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.
+
+// Check that exception messages for truncating operations contains the
+// operands.
+
+import 'package:expect/expect.dart';
+
+@NoInline() @AssumeDynamic()
+confuse(x) => x;
+
+void find1(expected, thunk) {
+ if (thunk == null) return;
+ var returned, exceptionText;
+ try {
+ returned = thunk();
+ } catch (e) {
+ exceptionText = '$e';
+ }
+ if (exceptionText == null) {
+ Expect.fail(
+ 'Expected exception containing "$expected", returned: $returned');
+ }
+ Expect.isTrue(
+ exceptionText.contains(expected),
+ 'Expected "$expected" in "$exceptionText"');
+}
+
+void find(expected, [thunk1, thunk2, thunk3, thunk4]) {
+ find1(expected, thunk1);
+ find1(expected, thunk2);
+ find1(expected, thunk3);
+ find1(expected, thunk4);
+}
+
+main() {
+
+ var NaN = double.NAN;
+ var Infinity = double.INFINITY;
+
+ find(' Infinity: 123 ~/ 0',
+ () => confuse(123) ~/ confuse(0),
+ () => confuse(123) ~/ 0,
+ () => 123 ~/ confuse(0),
+ () => 123 ~/ 0);
+
+ find('-Infinity: 123 ~/ -0.0',
+ () => confuse(123) ~/ confuse(-0.0),
+ () => confuse(123) ~/ -0.0,
+ () => 123 ~/ confuse(-0.0),
+ () => 123 ~/ -0.0);
+
+ find(' NaN: NaN ~/ 123',
+ () => confuse(NaN) ~/ confuse(123),
+ () => confuse(NaN) ~/ 123,
+ () => NaN ~/ confuse(123),
+ () => NaN ~/ 123);
+
+ find(' Infinity: 1e+200 ~/ 1e-200',
+ () => confuse(1e200) ~/ confuse(1e-200),
+ () => confuse(1e200) ~/ 1e-200,
+ () => 1e200 ~/ confuse(1e-200),
+ () => 1e200 ~/ 1e-200);
+
+ find('NaN.toInt()',
+ () => confuse(NaN).toInt(),
+ () => NaN.toInt());
+ find(' Infinity.toInt()',
+ () => confuse(Infinity).toInt(),
+ () => Infinity.toInt());
+ find('-Infinity.toInt()',
+ () => confuse(-Infinity).toInt(),
+ () => (-Infinity).toInt());
+
+ find('NaN.ceil()',
+ () => confuse(NaN).ceil(),
+ () => NaN.ceil());
+ find(' Infinity.ceil()',
+ () => confuse(Infinity).ceil(),
+ () => Infinity.ceil());
+ find('-Infinity.ceil()',
+ () => confuse(-Infinity).ceil(),
+ () => (-Infinity).ceil());
+
+ find('NaN.floor()',
+ () => confuse(NaN).floor(),
+ () => NaN.floor());
+ find(' Infinity.floor()',
+ () => confuse(Infinity).floor(),
+ () => Infinity.floor());
+ find('-Infinity.floor()',
+ () => confuse(-Infinity).floor(),
+ () => (-Infinity).floor());
+
+ find('NaN.round()',
+ () => confuse(NaN).round(),
+ () => NaN.round());
+ find(' Infinity.round()',
+ () => confuse(Infinity).round(),
+ () => Infinity.round());
+ find('-Infinity.round()',
+ () => confuse(-Infinity).round(),
+ () => (-Infinity).round());
+
+ // `truncate()` is the same as `toInt()`.
+ // We could change the runtime so that `truncate` is reported.
+ find('NaN.toInt()',
+ () => confuse(NaN).truncate(),
+ () => NaN.truncate());
+ find(' Infinity.toInt()',
+ () => confuse(Infinity).truncate(),
+ () => Infinity.truncate());
+ find('-Infinity.toInt()',
+ () => confuse(-Infinity).truncate(),
+ () => (-Infinity).truncate());
+
+}
+
diff --git a/tests/compiler/dart2js_native/call_on_native_class_test.dart b/tests/compiler/dart2js_native/call_on_native_class_test.dart
deleted file mode 100644
index 5142982..0000000
--- a/tests/compiler/dart2js_native/call_on_native_class_test.dart
+++ /dev/null
@@ -1,17 +0,0 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:_js_helper';
-
-@Native('*A')
-class A {
-}
-
-class B extends A {
- call() => 42;
-}
-
-main() {
- new B()();
-}
diff --git a/tests/compiler/dart2js_native/dart2js_native.status b/tests/compiler/dart2js_native/dart2js_native.status
index 28abf25..cae6550 100644
--- a/tests/compiler/dart2js_native/dart2js_native.status
+++ b/tests/compiler/dart2js_native/dart2js_native.status
@@ -6,7 +6,6 @@
*: Skip
[ $compiler == dart2js ]
-call_on_native_class_test: CompileTimeError # Issue 14813
native_no_such_method_exception4_frog_test: CompileTimeError # Issue 9631
native_no_such_method_exception5_frog_test: CompileTimeError # Issue 9631
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index 53ec300..78010e9 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -41,6 +41,7 @@
symbol_reserved_word_test/10: MissingCompileTimeError # bug 11669, 19972
[ $compiler == none && ($runtime == drt || $runtime == dartium) ]
+package_resource_test: RuntimeError # Issue 26842
symbol_reserved_word_test/02: RuntimeError # bug 20191 / dartium/drt cannot detect CompileTimeErrors
symbol_reserved_word_test/05: RuntimeError # bug 20191 / dartium/drt cannot detect CompileTimeErrors
symbol_reserved_word_test/04: Fail # bug 11669, 19972 / dartium/drt cannot detect CompileTimeErrors
@@ -138,8 +139,6 @@
[ $compiler == dart2analyzer ]
int_parse_radix_bad_handler_test: fail
-list_insert_test: fail
-list_removeat_test: fail
hash_set_type_check_test: StaticWarning, OK # Tests failing type tests.
error_stack_trace_test: StaticWarning, OK # Test generates errors on purpose.
iterable_element_at_test: StaticWarning, OK # Test generates errors on purpose.
@@ -162,8 +161,8 @@
file_resource_test: Skip, OK # VM specific test, uses dart:io.
http_resource_test: Skip, OK # VM specific test, uses dart:io.
-[ $runtime != vm && $runtime != dart_precompiled && $compiler != dart2analyzer && $cps_ir == false ]
-package_resource_test: RuntimeError # Issue 23825 (not implemented yet).
+[ $compiler == dart2js && $browser == false ]
+package_resource_test: RuntimeError # Issue 26842
[ $mode == debug ]
regexp/pcre_test: Pass, Slow # Timeout. Issue 22008
@@ -173,7 +172,6 @@
big_integer_parsed_mul_div_vm_test: Pass, Slow
[ $compiler == dart2js && $cps_ir ]
-package_resource_test: Crash # Surprisingly null object in type propagation.
regexp/pcre_test: Crash # Stack Overflow in LoopHierarchy.
core_runtime_types_test: Pass, RuntimeError # Issue 25795.
@@ -184,9 +182,6 @@
regexp/pcre_test: Crash # Stack Overflow
collection_removes_test: Crash # Issue 25911
-[ $compiler == dart2js && $host_checked ]
-package_resource_test: Crash # Issue 25911
-
[ $noopt || $compiler == precompiler ]
# Stacktraces in precompilation omit inlined frames.
stacktrace_current_test: Pass, RuntimeError
@@ -209,15 +204,3 @@
[ $arch == simdbc || $arch == simdbc64 ]
regexp/stack-overflow_test: RuntimeError, OK # Smaller limit with irregex interpreter
-
-[ $hot_reload ]
-big_integer_huge_mul_vm_test: Pass, Timeout
-big_integer_parsed_mul_div_vm_test: Pass, Timeout
-collection_length_test: Fail, Crash
-hash_map2_test: Pass, Crash
-queue_test: Pass, Crash
-regexp/regexp_test: Pass, Fail, Crash
-uri_parse_test: Pass, Timeout
-uri_test: Pass, RuntimeError
-data_uri_test: Pass, RuntimeError
-int_parse_radix_test: Pass, Timeout
diff --git a/tests/corelib/double_floor_test.dart b/tests/corelib/double_floor_test.dart
index c59f411..7407561 100644
--- a/tests/corelib/double_floor_test.dart
+++ b/tests/corelib/double_floor_test.dart
@@ -79,4 +79,4 @@
Expect.isTrue((-9007199254740991.0).floor() is int);
Expect.isTrue((-9007199254740992.0).floor() is int);
Expect.isTrue((-double.MAX_FINITE).floor() is int);
-}
\ No newline at end of file
+}
diff --git a/tests/html/html.status b/tests/html/html.status
index 4d57f42..c7afa75 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -26,6 +26,9 @@
wrapping_collections_test: SkipByDesign # Testing an issue that is only relevant to Dartium
js_typed_interop_default_arg_test/default_value: MissingCompileTimeError # Issue #25759
mirrors_js_typed_interop_test: Pass, Slow
+js_type_test/dynamic-null-not-Foo: Fail # Issue 26838
+js_type_test/dynamic-String-not-Foo: Fail # Issue 26838
+js_type_test/dynamic-String-not-dynamic-Foo: Fail # Issue 26838
[ $compiler == dart2js && $checked ]
@@ -338,14 +341,29 @@
[ $compiler == dart2js && ($runtime == drt || $runtime == ff) ]
request_animation_frame_test: Skip # Async test hangs.
+[ $runtime == drt ]
+webgl_extensions_test: Skip # webgl does not work properly on DRT, which is 'headless'.
+
+[ $runtime == dartium && ($system == windows || $system == linux) ]
+webgl_extensions_test: Fail # WebGL extension tests fail on Dartium without graphics. This is dependent on our bot configuration.
+
+[ $runtime == chrome && ($system == windows || $system == linux) ]
+webgl_extensions_test: Fail # WebGL extension tests fail without graphics. This is dependent on our bot configuration.
+
[ $compiler == dart2js && $csp && ($runtime == drt || $runtime == safari || $runtime == ff || $runtime == chrome || $runtime == chromeOnAndroid) ]
# Note: these tests are all injecting scripts by design. This is not allowed under CSP.
+# TODO(sra): Change these tests to use a same-origin JavaScript script file.
event_customevent_test: SkipByDesign
js_interop_1_test: SkipByDesign
js_test: SkipByDesign
js_array_test: SkipByDesign
+js_util_test: SkipByDesign
+js_typed_interop_bind_this_test: SkipByDesign
+js_typed_interop_callable_object_test: SkipByDesign
js_typed_interop_test: SkipByDesign
js_typed_interop_default_arg_test: SkipByDesign
+js_typed_interop_type_test: SkipByDesign
+js_typed_interop_window_property_test: SkipByDesign
js_function_getter_test: SkipByDesign
js_function_getter_trust_types_test: SkipByDesign
js_dart_to_string_test: SkipByDesign
diff --git a/tests/html/js_type_test.dart b/tests/html/js_type_test.dart
new file mode 100644
index 0000000..90df68f
--- /dev/null
+++ b/tests/html/js_type_test.dart
@@ -0,0 +1,146 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library jsTest;
+
+import 'dart:html';
+
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_individual_config.dart';
+import 'package:expect/expect.dart' show NoInline, AssumeDynamic;
+
+import 'js_type_test_lib.dart';
+
+class Bar {}
+
+@NoInline() @AssumeDynamic()
+confuse(x) => x;
+
+class Is<T> {
+ const Is();
+ check(o) => o is T;
+}
+
+main() {
+ useHtmlIndividualConfiguration();
+
+ new Is<Foo>().check(new Bar()); // Bar is instantiated by this code.
+ new Is<Foo>().check([]);
+ new Is<List>().check([]);
+
+ group('static', () {
+ test('not-String', () {
+ Foo e = new Foo();
+ expect(e is String, isFalse);
+ });
+
+ test('not-int', () {
+ Foo e = new Foo();
+ expect(e is int, isFalse);
+ });
+
+ test('not-Null', () {
+ Foo e = new Foo();
+ expect(e is Null, isFalse);
+ });
+
+ test('not-Bar', () {
+ Foo e = new Foo();
+ expect(e is Bar, isFalse);
+ });
+
+ test('is-Foo', () {
+ Foo e = new Foo();
+ expect(e is Foo, isTrue);
+ });
+
+ test('String-not-Foo', () {
+ String e = 'hello';
+ expect(e is Foo, isFalse);
+ });
+ });
+
+ group('dynamic', () {
+ test('not-String', () {
+ var e = confuse(new Foo());
+ expect(e is String, isFalse);
+ });
+
+ test('not-int', () {
+ var e = confuse(new Foo());
+ expect(e is int, isFalse);
+ });
+
+ test('not-Null', () {
+ var e = confuse(new Foo());
+ expect(e is Null, isFalse);
+ });
+
+ test('not-Bar', () {
+ var e = confuse(new Foo());
+ expect(e is Bar, isFalse);
+ });
+
+ test('is-Foo', () {
+ var e = confuse(new Foo());
+ expect(e is Foo, isTrue);
+ });
+ });
+
+ group('dynamic-String-not-Foo', () {
+ test('test', () {
+ var e = confuse('hello');
+ expect(e is Foo, isFalse);
+ });
+ });
+
+ group('dynamic-null-not-Foo', () {
+ test('test', () {
+ var e = confuse(null);
+ expect(e is Foo, isFalse);
+ });
+ });
+
+ group('dynamic-type', () {
+ test('not-String', () {
+ var e = confuse(new Foo());
+ expect(const Is<String>().check(e), isFalse);
+ });
+
+ test('not-int', () {
+ var e = confuse(new Foo());
+ expect(const Is<int>().check(e), isFalse);
+ });
+
+ test('not-Null', () {
+ var e = confuse(new Foo());
+ expect(const Is<Null>().check(e), isFalse);
+ });
+
+ test('not-Bar', () {
+ var e = confuse(new Foo());
+ expect(const Is<Bar>().check(e), isFalse);
+ });
+
+ test('is-Foo', () {
+ var e = confuse(new Foo());
+ expect(const Is<Foo>().check(e), isTrue);
+ });
+ });
+
+ group('dynamic-String-not-dynamic-Foo', () {
+ test('test', () {
+ var e = confuse('hello');
+ expect(const Is<Foo>().check(e), isFalse);
+ });
+ });
+
+ group('dynamic-null-not-dynamic-Foo', () {
+ test('test', () {
+ var e = confuse(null);
+ expect(const Is<Foo>().check(e), isFalse);
+ });
+ });
+
+}
diff --git a/tests/html/js_type_test.html b/tests/html/js_type_test.html
new file mode 100644
index 0000000..69628ed
--- /dev/null
+++ b/tests/html/js_type_test.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<--
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+-->
+<html>
+<head>
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
+ <meta name="dart.unittest" content="full-stack-traces">
+ <title> js_type_test </title>
+ <style>
+ .unittest-table { font-family:monospace; border:1px; }
+ .unittest-pass { background: #6b3;}
+ .unittest-fail { background: #d55;}
+ .unittest-error { background: #a11;}
+ </style>
+</head>
+<body>
+ <h1> Running js_type_test </h1>
+ <script type="text/javascript"
+ src="/root_dart/tests/html/js_type_test_js.js"></script>
+ <script type="text/javascript"
+ src="/root_dart/tools/testing/dart/test_controller.js"></script>
+ %TEST_SCRIPTS%
+</body>
+</html>
diff --git a/tests/html/js_type_test_js.js b/tests/html/js_type_test_js.js
new file mode 100644
index 0000000..1f12f38
--- /dev/null
+++ b/tests/html/js_type_test_js.js
@@ -0,0 +1,5 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+function Foo() {}
diff --git a/tests/html/js_type_test_lib.dart b/tests/html/js_type_test_lib.dart
new file mode 100644
index 0000000..6b7113c
--- /dev/null
+++ b/tests/html/js_type_test_lib.dart
@@ -0,0 +1,13 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@JS()
+library js_type_test_lib;
+
+import 'package:js/js.dart';
+
+@JS()
+class Foo {
+ external factory Foo();
+}
diff --git a/tests/html/js_typed_interop_bind_this_test.dart b/tests/html/js_typed_interop_bind_this_test.dart
new file mode 100644
index 0000000..d241cb9
--- /dev/null
+++ b/tests/html/js_typed_interop_bind_this_test.dart
@@ -0,0 +1,53 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@JS()
+library js_typed_interop_bind_this_test;
+
+import 'dart:html';
+
+import 'package:js/js.dart';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+import 'package:unittest/html_individual_config.dart';
+
+// This is a regression test for https://github.com/dart-lang/sdk/issues/25658
+
+_injectJs() {
+ document.body.append(new ScriptElement()
+ ..type = 'text/javascript'
+ ..innerHtml = r"""
+ "use strict";
+
+ function JsTest() {
+ }
+
+ JsTest.returnThis = function(name, value) {
+ return this;
+ };
+""");
+}
+
+@JS('JsTest.returnThis')
+external returnThis([name, value]);
+
+@JS('JsTest')
+external get jsTestObject;
+
+@JS('window')
+external get jsWindow;
+
+main() {
+ _injectJs();
+
+ useHtmlIndividualConfiguration();
+
+ group('bind this', () {
+ test('simple', () {
+ expect(identical(returnThis(), jsWindow), isFalse);
+ expect(identical(returnThis(), null), isFalse);
+ expect(identical(returnThis(), jsTestObject), isTrue);
+ });
+ });
+}
diff --git a/tests/html/js_typed_interop_callable_object_test.dart b/tests/html/js_typed_interop_callable_object_test.dart
new file mode 100644
index 0000000..4456459
--- /dev/null
+++ b/tests/html/js_typed_interop_callable_object_test.dart
@@ -0,0 +1,72 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@JS()
+library js_typed_interop_callable_object_test;
+
+import 'dart:html';
+
+import 'package:expect/expect.dart' show NoInline, AssumeDynamic;
+import 'package:js/js.dart';
+import 'package:unittest/html_config.dart';
+import 'package:unittest/html_individual_config.dart';
+import 'package:unittest/unittest.dart';
+
+// This is a regression test for https://github.com/dart-lang/sdk/issues/25658
+
+@NoInline()
+@AssumeDynamic()
+confuse(x) => x;
+
+_injectJs() {
+ document.body.append(new ScriptElement()
+ ..type = 'text/javascript'
+ ..innerHtml = r"""
+ "use strict";
+
+ window.callableObject = function (a, b) { return a + b; };
+ window.callableObject.foo = function() { return "bar"; };
+ window.callableObject.bar = 42;
+
+""");
+}
+
+@JS()
+@anonymous
+class CallableObject {
+ /// If a @JS class implements `call`, the underlying representation must be
+ /// a JavaScript callable (i.e. function).
+ external num call(num a, num b);
+ external int get bar;
+ external String foo();
+}
+
+@JS()
+external CallableObject get callableObject;
+
+main() {
+ _injectJs();
+
+ useHtmlIndividualConfiguration();
+
+ group('callable object', () {
+ test('simple', () {
+ var obj = callableObject;
+ expect(obj(4, 5), equals(9));
+ expect(obj.bar, equals(42));
+ expect(obj.foo(), equals("bar"));
+
+ expect(callableObject(4, 5), equals(9));
+ expect(callableObject.bar, equals(42));
+ expect(callableObject.foo(), equals("bar"));
+ });
+
+ test('dynamic', () {
+ var obj = confuse(callableObject);
+ expect(obj(4, 5), equals(9));
+ expect(obj.bar, equals(42));
+ expect(obj.foo(), equals("bar"));
+ });
+ });
+}
diff --git a/tests/html/js_typed_interop_test.dart b/tests/html/js_typed_interop_test.dart
index 431d533..960c0cc 100644
--- a/tests/html/js_typed_interop_test.dart
+++ b/tests/html/js_typed_interop_test.dart
@@ -71,6 +71,15 @@
getA: function() { return this.a;}
};
+ function _PrivateClass(a, b) {
+ this._a = a;
+ this._b = b;
+ };
+
+ _PrivateClass.prototype = {
+ _getA: function() { return this._a;}
+ };
+
var selection = ["a", "b", "c", foo, bar];
function returnNumArgs() { return arguments.length; };
@@ -78,6 +87,23 @@
function confuse(obj) { return obj; }
+ window['class'] = function() { return 42; };
+ window['delete'] = 100;
+ window['JS$hasJsInName'] = 'unicorn';
+ window['JS$hasJsInNameMethod'] = function(x) { return x*5; };
+
+ function JS$ClassWithJSInName(x) {
+ this.x = x;
+ this.JS$hasJsInName = 73;
+ this.$JS$doesNotNeedEscape = 103;
+ };
+
+ JS$ClassWithJSInName.prototype = {
+ JS$getXwithJsInName: function() { return this.x;}
+ };
+
+ JS$ClassWithJSInName.JS$staticMethod = function(x) { return x * 3; };
+
function StringWrapper(str) {
this.str = str;
}
@@ -110,6 +136,49 @@
external get b;
}
+@JS('ClassWithConstructor')
+class _ClassWithConstructor {
+ external _ClassWithConstructor(aParam, bParam);
+ external getA();
+ external get a;
+ external get b;
+}
+
+@JS()
+class JS$_PrivateClass {
+ external JS$_PrivateClass(aParam, bParam);
+ external JS$_getA();
+ external get JS$_a;
+ external get JS$_b;
+ // Equivalent to JS$_a but only visible within
+ // the class.
+ external get _a;
+}
+
+@JS()
+external String get JS$JS$hasJsInName;
+
+@JS()
+external int JS$JS$hasJsInNameMethod(int x);
+
+// This is the prefered way to handle static or top level members that start
+// with JS$. We verify that JS$JS$ works purely to prevent bugs.
+@JS(r'JS$hasJsInName')
+external String get JS$hasJsInName;
+
+@JS(r'JS$hasJsInNameMethod')
+external int JS$hasJsInNameMethod(int x);
+
+@JS()
+class JS$JS$ClassWithJSInName {
+ external JS$JS$ClassWithJSInName(x);
+ external int get x;
+ external int get JS$JS$hasJsInName;
+ external int get $JS$doesNotNeedEscape;
+ external int JS$JS$getXwithJsInName();
+ external static int JS$JS$staticMethod(x);
+}
+
typedef num MultiplyWithDefault(num a, [num b]);
@JS()
@@ -118,6 +187,7 @@
external set x(int v);
external num multiplyByX(num y);
external num multiplyBy2(num y);
+ external num JS$multiplyBy2(num y);
external MultiplyWithDefault get multiplyDefault2Function;
external callClosureWithArgAndThis(Function closure, arg);
@@ -126,14 +196,17 @@
external Bar getBar();
external static num multiplyDefault2(num a, [num b]);
+ // Should desugar to multiplyDefault2.
+ external static num JS$multiplyDefault2(num a, [num b]);
}
@anonymous
@JS()
class ExampleLiteral {
- external factory ExampleLiteral({int x, String y, num z});
+ external factory ExampleLiteral({int x, String y, num z, JS$class});
external int get x;
+ external int get JS$class;
external String get y;
external num get z;
}
@@ -182,6 +255,13 @@
@JS()
external confuse(obj);
+/// Desugars to calling the js method named class.
+@JS()
+external JS$class();
+
+@JS()
+external get JS$delete;
+
@JS()
external CanvasRenderingContext2D getCanvasContext();
@@ -191,6 +271,16 @@
@JS('window.self.window.window.windowProperty')
external num get propertyOnWindow;
+@JS()
+@anonymous
+class Simple
+{
+ external List<int> get numbers;
+ external set numbers(List<int> numbers);
+
+ external factory Simple({ List<int> numbers });
+}
+
main() {
_injectJs();
@@ -210,6 +300,17 @@
expect(stringify(l), equals('{"z":100}'));
});
+ test('with array', () {
+ // Repro for https://github.com/dart-lang/sdk/issues/26768
+ var simple = new Simple(numbers: [ 1, 2, 3 ]);
+ expect(stringify(simple), equals('{"numbers":[1,2,3]}'));
+ });
+
+ test(r'JS$ escaped name', () {
+ var l = new ExampleLiteral(JS$class: 3, y: "foo");
+ expect(l.JS$class, equals(3));
+ });
+
test('empty', () {
var l = new EmptyLiteral();
expect(stringify(l), equals('{}'));
@@ -225,6 +326,25 @@
});
});
+ group('private class', () {
+ test('simple', () {
+ var o = new _ClassWithConstructor("foo", "bar");
+ expect(o.a, equals("foo"));
+ expect(o.b, equals("bar"));
+ expect(o.getA(), equals("foo"));
+ });
+ });
+
+ group('private class', () {
+ test('simple', () {
+ var o = new JS$_PrivateClass("foo", "bar");
+ expect(o.JS$_a, equals("foo"));
+ expect(o.JS$_b, equals("bar"));
+ expect(o._a, equals("foo"));
+ expect(o.JS$_getA(), equals("foo"));
+ });
+ });
+
group('property', () {
test('get', () {
expect(foo.x, equals(3));
@@ -276,6 +396,22 @@
expect(untypedFunction(), isNaN);
});
+
+ test(r'JS$ escaped name', () {
+ foo.x = 10;
+ expect(foo.JS$multiplyBy2(5), equals(10));
+
+ Function multiplyBy2 = foo.JS$multiplyBy2;
+ expect(multiplyBy2(5), equals(10));
+ });
+
+ test(r'JS$ double escaped name', () {
+ var obj = new JS$JS$ClassWithJSInName(42);
+ expect(obj.x, equals(42));
+ expect(obj.JS$JS$getXwithJsInName(), equals(42));
+ expect(obj.JS$JS$hasJsInName, equals(73));
+ expect(obj.$JS$doesNotNeedEscape, equals(103));
+ });
});
group('static_method_call', () {
@@ -283,6 +419,15 @@
expect(Foo.multiplyDefault2(6, 7), equals(42));
expect(Foo.multiplyDefault2(6), equals(12));
});
+
+ test(r'JS$ escaped name', () {
+ expect(Foo.JS$multiplyDefault2(6, 7), equals(42));
+ expect(Foo.JS$multiplyDefault2(6), equals(12));
+ });
+
+ test(r'JS$ double escaped name', () {
+ expect(JS$JS$ClassWithJSInName.JS$JS$staticMethod(4), equals(12));
+ });
});
// Note: these extra groups are added to be able to mark each test
@@ -384,6 +529,17 @@
});
});
+ group(r'JS$ escaped', () {
+ test('top level', () {
+ expect(JS$class(), equals(42));
+ expect(JS$delete, equals(100));
+ });
+ test('top level double escaped', () {
+ expect(JS$JS$hasJsInName, equals('unicorn'));
+ expect(JS$JS$hasJsInNameMethod(4), equals(20));
+ });
+ });
+
group('type check', () {
test('js interfaces', () {
// Is checks return true for all JavaScript interfaces.
diff --git a/tests/html/js_typed_interop_type_test.dart b/tests/html/js_typed_interop_type_test.dart
new file mode 100644
index 0000000..59266dc
--- /dev/null
+++ b/tests/html/js_typed_interop_type_test.dart
@@ -0,0 +1,166 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+
+@JS()
+library js_typed_interop_type_test;
+
+import 'dart:html';
+import 'package:js/js.dart';
+import 'package:expect/expect.dart';
+
+@JS()
+class A {
+ var foo;
+
+ external A(var foo);
+}
+
+@JS()
+class B {
+ var foo;
+
+ external B(var foo);
+}
+
+@JS()
+@anonymous
+class C {
+ final foo;
+
+ external factory C({foo});
+}
+
+@JS()
+@anonymous
+class D {
+ final foo;
+
+ external factory D({foo});
+}
+
+class E {
+ final foo;
+
+ E(this.foo);
+}
+
+class F {
+ final foo;
+
+ F(this.foo);
+}
+
+@NoInline()
+testA(A o) {
+ return o.foo;
+}
+
+
+@NoInline()
+testB(B o) {
+ return o.foo;
+}
+
+
+@NoInline()
+testC(C o) {
+ return o.foo;
+}
+
+
+@NoInline()
+testD(D o) {
+ return o.foo;
+}
+
+@NoInline()
+testE(E o) {
+ return o.foo;
+}
+
+@NoInline()
+testF(F o) {
+ return o.foo;
+}
+
+
+_injectJs() {
+ document.body.append(new ScriptElement()
+ ..type = 'text/javascript'
+ ..innerHtml = r"""
+function A(foo) {
+ this.foo = foo;
+}
+
+function B(foo) {
+ this.foo = foo;
+}
+""");
+}
+
+void expectValueOrTypeError(f(), value) {
+ try {
+ var i = 0;
+ String s = i; // Test for checked mode.
+ Expect.equals(f(), value);
+ } on TypeError catch (error) {
+ Expect.throws(f, (ex) => ex is TypeError);
+ }
+}
+
+main() {
+ _injectJs();
+
+ var a = new A(1);
+ var b = new B(2);
+ var c = new C(foo: 3);
+ var d = new D(foo: 4);
+ var e = new E(5);
+ var f = new F(6);
+
+ Expect.equals(testA(a), 1);
+ Expect.equals(testA(b), 2);
+ Expect.equals(testA(c), 3);
+ Expect.equals(testA(d), 4);
+ expectValueOrTypeError(() => testA(e), 5);
+ expectValueOrTypeError(() => testA(f), 6);
+
+ Expect.equals(testB(a), 1);
+ Expect.equals(testB(b), 2);
+ Expect.equals(testB(c), 3);
+ Expect.equals(testB(d), 4);
+ expectValueOrTypeError(() => testB(e), 5);
+ expectValueOrTypeError(() => testB(f), 6);
+
+ Expect.equals(testC(a), 1);
+ Expect.equals(testC(b), 2);
+ Expect.equals(testC(c), 3);
+ Expect.equals(testC(d), 4);
+ expectValueOrTypeError(() => testC(e), 5);
+ expectValueOrTypeError(() => testC(f), 6);
+
+ Expect.equals(testD(a), 1);
+ Expect.equals(testD(b), 2);
+ Expect.equals(testD(c), 3);
+ Expect.equals(testD(d), 4);
+ expectValueOrTypeError(() => testD(e), 5);
+ expectValueOrTypeError(() => testD(f), 6);
+
+ expectValueOrTypeError(() => testE(a), 1);
+ expectValueOrTypeError(() => testE(b), 2);
+ expectValueOrTypeError(() => testE(c), 3);
+ expectValueOrTypeError(() => testE(d), 4);
+ Expect.equals(testE(e), 5);
+ expectValueOrTypeError(() => testE(f), 6);
+
+ expectValueOrTypeError(() => testF(a), 1);
+ expectValueOrTypeError(() => testF(b), 2);
+ expectValueOrTypeError(() => testF(c), 3);
+ expectValueOrTypeError(() => testF(d), 4);
+ expectValueOrTypeError(() => testF(e), 5);
+ Expect.equals(testF(f), 6);
+}
+
+
diff --git a/tests/html/js_typed_interop_window_property_test.dart b/tests/html/js_typed_interop_window_property_test.dart
new file mode 100644
index 0000000..0f2bdc6
--- /dev/null
+++ b/tests/html/js_typed_interop_window_property_test.dart
@@ -0,0 +1,40 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@JS()
+library js_typed_interop_window_property_test;
+
+import 'dart:html';
+
+import 'package:js/js.dart';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+import 'package:unittest/html_individual_config.dart';
+
+// This is a regression test for https://github.com/dart-lang/sdk/issues/24817
+
+_injectJs() {
+ document.body.append(new ScriptElement()
+ ..type = 'text/javascript'
+ ..innerHtml = r"""
+ "use strict";
+
+ window.foo = [function() { return 42; }];
+""");
+}
+
+@JS("window.foo")
+external List<Function> get foo;
+
+main() {
+ _injectJs();
+
+ useHtmlIndividualConfiguration();
+
+ group('bind this', () {
+ test('simple', () {
+ expect(foo[0](), equals(42));
+ });
+ });
+}
diff --git a/tests/html/js_util_test.dart b/tests/html/js_util_test.dart
new file mode 100644
index 0000000..b0130b2
--- /dev/null
+++ b/tests/html/js_util_test.dart
@@ -0,0 +1,347 @@
+// 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.
+
+@JS()
+library js_native_test;
+
+import 'dart:async';
+import 'dart:html';
+import 'dart:typed_data' show ByteBuffer, Int32List;
+import 'dart:indexed_db' show IdbFactory, KeyRange;
+
+import 'package:js/js.dart';
+import 'package:js/js_util.dart' as js_util;
+
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_individual_config.dart';
+
+_injectJs() {
+ final script = new ScriptElement();
+ script.type = 'text/javascript';
+ script.innerHtml = r"""
+var x = 42;
+
+var _x = 123;
+
+var myArray = ["value1"];
+
+function returnThis() {
+ return this;
+}
+
+function getTypeOf(o) {
+ return typeof(o);
+}
+
+function Foo(a) {
+ this.a = a;
+}
+
+Foo.b = 38;
+
+Foo.prototype.bar = function() {
+ return this.a;
+}
+Foo.prototype.toString = function() {
+ return "I'm a Foo a=" + this.a;
+}
+
+var container = new Object();
+container.Foo = Foo;
+
+function checkMap(m, key, value) {
+ if (m.hasOwnProperty(key))
+ return m[key] == value;
+ else
+ return false;
+}
+
+""";
+ document.body.append(script);
+}
+
+@JS()
+external bool checkMap(m, String, value);
+
+@JS('JSON.stringify')
+external String stringify(o);
+
+@JS('Node')
+external get JSNodeType;
+
+@JS('Element')
+external get JSElementType;
+
+@JS('Text')
+external get JSTextType;
+
+@JS('HTMLCanvasElement')
+external get JSHtmlCanvasElementType;
+
+@JS()
+class Foo {
+ external Foo(num a);
+
+ external num get a;
+ external num bar();
+}
+
+@JS('Foo')
+external get JSFooType;
+
+@JS()
+@anonymous
+class ExampleTypedLiteral {
+ external factory ExampleTypedLiteral({a, b, JS$_c, JS$class});
+
+ external get a;
+ external get b;
+ external get JS$_c;
+ external set JS$_c(v);
+ // Identical to JS$_c but only accessible within the library.
+ external get _c;
+ external get JS$class;
+ external set JS$class(v);
+}
+
+@JS("Object.prototype.hasOwnProperty")
+external get _hasOwnProperty;
+
+bool hasOwnProperty(o, String name) {
+ return js_util.callMethod(_hasOwnProperty, 'call', [o, name]);
+}
+
+main() {
+ _injectJs();
+ useHtmlIndividualConfiguration();
+
+ group('js_util.jsify()', () {
+ test('convert a List', () {
+ final list = [1, 2, 3, 4, 5, 6, 7, 8];
+ var array = js_util.jsify(list);
+ expect(array is List, isTrue);
+ expect(identical(array, list), isFalse);
+ expect(array.length, equals(list.length));
+ for (var i = 0; i < list.length; i++) {
+ expect(array[i], equals(list[i]));
+ }
+ });
+
+ test('convert an Iterable', () {
+ final set = new Set.from([1, 2, 3, 4, 5, 6, 7, 8]);
+ var array = js_util.jsify(set);
+ expect(array is List, isTrue);
+ expect(array.length, equals(set.length));
+ for (var i = 0; i < array.length; i++) {
+ expect(set.contains(array[i]), isTrue);
+ }
+ });
+
+ test('convert a Map', () {
+ var map = {'a': 1, 'b': 2, 'c': 3};
+ var jsMap = js_util.jsify(map);
+ expect(jsMap is! List, isTrue);
+ for (var key in map.keys) {
+ expect(checkMap(jsMap, key, map[key]), isTrue);
+ }
+ });
+
+ test('deep convert a complex object', () {
+ final object = {
+ 'a': [
+ 1,
+ [2, 3]
+ ],
+ 'b': {'c': 3, 'd': new Foo(42)},
+ 'e': null
+ };
+ var jsObject = js_util.jsify(object);
+ expect(js_util.getProperty(jsObject, 'a')[0], equals(object['a'][0]));
+ expect(
+ js_util.getProperty(jsObject, 'a')[1][0], equals(object['a'][1][0]));
+ expect(
+ js_util.getProperty(jsObject, 'a')[1][1], equals(object['a'][1][1]));
+ expect(js_util.getProperty(js_util.getProperty(jsObject, 'b'), 'c'),
+ equals(object['b']['c']));
+ expect(js_util.getProperty(js_util.getProperty(jsObject, 'b'), 'd'),
+ equals(object['b']['d']));
+ expect(
+ js_util.callMethod(
+ js_util.getProperty(js_util.getProperty(jsObject, 'b'), 'd'),
+ 'bar', []),
+ equals(42));
+ expect(js_util.getProperty(jsObject, 'e'), isNull);
+ });
+
+ test('throws if object is not a Map or Iterable', () {
+ expect(() => js_util.jsify('a'),
+ throwsA(new isInstanceOf<ArgumentError>()));
+ });
+ });
+
+ group('js_util.newObject', () {
+ test('create', () {
+ expect(identical(js_util.newObject(), js_util.newObject()), isFalse);
+ });
+
+ test('callMethod', () {
+ var o = js_util.newObject();
+ expect(js_util.callMethod(o, 'toString', []), equals('[object Object]'));
+ expect(stringify(o), equals('{}'));
+ });
+
+ test('properties', () {
+ var o = js_util.newObject();
+ expect(js_util.hasProperty(o, 'foo bar'), isFalse);
+ expect(js_util.hasProperty(o, 'toString'), isTrue);
+ expect(hasOwnProperty(o, 'toString'), isFalse);
+ expect(hasOwnProperty(o, 'foo bar'), isFalse);
+ js_util.setProperty(o, 'foo bar', 42);
+ expect(hasOwnProperty(o, 'foo bar'), isTrue);
+ expect(js_util.getProperty(o, 'foo bar'), equals(42));
+ expect(js_util.hasProperty(o, 'foo bar'), isTrue);
+ expect(stringify(o), equals('{"foo bar":42}'));
+ });
+ });
+
+ group('hasProperty', () {
+ test('typed object', () {
+ var f = new Foo(42);
+ expect(js_util.hasProperty(f, 'a'), isTrue);
+ expect(js_util.hasProperty(f, 'toString'), isTrue);
+ js_util.setProperty(f, '__proto__', null);
+ expect(js_util.hasProperty(f, 'toString'), isFalse);
+ });
+ test('typed literal', () {
+ var l =
+ new ExampleTypedLiteral(a: 'x', b: 42, JS$_c: null, JS$class: true);
+ expect(js_util.hasProperty(l, 'a'), isTrue);
+ expect(js_util.hasProperty(l, 'b'), isTrue);
+ expect(js_util.hasProperty(l, '_c'), isTrue);
+ expect(l.JS$_c, isNull);
+ expect(js_util.hasProperty(l, 'class'), isTrue);
+ // JS$_c escapes to _c so the property JS$_c will not exist on the object.
+ expect(js_util.hasProperty(l, r'JS$_c'), isFalse);
+ expect(js_util.hasProperty(l, r'JS$class'), isFalse);
+ expect(l.JS$class, isTrue);
+
+ l = new ExampleTypedLiteral(a: null);
+ expect(js_util.hasProperty(l, 'a'), isTrue);
+ expect(js_util.hasProperty(l, 'b'), isFalse);
+ expect(js_util.hasProperty(l, '_c'), isFalse);
+ expect(js_util.hasProperty(l, 'class'), isFalse);
+
+ l = new ExampleTypedLiteral(JS$_c: 74);
+ expect(js_util.hasProperty(l, '_c'), isTrue);
+ expect(l.JS$_c, equals(74));
+ });
+ });
+
+ group('getProperty', () {
+ test('typed object', () {
+ var f = new Foo(42);
+ expect(js_util.getProperty(f, 'a'), equals(42));
+ expect(js_util.getProperty(f, 'toString') is Function, isTrue);
+ js_util.setProperty(f, '__proto__', null);
+ expect(js_util.getProperty(f, 'toString'), isNull);
+ });
+
+ test('typed literal', () {
+ var l = new ExampleTypedLiteral(a: 'x', b: 42, JS$_c: 7, JS$class: true);
+ expect(js_util.getProperty(l, 'a'), equals('x'));
+ expect(js_util.getProperty(l, 'b'), equals(42));
+ expect(js_util.getProperty(l, '_c'), equals(7));
+ expect(l.JS$_c, equals(7));
+ expect(js_util.getProperty(l, 'class'), isTrue);
+ expect(js_util.getProperty(l, r'JS$_c'), isNull);
+ expect(js_util.getProperty(l, r'JS$class'), isNull);
+ });
+ });
+
+ group('setProperty', () {
+ test('typed object', () {
+ var f = new Foo(42);
+ expect(js_util.getProperty(f, 'a'), equals(42));
+ js_util.setProperty(f, 'a', 100);
+ expect(f.a, equals(100));
+ expect(js_util.getProperty(f, 'a'), equals(100));
+ });
+
+ test('typed literal', () {
+ var l = new ExampleTypedLiteral();
+ js_util.setProperty(l, 'a', 'foo');
+ expect(js_util.getProperty(l, 'a'), equals('foo'));
+ expect(l.a, equals('foo'));
+ js_util.setProperty(l, 'a', l);
+ expect(identical(l.a, l), isTrue);
+ var list = ['arr'];
+ js_util.setProperty(l, 'a', list);
+ expect(identical(l.a, list), isTrue);
+ l.JS$class = 42;
+ expect(l.JS$class, equals(42));
+ js_util.setProperty(l, 'class', 100);
+ expect(l.JS$class, equals(100));
+ });
+ });
+
+ group('callMethod', () {
+ test('html object', () {
+ var canvas = new Element.tag('canvas');
+ expect(
+ identical(canvas.getContext('2d'),
+ js_util.callMethod(canvas, 'getContext', ['2d'])),
+ isTrue);
+ });
+
+ test('typed object', () {
+ var f = new Foo(42);
+ expect(js_util.callMethod(f, 'bar', []), equals(42));
+ });
+ });
+
+ group('instanceof', () {
+ test('html object', () {
+ var canvas = new Element.tag('canvas');
+ expect(js_util.instanceof(canvas, JSNodeType), isTrue);
+ expect(js_util.instanceof(canvas, JSTextType), isFalse);
+ expect(js_util.instanceof(canvas, JSElementType), isTrue);
+ expect(js_util.instanceof(canvas, JSHtmlCanvasElementType), isTrue);
+ var div = new Element.tag('div');
+ expect(js_util.instanceof(div, JSNodeType), isTrue);
+ expect(js_util.instanceof(div, JSTextType), isFalse);
+ expect(js_util.instanceof(div, JSElementType), isTrue);
+ expect(js_util.instanceof(div, JSHtmlCanvasElementType), isFalse);
+
+ var text = new Text('foo');
+ expect(js_util.instanceof(text, JSNodeType), isTrue);
+ expect(js_util.instanceof(text, JSTextType), isTrue);
+ expect(js_util.instanceof(text, JSElementType), isFalse);
+ });
+
+ test('typed object', () {
+ var f = new Foo(42);
+ expect(js_util.instanceof(f, JSFooType), isTrue);
+ expect(js_util.instanceof(f, JSNodeType), isFalse);
+ });
+
+ test('typed literal', () {
+ var l = new ExampleTypedLiteral();
+ expect(js_util.instanceof(l, JSFooType), isFalse);
+ });
+ });
+
+ group('callConstructor', () {
+ test('html object', () {
+ var textNode = js_util.callConstructor(JSTextType, ['foo']);
+ expect(js_util.instanceof(textNode, JSTextType), isTrue);
+ expect(textNode is Text, isTrue);
+ expect(textNode.text, equals('foo'));
+ });
+
+ test('typed object', () {
+ Foo f = js_util.callConstructor(JSFooType, [42]);
+ expect(f.a, equals(42));
+ });
+ });
+}
diff --git a/tests/html/node_validator_important_if_you_suppress_make_the_bug_critical_test.dart b/tests/html/node_validator_important_if_you_suppress_make_the_bug_critical_test.dart
index 4d7d338..6859e87 100644
--- a/tests/html/node_validator_important_if_you_suppress_make_the_bug_critical_test.dart
+++ b/tests/html/node_validator_important_if_you_suppress_make_the_bug_critical_test.dart
@@ -116,6 +116,14 @@
validator,
'<span>![CDATA[ some text ]]></span>');
+ testHtml('backquotes not removed',
+ validator,
+ '<img src="dice.png" alt="``onload=xss()" />');
+
+ testHtml('0x3000 not removed',
+ validator,
+ '<a href=" javascript:alert(1)">CLICKME</a>');
+
test('sanitizes template contents', () {
if (!TemplateElement.supported) return;
diff --git a/tests/html/webgl_extensions_test.dart b/tests/html/webgl_extensions_test.dart
new file mode 100644
index 0000000..07232f0
--- /dev/null
+++ b/tests/html/webgl_extensions_test.dart
@@ -0,0 +1,199 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library web_gl_test;
+
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_individual_config.dart';
+import 'dart:html';
+import 'dart:typed_data';
+import 'dart:web_gl';
+import 'dart:web_gl' as gl;
+
+// Test that various webgl extensions are available. Only test advertised
+// supported extensions. If the extension has methods, we just test the presence
+// of some methods - we don't test if functionality works.
+
+main() {
+ useHtmlIndividualConfiguration();
+
+ if (!RenderingContext.supported) return;
+
+
+ const allExtensions = const [
+ 'ANGLE_instanced_arrays',
+ 'EXT_blend_minmax',
+ 'EXT_color_buffer_float',
+ 'EXT_color_buffer_half_float',
+ 'EXT_disjoint_timer_query',
+ 'EXT_frag_depth',
+ 'EXT_sRGB',
+ 'EXT_shader_texture_lod',
+ 'EXT_texture_filter_anisotropic',
+ 'OES_element_index_uint',
+ 'OES_standard_derivatives',
+ 'OES_texture_float',
+ 'OES_texture_float_linear',
+ 'OES_texture_half_float',
+ 'OES_texture_half_float_linear',
+ 'OES_vertex_array_object',
+ 'WEBGL_color_buffer_float',
+ 'WEBGL_compressed_texture_atc',
+ 'WEBGL_compressed_texture_es3',
+ 'WEBGL_compressed_texture_etc1',
+ 'WEBGL_compressed_texture_pvrtc',
+ 'WEBGL_compressed_texture_s3tc',
+ 'WEBGL_debug_renderer_info',
+ 'WEBGL_debug_shaders',
+ 'WEBGL_depth_texture',
+ 'WEBGL_draw_buffers',
+ 'WEBGL_lose_context',
+ ];
+
+ getExtension(String name) {
+ expect(name, isIn(allExtensions), reason: 'unknown extension');
+ var canvas = new CanvasElement();
+ var context = canvas.getContext3d();
+ var supportedExtensions = context.getSupportedExtensions();
+ if (supportedExtensions.contains(name)) {
+ var extension = context.getExtension(name);
+ expect(extension, isNotNull);
+ return extension;
+ }
+ return null;
+ }
+
+ testType(name, typeMatcher) {
+ test('type', () {
+ var extension = getExtension(name);
+ if (extension == null) return;
+ expect(extension, typeMatcher);
+ // Ensure that isInstanceOf<X> is not instantiated for an erroneous type
+ // X. If X is erroneous, there is only a warning at compile time and X is
+ // treated as dynamic, which would make the above line pass.
+ expect(1, isNot(typeMatcher), reason: 'invalid typeMatcher');
+ });
+ }
+
+ group('ANGLE_instanced_arrays', () {
+ const name = 'ANGLE_instanced_arrays';
+ testType(name, const isInstanceOf<AngleInstancedArrays>());
+ test('vertexAttribDivisorAngle', () {
+ var extension = getExtension(name);
+ if (extension == null) return;
+ expect(extension.vertexAttribDivisorAngle, isFunction);
+ });
+ });
+
+ group('EXT_blend_minmax', () {
+ testType('EXT_blend_minmax', const isInstanceOf<ExtBlendMinMax>());
+ });
+
+ group('EXT_frag_depth', () {
+ testType('EXT_frag_depth', const isInstanceOf<ExtFragDepth>());
+ });
+
+ group('EXT_sRGB', () {
+ testType('EXT_sRGB', const isInstanceOf<EXTsRgb>());
+ });
+
+ group('EXT_shader_texture_lod', () {
+ testType(
+ 'EXT_shader_texture_lod', const isInstanceOf<ExtShaderTextureLod>());
+ });
+
+ group('EXT_texture_filter_anisotropic', () {
+ testType('EXT_texture_filter_anisotropic',
+ const isInstanceOf<ExtTextureFilterAnisotropic>());
+ });
+
+ group('OES_element_index_uint', () {
+ testType(
+ 'OES_element_index_uint', const isInstanceOf<OesElementIndexUint>());
+ });
+
+ group('OES_standard_derivatives', () {
+ testType('OES_standard_derivatives',
+ const isInstanceOf<OesStandardDerivatives>());
+ });
+
+ group('OES_texture_float', () {
+ testType('OES_texture_float', const isInstanceOf<OesTextureFloat>());
+ });
+
+ group('OES_texture_float_linear', () {
+ testType('OES_texture_float_linear',
+ const isInstanceOf<OesTextureFloatLinear>());
+ });
+
+ group('OES_texture_half_float', () {
+ testType(
+ 'OES_texture_half_float', const isInstanceOf<OesTextureHalfFloat>());
+ });
+
+ group('OES_texture_half_float_linear', () {
+ testType('OES_texture_half_float_linear',
+ const isInstanceOf<OesTextureHalfFloatLinear>());
+ });
+
+ group('OES_vertex_array_object', () {
+ testType(
+ 'OES_vertex_array_object', const isInstanceOf<OesVertexArrayObject>());
+ });
+
+ group('WEBGL_compressed_texture_atc', () {
+ testType('WEBGL_compressed_texture_atc',
+ const isInstanceOf<CompressedTextureAtc>());
+ });
+
+ group('WEBGL_compressed_texture_etc1', () {
+ testType('WEBGL_compressed_texture_etc1',
+ const isInstanceOf<CompressedTextureETC1>());
+ });
+
+ group('WEBGL_compressed_texture_pvrtc', () {
+ testType('WEBGL_compressed_texture_pvrtc',
+ const isInstanceOf<CompressedTexturePvrtc>());
+ });
+
+ group('WEBGL_compressed_texture_s3tc', () {
+ testType('WEBGL_compressed_texture_s3tc',
+ const isInstanceOf<CompressedTextureS3TC>());
+ });
+
+ group('WEBGL_debug_renderer_info', () {
+ testType(
+ 'WEBGL_debug_renderer_info', const isInstanceOf<DebugRendererInfo>());
+ });
+
+ group('WEBGL_debug_shaders', () {
+ testType('WEBGL_debug_shaders', const isInstanceOf<DebugShaders>());
+ });
+
+ group('WEBGL_depth_texture', () {
+ testType('WEBGL_depth_texture', const isInstanceOf<DepthTexture>());
+ });
+
+ group('WEBGL_draw_buffers', () {
+ const name = 'WEBGL_draw_buffers';
+ testType(name, const isInstanceOf<DrawBuffers>());
+ test('drawBuffersWebgl', () {
+ var extension = getExtension(name);
+ if (extension == null) return;
+ expect(extension.drawBuffersWebgl, isFunction);
+ });
+ });
+
+ group('WEBGL_lose_context', () {
+ const name = 'WEBGL_lose_context';
+ testType(name, const isInstanceOf<LoseContext>());
+ test('loseContext', () {
+ var extension = getExtension(name);
+ if (extension == null) return;
+ expect(extension.loseContext, isFunction);
+ });
+ });
+}
+
+Matcher isFunction = const isInstanceOf<Function>();
diff --git a/tests/isolate/isolate.status b/tests/isolate/isolate.status
index 67d2941..1902a62 100644
--- a/tests/isolate/isolate.status
+++ b/tests/isolate/isolate.status
@@ -207,3 +207,10 @@
[ $compiler == precompiler && $runtime == dart_precompiled && $system == android ]
*: Skip # Issue #26373
+
+[ $hot_reload ]
+function_send_test: Pass, Fail # Closure identity
+message3_test/fun: Pass, Fail # Closure identity
+deferred_in_isolate_test: Crash # Requires deferred libraries
+deferred_in_isolate2_test: Crash # Requires deferred libraries
+issue_21398_parent_isolate2_test: Crash # Requires deferred libraries
diff --git a/tests/isolate/package_config_test.dart b/tests/isolate/package_config_test.dart
index 1b55194..58792d9 100644
--- a/tests/isolate/package_config_test.dart
+++ b/tests/isolate/package_config_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=--trace_shutdown
import 'dart:io';
import 'dart:isolate';
diff --git a/tests/language/arg_param_trailing_comma_test.dart b/tests/language/arg_param_trailing_comma_test.dart
index 4b87b1a..cd0d3a4 100644
--- a/tests/language/arg_param_trailing_comma_test.dart
+++ b/tests/language/arg_param_trailing_comma_test.dart
@@ -41,7 +41,7 @@
void afterFunsigY([void f(),]) {} /// none: continued
void afterFunsigZ({void f(),}) {} /// none: continued
void afterFunsigDefaultValueY([void f() = topy,]) {} /// none: continued
-void afterFunsigDefaultValueZ({void f() : topt,}) {} /// none: continued
+void afterFunsigDefaultValueZ({void f() : topz,}) {} /// none: continued
class C {
C();
@@ -77,8 +77,8 @@
main() {
testCalls(); /// none: continued
- // Make sure the Bad class is checked.
- new Bad().method();
+ // Make sure the cases are checked.
+ testBadCalls();
}
void testCalls() {
@@ -124,7 +124,7 @@
c + x; /// none: continued
c[x] = y; /// none: continued
- // Call with ekstra comma (not possible for setters and operators).
+ // Call with extra comma (not possible for setters and operators).
topx(x, ); /// none: continued
topy(y, ); /// none: continued
topxy(x, y, ); /// none: continued
@@ -169,7 +169,6 @@
argfxz(topxz); /// none: continued
}
-
// Invalid syntax. This was invalid syntax before the addition of trailing
// commas too, and should stay that way.
void topBadEmpty(,) {} /// 1: compile-time error
@@ -199,6 +198,7 @@
void set topSetBadEnd(a,,) {} /// 25: compile-time error
void set topSetBadMiddle(a,, b) {} /// 26: compile-time error
class Bad {
+ Bad() {}
Bad.empty(,) {} /// 27: compile-time error
Bad.start(, a) {} /// 28: compile-time error
Bad.end(a,,) {} /// 29: compile-time error
@@ -399,3 +399,164 @@
typedef void BadNamEnd({a,,}); /// 208: compile-time error
typedef void BadNamStart({a},); /// 209: compile-time error
typedef void BadNamMiddle({a,, b}); /// 210: compile-time error
+
+void testBadCalls() {
+ topBadEmpty(); /// 1: continued
+ topBadStart(); /// 2: continued
+ topBadEnd(); /// 3: continued
+ topBadMiddle(); /// 4: continued
+ topBadPosEmpty(); /// 5: continued
+ topBadPosEmpty(); /// 6: continued
+ topBadPosEmpty(); /// 7: continued
+ topBadPosEmpty(); /// 8: continued
+ topBadPosStart(); /// 9: continued
+ topBadPosStart(); /// 10: continued
+ topBadPosEnd(); /// 11: continued
+ topBadPosStart(); /// 12: continued
+ topBadPosMiddle(); /// 13: continued
+ topBadNamEmpty(); /// 14: continued
+ topBadNamEmpty(); /// 15: continued
+ topBadNamEmpty(); /// 16: continued
+ topBadNamEmpty(); /// 17: continued
+ topBadNamStart(); /// 18: continued
+ topBadNamStart(); /// 19: continued
+ topBadNamEnd(); /// 20: continued
+ topBadNamStart(); /// 21: continued
+ topBadNamMiddle(); /// 22: continued
+ topSetBadEmpty = 1; /// 23: continued
+ topSetBadStart = 1; /// 24: continued
+ topSetBadEnd = 1; /// 25: continued
+ topSetBadMiddle = 1; /// 26: continued
+ new Bad.empty(); /// 27: continued
+ new Bad.start(); /// 28: continued
+ new Bad.end(); /// 29: continued
+ new Bad.middle(); /// 30: continued
+ new Bad.posEmpty(); /// 31: continued
+ new Bad.posEmpty(); /// 32: continued
+ new Bad.posEmpty(); /// 33: continued
+ new Bad.posEmpty(); /// 34: continued
+ new Bad.posStart(); /// 35: continued
+ new Bad.posStart(); /// 36: continued
+ new Bad.posEnd(); /// 37: continued
+ new Bad.posStart(); /// 38: continued
+ new Bad.PosMiddle(); /// 39: continued
+ new Bad.namEmpty(); /// 40: continued
+ new Bad.namEmpty(); /// 41: continued
+ new Bad.namEmpty(); /// 42: continued
+ new Bad.namEmpty(); /// 43: continued
+ new Bad.namStart(); /// 44: continued
+ new Bad.namStart(); /// 45: continued
+ new Bad.namEnd(); /// 46: continued
+ new Bad.namStart(); /// 47: continued
+ new Bad.namMiddle(); /// 48: continued
+ Bad.staticBadEmpty(); /// 49: continued
+ Bad.staticBadStart(); /// 50: continued
+ Bad.staticBadEnd(); /// 51: continued
+ Bad.staticBadMiddle(); /// 52: continued
+ Bad.staticBadPosEmpty(); /// 53: continued
+ Bad.staticBadPosEmpty(); /// 54: continued
+ Bad.staticBadPosEmpty(); /// 55: continued
+ Bad.staticBadPosEmpty(); /// 56: continued
+ Bad.staticBadPosStart(); /// 57: continued
+ Bad.staticBadPosStart(); /// 58: continued
+ Bad.staticBadPosEnd(); /// 59: continued
+ Bad.staticBadPosStart(); /// 60: continued
+ Bad.staticBadPosMiddle(); /// 61: continued
+ Bad.staticBadNamEmpty(); /// 62: continued
+ Bad.staticBadNamEmpty(); /// 63: continued
+ Bad.staticBadNamEmpty(); /// 64: continued
+ Bad.staticBadNamEmpty(); /// 65: continued
+ Bad.staticBadNamStart(); /// 66: continued
+ Bad.staticBadNamStart(); /// 67: continued
+ Bad.staticBadNamEnd(); /// 68: continued
+ Bad.staticBadNamStart(); /// 69: continued
+ Bad.staticBadNamMiddle(); /// 70: continued
+ Bad.staticSetBadEmpty = 1; /// 71: continued
+ Bad.staticSetBadStart = 1; /// 72: continued
+ Bad.staticSetBadEnd = 1; /// 73: continued
+ Bad.staticSetBadMiddle = 1; /// 74: continued
+
+ var bad = new Bad();
+ bad.instanceBadEmpty(); /// 75: continued
+ bad.instanceBadStart(); /// 76: continued
+ bad.instanceBadEnd(); /// 77: continued
+ bad.instanceBadMiddle(); /// 78: continued
+ bad.instanceBadPosEmpty(); /// 79: continued
+ bad.instanceBadPosEmpty(); /// 80: continued
+ bad.instanceBadPosEmpty(); /// 81: continued
+ bad.instanceBadPosEmpty(); /// 82: continued
+ bad.instanceBadPosStart(); /// 83: continued
+ bad.instanceBadPosStart(); /// 84: continued
+ bad.instanceBadPosEnd(); /// 85: continued
+ bad.instanceBadPosStart(); /// 86: continued
+ bad.instanceBadPosMiddle(); /// 87: continued
+ bad.instanceBadNamEmpty(); /// 88: continued
+ bad.instanceBadNamEmpty(); /// 89: continued
+ bad.instanceBadNamEmpty(); /// 90: continued
+ bad.instanceBadNamEmpty(); /// 91: continued
+ bad.instanceBadNamStart(); /// 92: continued
+ bad.instanceBadNamStart(); /// 93: continued
+ bad.instanceBadNamEnd(); /// 94: continued
+ bad.instanceBadNamStart(); /// 95: continued
+ bad.instanceBadNamMiddle(); /// 96: continued
+ bad.instanceSetBadEmpty = 1; /// 97: continued
+ bad.instanceSetBadStart = 1; /// 98: continued
+ bad.instanceSetBadEnd = 1; /// 99: continued
+ bad.instanceSetBadMiddle = 1; /// 100: continued
+ bad * bad; /// 101: continued
+ bad * bad; /// 102: continued
+ bad * bad; /// 103: continued
+ bad[1] = 1; /// 104: continued
+ bad[1] = 1; /// 105: continued
+ bad[1] = 1; /// 106: continued
+ bad[1] = 1; /// 107: continued
+
+ // This covers tests 108-166
+ bad.method();
+
+ bad.f(() {}); /// 167: compile-time error
+ bad.f(() {}); /// 168: compile-time error
+ bad.f(() {}); /// 169: compile-time error
+ bad.f(() {}); /// 170: compile-time error
+ bad.f(() {}); /// 171: compile-time error
+ bad.f(() {}); /// 172: compile-time error
+ bad.f(() {}); /// 173: compile-time error
+ bad.f(() {}); /// 174: compile-time error
+ bad.f(() {}); /// 175: compile-time error
+ bad.f(() {}); /// 176: compile-time error
+ bad.f(() {}); /// 177: compile-time error
+ bad.f(() {}); /// 178: compile-time error
+ bad.f(() {}); /// 179: compile-time error
+ bad.f(() {}); /// 180: compile-time error
+ bad.f(() {}); /// 181: compile-time error
+ bad.f(() {}); /// 182: compile-time error
+ bad.f(() {}); /// 183: compile-time error
+ bad.f(() {}); /// 184: compile-time error
+ bad.f(() {}); /// 185: compile-time error
+ bad.f(() {}); /// 186: compile-time error
+ bad.f(() {}); /// 187: compile-time error
+ bad.f(() {}); /// 188: compile-time error
+
+ BadEmpty x; /// 189: compile-time error
+ BadStart x; /// 190: compile-time error
+ BadEnd x; /// 191: compile-time error
+ BadMiddle x; /// 192: compile-time error
+ BadPosEmpty x; /// 193: compile-time error
+ BadPosEmpty x; /// 194: compile-time error
+ BadPosEmpty x; /// 195: compile-time error
+ BadPosEmpty x; /// 196: compile-time error
+ BadPosStart x; /// 197: compile-time error
+ BadPosStart x; /// 198: compile-time error
+ BadPosEnd x; /// 199: compile-time error
+ BadPosStart x; /// 200: compile-time error
+ BadPosMiddle x; /// 201: compile-time error
+ BadNamEmpty x; /// 202: compile-time error
+ BadNamEmpty x; /// 203: compile-time error
+ BadNamEmpty x; /// 204: compile-time error
+ BadNamEmpty x; /// 205: compile-time error
+ BadNamStart x; /// 206: compile-time error
+ BadNamStart x; /// 207: compile-time error
+ BadNamEnd x; /// 208: compile-time error
+ BadNamStart x; /// 209: compile-time error
+ BadNamMiddle x; /// 210: compile-time error
+}
diff --git a/tests/language/compile_time_constant_e_test.dart b/tests/language/compile_time_constant_e_test.dart
index 7ab0ea2..77b20e9 100644
--- a/tests/language/compile_time_constant_e_test.dart
+++ b/tests/language/compile_time_constant_e_test.dart
@@ -19,7 +19,6 @@
}
const a1 = const A(99, 100);
-const a1n = const A.n(99, 100);
const a2 = const A.named(z: 99, t: 100);
const a3 = const A.named2(t: 1, z: 2, y: 3, x: 4);
const a4 = const A();
diff --git a/tests/language/disassemble_test.dart b/tests/language/disassemble_test.dart
index 8e53224..bdee5fff 100644
--- a/tests/language/disassemble_test.dart
+++ b/tests/language/disassemble_test.dart
@@ -4,6 +4,7 @@
// Dart test program for testing isolate communication with
// typed objects.
// VMOptions=--disassemble
+// VMOptions=--disassemble --print-variable-descriptors --no-background-compilation
// Tests proper object recognition in disassembler.
diff --git a/tests/language/factory5_test.dart b/tests/language/factory5_test.dart
index ff2013b..6155625 100644
--- a/tests/language/factory5_test.dart
+++ b/tests/language/factory5_test.dart
@@ -6,9 +6,8 @@
factory Link.create() = LinkFactory<T>.create;
}
-class LinkFactory<T> {
+class LinkFactory<T> implements Link<T> {
factory LinkFactory.create() { return null; }
- factory LinkFactory.Foo() = Foo<T>; /// 00: static type warning
}
main() {
diff --git a/tests/language/factory6_test.dart b/tests/language/factory6_test.dart
new file mode 100644
index 0000000..0f998ff
--- /dev/null
+++ b/tests/language/factory6_test.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+
+abstract class Link<T> {
+ factory Link.Foo() = LinkFactory<T>.Foo; /// 00: static type warning
+}
+
+class LinkFactory<T> {
+ factory LinkFactory.Foo() = Foo<T>; /// 00: continued
+}
+
+main() {
+ Expect.throws(() => new Link<int>.Foo()); /// 00: continued
+}
diff --git a/tests/language/generic_local_functions_test.dart b/tests/language/generic_local_functions_test.dart
index 1ec1227..47496a6 100644
--- a/tests/language/generic_local_functions_test.dart
+++ b/tests/language/generic_local_functions_test.dart
@@ -12,13 +12,13 @@
import "package:expect/expect.dart";
// Declare a generic function parameter.
-String f(int g<X, Y>(Map<X, Y> arg)) => null;
+int f(Y g<X, Y>(Map<X, Y> arg, X x)) => g<int, int>(<int, int>{1: 42}, 1);
main() {
// Declare a generic local function
- int h<X extends Y, Y>(Map<X, Y> arg) => null;
+ Y h<X, Y>(Map<X, Y> m, X x) => m[x];
// Pass a generic local function as an argument.
- f(h);
+ Expect.equals(f(h), 42);
// Pass a function expression as an argument.
- f(<X, Y super X>(Map<X, Y> arg) => 42);
+ Expect.equals(f(<X, Y>(Map<X, Y> m, X x) => m[x]), 42);
}
diff --git a/tests/language/language.status b/tests/language/language.status
index 03fd476..61b35c9 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -5,12 +5,6 @@
# This directory contains tests that are intended to show the
# current state of the language.
-# Trailing commas are so far supported by:
-# - The VM (vm, dartium, drt, precompiler+dart_precompiled)
-# Remaining targets still fail on arg_param_trailing_comma_test/none.
-[($compiler != none && $compiler != precompiler) || ($runtime != vm && $runtime != dartium && $runtime != drt && $runtime != dart_precompiled)]
-arg_param_trailing_comma_test/none: Fail # Issue 26644
-
[ ($compiler == none || $compiler == precompiler || $compiler == dart2app || $compiler == dart2appjit) ]
tearoff_constructor_basic_test: Skip # Crashes in checked mode -- hausner investigating
@@ -197,6 +191,9 @@
ct_const2_test: Skip # Incompatible flag: --compile_all
hello_dart_test: Skip # Incompatible flag: --compile_all
+[ $runtime == dart_app ]
+number_identity_test: RuntimeError # Issue 26873
+
[ $compiler == precompiler ]
implicit_closure_test: Skip # Incompatible flag: --use_slow_path
deopt_inlined_function_lazy_test: Skip # Incompatible flag: --deoptimize-alot
@@ -252,6 +249,37 @@
issue23244_test: Skip # Issue #26373
[ $hot_reload ]
-deferred_load_inval_code_test: RuntimeError
-regress_26453_test: Pass, Fail, Crash
-vm/regress_16873_test: Pass, Crash
+bound_closure_equality_test: Pass, Fail # Closure identity
+static_closure_identical_test: Pass, Fail # Closure identity
+cha_deopt1_test: Crash # Requires deferred libraries
+cha_deopt2_test: Crash # Requires deferred libraries
+cha_deopt3_test: Crash # Requires deferred libraries
+deferred_call_empty_before_load_test: Crash # Requires deferred libraries
+deferred_closurize_load_library_test: Crash # Requires deferred libraries
+deferred_constant_list_test: Crash # Requires deferred libraries
+deferred_constraints_constants_test: Crash # Requires deferred libraries
+deferred_constraints_type_annotation_test: Crash # Requires deferred libraries
+deferred_function_type_test: Crash # Requires deferred libraries
+deferred_global_test: Crash # Requires deferred libraries
+deferred_import_core_test: Crash # Requires deferred libraries
+deferred_inlined_test: Crash # Requires deferred libraries
+deferred_inheritance_constraints_test: Crash # Requires deferred libraries
+deferred_load_constants_test: Crash # Requires deferred libraries
+deferred_load_inval_code_test: Crash # Requires deferred libraries
+deferred_load_library_wrong_args_test: Crash # Requires deferred libraries
+deferred_mixin_test: Crash # Requires deferred libraries
+deferred_no_such_method_test: Crash # Requires deferred libraries
+deferred_not_loaded_check_test: Crash # Requires deferred libraries
+deferred_only_constant_test: Crash # Requires deferred libraries
+deferred_optimized_test: Crash # Requires deferred libraries
+deferred_redirecting_factory_test: Crash # Requires deferred libraries
+deferred_regression_22995_test: Crash # Requires deferred libraries
+deferred_shadow_load_library_test: Crash # Requires deferred libraries
+deferred_shared_and_unshared_classes_test: Crash # Requires deferred libraries
+deferred_static_seperate_test: Crash # Requires deferred libraries
+deferred_super_dependency_test: Pass, Crash # Requires deferred libraries
+deferred_type_dependency_test: Crash # Requires deferred libraries
+issue_1751477_test: Crash # Requires deferred libraries
+regress_23408_test: Crash # Requires deferred libraries
+regress_22443_test: Crash # Requires deferred libraries
+tearoff_basic_test: Crash # Requires deferred libraries
diff --git a/tests/language/language_analyzer2.status b/tests/language/language_analyzer2.status
index 63ac9b5..492e396 100644
--- a/tests/language/language_analyzer2.status
+++ b/tests/language/language_analyzer2.status
@@ -85,9 +85,6 @@
# test issue 11579, assignment, no setter
getter_no_setter_test/none: fail
-# test issue 11584, positional arguments cannot be used for named parameters
-compile_time_constant_e_test: fail # Test Issue 11584
-
# test issue 11585, static warning, not negative test
constructor3_negative_test: fail
constructor_call_wrong_argument_count_negative_test: fail
@@ -126,9 +123,6 @@
# test issue 12191, ambiguous import is always warning now
prefix3_negative_test: fail # Issue 12191
-# test issue 12289, assignment in assert statement
-type_error_test: fail # Issue 12289
-
# test issue 12381, It is compile-time error to invoke not existing function
issue11724_test: fail # Issue 12381
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index aec3d55..8001ee7 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -5,6 +5,7 @@
[ $compiler == dart2js ]
getter_setter_in_lib_test: Fail # Issue 23288
method_name_test: Fail # issue 25574
+setter4_test: CompileTimeError # issue 13639
async_star_cancel_while_paused_test: RuntimeError # Issue 22853
tearoff_basic_test: Skip # Tear-off not supported
@@ -102,8 +103,7 @@
ref_before_declaration_test/05: MissingCompileTimeError
ref_before_declaration_test/06: MissingCompileTimeError
-regress_22976_test/01: CompileTimeError # Issue 23132
-regress_22976_test/02: CompileTimeError # Issue 23132
+regress_22976_test: CompileTimeError # Issue 23132
if_null_assignment_behavior_test/13: Crash # Issue 23491
if_null_assignment_behavior_test/14: Crash # Issue 23491
@@ -243,14 +243,6 @@
stack_trace_test: Fail, OK # Stack trace not preserved in minified code.
regress_21795_test: RuntimeError # Issue 12605
-[ $compiler == dart2js && $runtime == d8 && $system == windows ]
-# Detection of d8 runtime does not work on Windows so the runtime result is
-# unreliable; at the time of writing, 32 passed, 31 failed with runtime error.
-# Marked with Pass,RuntimeError to avoid undetected compile-time failures.
-*deferred*: Pass,RuntimeError # Issue 17458
-cha_deopt*: Pass,RuntimeError # Issue 17458
-regress_22443_test: Pass,RuntimeError # Issue 17458
-
[ $compiler == dart2js && $cps_ir == false ]
accessor_conflict_export2_test: Crash # Issue 25626
accessor_conflict_export_test: Crash # Issue 25626
@@ -337,3 +329,9 @@
[ $compiler == dart2js && $cps_ir && $checked ]
*: Skip # `assert` not implemented
+
+[ $compiler == dart2js && $host_checked ]
+regress_26855_test/1: Crash # Issue 26867
+regress_26855_test/2: Crash # Issue 26867
+regress_26855_test/3: Crash # Issue 26867
+regress_26855_test/4: Crash # Issue 26867
diff --git a/tests/language/regress_22976_test.dart b/tests/language/regress_22976_test.dart
index 67d6957..ea29319 100644
--- a/tests/language/regress_22976_test.dart
+++ b/tests/language/regress_22976_test.dart
@@ -9,6 +9,8 @@
class C<S, T> implements B<S>, A<T> {}
main() {
- A<int> a0 = new C<int, String>(); /// 01: ok
- A<int> a1 = new C<String, int>(); /// 02: ok
+ C<int, String> c1 = new C<int, String>();
+ C<String, int> c2 = new C<String, int>();
+ A<int> a0 = c1; /// 01: ok
+ A<int> a1 = c2; /// 02: ok
}
diff --git a/tests/language/regress_26855_test.dart b/tests/language/regress_26855_test.dart
new file mode 100644
index 0000000..3d6c963
--- /dev/null
+++ b/tests/language/regress_26855_test.dart
@@ -0,0 +1,26 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+void f0(this.x) {} /// 0: compile-time error
+
+void f1(int g(this.x)) {} /// 1: compile-time error
+
+void f2(int g(int this.x)) {} /// 2: compile-time error
+
+class C {
+ C();
+ var x;
+ void f3(int g(this.x)) {} /// 3: compile-time error
+ C.f4(int g(this.x)); /// 4: compile-time error
+}
+
+main() {
+ f0(null); /// 0: continued
+ f1(null); /// 1: continued
+ f2(null); /// 2: continued
+ C c = new C();
+ c.f3(null); /// 3: continued
+ new C.f4(null); /// 4: continued
+}
+
diff --git a/tests/language/setter4_test.dart b/tests/language/setter4_test.dart
index 8428a7a..0fea7fe 100644
--- a/tests/language/setter4_test.dart
+++ b/tests/language/setter4_test.dart
@@ -4,14 +4,23 @@
// Dart test to catch error reporting bugs in class fields declarations.
// Should be an error because we have a setter overriding a function name.
+import 'package:expect/expect.dart';
+
class A {
+ int i;
int a() {
return 1;
}
void set a(var val) {
- int i = val;
+ i = val;
}
}
main() {
+ var a = new A();
+ Expect.isNull(a.i);
+ Expect.equals(a.a(), 1);
+ a.a = 2;
+ Expect.equals(a.a(), 1);
+ Expect.equals(a.i, 2);
}
diff --git a/tests/lib/analyzer/analyze_library.status b/tests/lib/analyzer/analyze_library.status
index b86abdc..98b521c 100644
--- a/tests/lib/analyzer/analyze_library.status
+++ b/tests/lib/analyzer/analyze_library.status
@@ -9,6 +9,7 @@
lib/html/html_common/html_common_dart2js: CompileTimeError # Issue 16522
lib/indexed_db/dart2js/indexed_db_dart2js: CompileTimeError # Issue 16522
lib/js/dart2js/js_dart2js: CompileTimeError # Issue 16522
+lib/js_util/dart2js/js_util_dart2js: CompileTimeError # Issue 16522
lib/svg/dart2js/svg_dart2js: CompileTimeError # Issue 16522
lib/typed_data/dart2js/native_typed_data_dart2js: CompileTimeError # Issue 16522
lib/typed_data/dart2js/typed_data_dart2js: CompileTimeError # Issue 16522
@@ -25,4 +26,5 @@
lib/web_audio/dartium/web_audio_dartium: StaticWarning # Issue 21647
lib/svg/dartium/svg_dartium: StaticWarning # Issue 21647
lib/_blink/dartium/_blink_dartium: StaticWarning # Undefined Creates and Returns classes
-lib/js/dartium/js_dartium: StaticWarning # Undefined Creates and Returns classes
\ No newline at end of file
+lib/js/dartium/js_dartium: StaticWarning # Undefined Creates and Returns classes
+lib/js_util/dartium/js_util_dartium: StaticWarning # Issue 21647
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index 8d3dcee..37f4f1e 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -375,6 +375,28 @@
mirrors/accessor_cache_overflow_test: Skip
[ $hot_reload ]
-convert/chunked_conversion_utf88_test: Pass, Timeout
-convert/streamed_conversion_json_utf8_decode_test: Fail, Crash
-convert/utf85_test: Fail, Crash
+async/stream_transformer_test: Pass, Fail # Closure identity
+mirrors/closurization_equivalence_test: SkipByDesign # Method equality
+mirrors/fake_function_with_call_test: SkipByDesign # Method equality
+
+async/multiple_timer_test: Pass, Fail # Timing related
+
+mirrors/generic_bounded_by_type_parameter_test/02: Fail # Type equality - Issue 26869
+mirrors/typedef_reflected_type_test/01: Fail # Type equality - Issue 26869
+mirrors/generic_bounded_test/02: Fail # Type equality - Issue 26869
+mirrors/generic_bounded_by_type_parameter_test/02: Fail # Type equality - Issue 26869
+mirrors/typedef_reflected_type_test/01: Fail # Type equality - Issue 26869
+
+mirrors/library_enumeration_deferred_loading_test: Crash # Deferred loading
+mirrors/library_imports_deferred_test: Crash # Deferred loading
+mirrors/library_import_deferred_loading_test: Crash # Deferred loading
+mirrors/typedef_deferred_library_test: Crash # Deferred loading
+mirrors/deferred_mirrors_update_test: Crash # Deferred loading
+mirrors/deferred_mirrors_metadata_test: Crash # Deferred loading
+mirrors/deferred_mirrors_metatarget_test: Crash # Deferred loading
+mirrors/load_library_test: Crash # Deferred loading
+
+mirrors/metadata_scope_test/none: Fail # Constant equality - Issue 26868
+
+typed_data/float32x4_unbox_regress_test: Pass, Crash # Issue 26888
+math/double_pow_test: Pass, Fail # Issue 26887
diff --git a/tests/standalone/io/http_basic_test.dart b/tests/standalone/io/http_basic_test.dart
index f30a32b..266dd8f 100644
--- a/tests/standalone/io/http_basic_test.dart
+++ b/tests/standalone/io/http_basic_test.dart
@@ -2,10 +2,10 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
//
-// VMOptions=
-// VMOptions=--short_socket_read
-// VMOptions=--short_socket_write
-// VMOptions=--short_socket_read --short_socket_write
+// VMOptions=--trace_shutdown
+// VMOptions=--trace_shutdown --short_socket_read
+// VMOptions=--trace_shutdown --short_socket_write
+// VMOptions=--trace_shutdown --short_socket_read --short_socket_write
import "package:expect/expect.dart";
import "dart:isolate";
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index bcad73f..ff14249 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -319,13 +319,18 @@
oom_error_stacktrace_test: Skip # Issue #26377
out_of_memory_test: Skip # Issue #26377
-[ $runtime == dart_precompiled ]
+[ $runtime == vm || $runtime == dart_app || $runtime == dart_precompiled ]
deferred_transitive_import_error_test: Skip # Contains intentional errors.
[ $hot_reload ]
-io/bytes_builder_test: RuntimeError
-io/file_input_stream_test: Crash
-io/file_test: Pass, Crash
-io/web_socket_protocol_processor_test: Pass, Crash
-map_insert_remove_oom_test: Crash
-priority_queue_stress_test: Crash
+deferred_transitive_import_error_test: Crash # Uses deferred imports.
+package/*: SkipByDesign # Launches VMs in interesting ways.
+
+[ $builder_tag == no_ipv6 ]
+io/http_bind_test: Skip
+io/raw_datagram_socket_test: Skip
+io/socket_source_address_test: Skip
+io/socket_bind_test: Skip
+io/http_proxy_advanced_test: Skip
+io/http_ipv6_test: Skip
+io/socket_ipv6_test: Skip
diff --git a/tests/utils/dummy_compiler_test.dart b/tests/utils/dummy_compiler_test.dart
index 608e099..c8becb3 100644
--- a/tests/utils/dummy_compiler_test.dart
+++ b/tests/utils/dummy_compiler_test.dart
@@ -1,8 +1,6 @@
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-// VMOptions=
-// VMOptions=--print-object-histogram
// Smoke test of the dart2js compiler API.
library dummy_compiler;
diff --git a/tests/utils/utils.status b/tests/utils/utils.status
index b1dc829..66ec0d2 100644
--- a/tests/utils/utils.status
+++ b/tests/utils/utils.status
@@ -20,3 +20,7 @@
[ $compiler == dart2js && $cps_ir && $host_checked ]
dummy_compiler_test: Crash # Issue 24485
recursive_import_test: Crash # Issue 24485
+
+[ $hot_reload ]
+recursive_import_test: Skip # Running dart2js under frequent reloads is slow.
+dummy_compiler_test: Skip # Running dart2js under frequent reloads is slow.
diff --git a/tools/VERSION b/tools/VERSION
index bc466cc..8dbdf92 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -25,7 +25,7 @@
#
CHANNEL dev
MAJOR 1
-MINOR 18
+MINOR 19
PATCH 0
-PRERELEASE 4
-PRERELEASE_PATCH 4
+PRERELEASE 0
+PRERELEASE_PATCH 0
diff --git a/tools/build.py b/tools/build.py
index 1f9eb8b..055b19a 100755
--- a/tools/build.py
+++ b/tools/build.py
@@ -88,7 +88,7 @@
def ProcessOptions(options, args):
if options.arch == 'all':
- options.arch = 'ia32,x64,simarm,simarm64,simmips,simdbc'
+ options.arch = 'ia32,x64,simarm,simarm64,simmips,simdbc64'
if options.mode == 'all':
options.mode = 'debug,release,product'
if options.os == 'all':
diff --git a/tools/create_sdk.py b/tools/create_sdk.py
index 65f585e..dad929b 100755
--- a/tools/create_sdk.py
+++ b/tools/create_sdk.py
@@ -59,6 +59,7 @@
# ......io/
# ......isolate/
# ......js/
+# ......js_util/
# ......math/
# ......mirrors/
# ......typed_data/
@@ -254,7 +255,7 @@
join('html', 'dart2js'), join('html', 'dartium'),
join('html', 'html_common'),
join('indexed_db', 'dart2js'), join('indexed_db', 'dartium'),
- 'js', 'math', 'mirrors', 'profiler', 'typed_data',
+ 'js', 'js_util', 'math', 'mirrors', 'profiler', 'typed_data',
join('svg', 'dart2js'), join('svg', 'dartium'),
join('web_audio', 'dart2js'), join('web_audio', 'dartium'),
join('web_gl', 'dart2js'), join('web_gl', 'dartium'),
diff --git a/tools/dartium/generate_patches.sh b/tools/dartium/generate_patches.sh
index 40dc895..11c73b8 100755
--- a/tools/dartium/generate_patches.sh
+++ b/tools/dartium/generate_patches.sh
@@ -26,17 +26,17 @@
# build Dartium, run this script and build Dartium again with the newly
# generated patches.
-LOCATION_DARTIUM="../../../out/Release"
-DARTIUM="$LOCATION_DARTIUM"
+if [[ "$1" != "" ]] ; then
+ DARTIUM="$1"
+else
+ LOCATION_DARTIUM="../../../out/Release"
+ DARTIUM="$LOCATION_DARTIUM"
+fi
DART_APP_LOCATION="file://"$PWD"/generate_app/generate_cached_patches.html"
DARTIUM_ARGS=" --user-data-dir=out --disable-web-security --no-sandbox --enable-blink-features=dartGenCachedPatches"
CACHED_PATCHES_FILE=""$PWD"/../../sdk/lib/js/dartium/cached_patches.dart"
-if [[ "$1" != "" ]] ; then
- DARTIM="$1"
-fi
-
cmd=""$DARTIUM"/chrome "$DARTIUM_ARGS" "$DART_APP_LOCATION" |
(sed -n '/START_OF_CACHED_PATCHES/,/END_OF_CACHED_PATCHES/p') > "$CACHED_PATCHES_FILE""
diff --git a/tools/deps/dartium.deps/DEPS b/tools/deps/dartium.deps/DEPS
index a12cdc3..9c2c9a4 100644
--- a/tools/deps/dartium.deps/DEPS
+++ b/tools/deps/dartium.deps/DEPS
@@ -9,7 +9,7 @@
vars.update({
"dartium_chromium_commit": "67a7ba9669f7bb0300ef35085d4e6bb98b1966cc",
- "dartium_webkit_commit": "d3db7d1b53979ca91cbf8f3117971f49d0fddf13",
+ "dartium_webkit_commit": "6d435325ef16ceb54f23f5ec6414650ce5ef79ef",
"chromium_base_revision": "338390",
# We use mirrors of all github repos to guarantee reproducibility and
diff --git a/tools/dom/scripts/dartdomgenerator.py b/tools/dom/scripts/dartdomgenerator.py
index c0315df2..6459e45 100755
--- a/tools/dom/scripts/dartdomgenerator.py
+++ b/tools/dom/scripts/dartdomgenerator.py
@@ -287,6 +287,9 @@
parser.add_option('--gen-interop', dest='dart_js_interop',
action='store_true', default=False,
help='Use Javascript objects (dart:js) accessing the DOM in _blink')
+ parser.add_option('--no-cached-patches', dest='no_cached_patches',
+ action='store_true', default=False,
+ help='Do not generate the sdk/lib/js/cached_patches.dart file')
(options, args) = parser.parse_args()
@@ -346,13 +349,14 @@
os.path.join(dartium_output_dir, '%s_dartium.dart' % library_name),
os.path.join('..', '..', '..', 'sdk', 'lib', library_name, 'dartium'))
- # Blow away the cached_patches.dart needs to be re-generated for Dartium
- # see tools/dartium/generate_patches.sh
- cached_patches_filename = os.path.join('..', '..', '..', 'sdk', 'lib', 'js', 'dartium',
- 'cached_patches.dart')
- cached_patches = open(cached_patches_filename, 'w')
- cached_patches.write(CACHED_PATCHES);
- cached_patches.close()
+ if (not(options.no_cached_patches)):
+ # Blow away the cached_patches.dart needs to be re-generated for Dartium
+ # see tools/dartium/generate_patches.sh
+ cached_patches_filename = os.path.join('..', '..', '..', 'sdk', 'lib', 'js', 'dartium',
+ 'cached_patches.dart')
+ cached_patches = open(cached_patches_filename, 'w')
+ cached_patches.write(CACHED_PATCHES);
+ cached_patches.close()
if '_blink' in systems:
_logger.info('Generating dartium _blink file.')
diff --git a/tools/dom/scripts/generator.py b/tools/dom/scripts/generator.py
index db47521..9e15a96 100644
--- a/tools/dom/scripts/generator.py
+++ b/tools/dom/scripts/generator.py
@@ -321,14 +321,47 @@
'TransitionEvent': 'TransitionEvent,WebKitTransitionEvent',
- 'WebGLLoseContext': 'WebGLLoseContext,WebGLExtensionLoseContext',
-
'CSSKeyframeRule':
'CSSKeyframeRule,MozCSSKeyframeRule,WebKitCSSKeyframeRule',
'CSSKeyframesRule':
'CSSKeyframesRule,MozCSSKeyframesRule,WebKitCSSKeyframesRule',
+ # webgl extensions are sometimes named directly after the getExtension
+ # parameter (e.g on Firefox).
+
+ 'ANGLEInstancedArrays': 'ANGLEInstancedArrays,ANGLE_instanced_arrays',
+ 'EXTsRGB': 'EXTsRGB,EXT_sRGB',
+ 'EXTBlendMinMax': 'EXTBlendMinMax,EXT_blend_minmax',
+ 'EXTFragDepth': 'EXTFragDepth,EXT_frag_depth',
+ 'EXTShaderTextureLOD': 'EXTShaderTextureLOD,EXT_shader_texture_lod',
+ 'EXTTextureFilterAnisotropic':
+ 'EXTTextureFilterAnisotropic,EXT_texture_filter_anisotropic',
+ 'OESElementIndexUint': 'OESElementIndexUint,OES_element_index_uint',
+ 'OESStandardDerivatives': 'OESStandardDerivatives,OES_standard_derivatives',
+ 'OESTextureFloat': 'OESTextureFloat,OES_texture_float',
+ 'OESTextureFloatLinear': 'OESTextureFloatLinear,OES_texture_float_linear',
+ 'OESTextureHalfFloat': 'OESTextureHalfFloat,OES_texture_half_float',
+ 'OESTextureHalfFloatLinear':
+ 'OESTextureHalfFloatLinear,OES_texture_half_float_linear',
+ 'OESVertexArrayObject':
+ 'OESVertexArrayObject,OES_vertex_array_object',
+ 'WebGLCompressedTextureATC':
+ 'WebGLCompressedTextureATC,WEBGL_compressed_texture_atc',
+ 'WebGLCompressedTextureETC1':
+ 'WebGLCompressedTextureETC1,WEBGL_compressed_texture_etc1',
+ 'WebGLCompressedTexturePVRTC':
+ 'WebGLCompressedTexturePVRTC,WEBGL_compressed_texture_pvrtc',
+ 'WebGLCompressedTextureS3TC':
+ 'WebGLCompressedTextureS3TC,WEBGL_compressed_texture_s3tc',
+ 'WebGLDebugRendererInfo': 'WebGLDebugRendererInfo,WEBGL_debug_renderer_info',
+ 'WebGLDebugShaders': 'WebGLDebugShaders,WEBGL_debug_shaders',
+ 'WebGLDepthTexture': 'WebGLDepthTexture,WEBGL_depth_texture',
+ 'WebGLDrawBuffers': 'WebGLDrawBuffers,WEBGL_draw_buffers',
+ 'WebGLLoseContext':
+ 'WebGLLoseContext,WebGLExtensionLoseContext,WEBGL_lose_context',
+
+
}, dart2jsOnly=True)
def IsRegisteredType(type_name):
@@ -698,7 +731,7 @@
# Events fired need use a JSFunction not a anonymous closure to
# insure the event can really be removed.
parameters.append('js.allowInterop(%s)' % p.name)
-# These commented out cases don't actually generate any code.
+# These commented out cases don't actually generate any code.
# elif dart_js_interop and type_id == 'FontFaceSetForEachCallback':
# forEach is supported in the DOM for FontFaceSet as it iterates
# over the Javascript Object the callback parameters are also
diff --git a/tools/dom/scripts/go.sh b/tools/dom/scripts/go.sh
index a830a9b..99c4e72 100755
--- a/tools/dom/scripts/go.sh
+++ b/tools/dom/scripts/go.sh
@@ -20,6 +20,12 @@
#
# ./go.sh dart2js,htmldartium
#
+# To re-gen all sdk/lib files (outside of a Dartium enlistment the file
+# 'sdk/lib/js/cached_patches.dart' might not need to be generated). To run
+# go.sh w/o the patches files used --no-cached-patches switch e.g.,
+#
+# ./go.sh --no-cached-patches
+#
# The following gives a picture of the changes due to 'work'
#
# git checkout master # select client without changes
@@ -33,8 +39,20 @@
SYSTEMS="$ALLSYSTEMS"
if [[ "$1" != "" ]] ; then
- SYSTEMS="$1"
+ if [[ "$1" =~ ^-- ]]; then
+ ARG_OPTION="$1"
+ else
+ SYSTEMS="$1"
+ fi
+fi
+
+if [[ "$2" != "" ]] ; then
+ if [[ "$2" =~ ^-- ]]; then
+ ARG_OPTION="$2"
+ else
+ SYSTEMS="$2"
+ fi
fi
reset && \
-./dartdomgenerator.py --systems="$SYSTEMS" --logging=40 --update-dom-metadata --gen-interop
+./dartdomgenerator.py --systems="$SYSTEMS" --logging=40 --update-dom-metadata --gen-interop "$ARG_OPTION"
diff --git a/tools/fuchsia_link.py b/tools/fuchsia_link.py
index c3c537b..74936b0 100755
--- a/tools/fuchsia_link.py
+++ b/tools/fuchsia_link.py
@@ -105,8 +105,8 @@
if link_target == 'target':
# Add and remove libraries as listed in configurations_fuchsia.gypi
- libs_to_rm = ['-lrt', '-lpthread', '-ldl']
- libs_to_add = [fuchsia_libgcc, '-lc',]
+ libs_to_rm = ['-lrt', '-lpthread']
+ libs_to_add = [fuchsia_libgcc, '-lc', '-ldl', '-lm']
# Add crtn_fuchsia to end if we are linking an executable.
if link_type == 'executable':
diff --git a/tools/gyp/configurations_msvs.gypi b/tools/gyp/configurations_msvs.gypi
index 68a08c5..10e3c47 100644
--- a/tools/gyp/configurations_msvs.gypi
+++ b/tools/gyp/configurations_msvs.gypi
@@ -116,6 +116,7 @@
'Optimization': '2',
'InlineFunctionExpansion': '2',
'EnableIntrinsicFunctions': 'true',
+ 'EnableFunctionLevelLinking': 'true',
'FavorSizeOrSpeed': '0',
'ExceptionHandling': '0',
'RuntimeTypeInfo': 'false',
diff --git a/tools/gypi_to_gn.py b/tools/gypi_to_gn.py
old mode 100644
new mode 100755
index a107f94..1aa092c
--- a/tools/gypi_to_gn.py
+++ b/tools/gypi_to_gn.py
@@ -1,3 +1,4 @@
+#!/usr/bin/env python
# Copyright 2014 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
diff --git a/tools/make_version.py b/tools/make_version.py
old mode 100644
new mode 100755
index cf96fe2..157c955
--- a/tools/make_version.py
+++ b/tools/make_version.py
@@ -1,3 +1,4 @@
+#!/usr/bin/env python
# Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
diff --git a/tools/testing/dart/compiler_configuration.dart b/tools/testing/dart/compiler_configuration.dart
index 76a0e55..1747731 100644
--- a/tools/testing/dart/compiler_configuration.dart
+++ b/tools/testing/dart/compiler_configuration.dart
@@ -180,10 +180,6 @@
}
if (hotReload) {
args.add('--hot-reload-test-mode');
- // Remove the following once known bugs with background compilation
- // and OSR are fixed.
- args.add('--no-background-compilation');
- args.add('--no-osr');
}
return args
..addAll(vmOptions)
diff --git a/tools/testing/dart/multitest.dart b/tools/testing/dart/multitest.dart
index d39bc9a..eb85c1a 100644
--- a/tools/testing/dart/multitest.dart
+++ b/tools/testing/dart/multitest.dart
@@ -221,7 +221,11 @@
}
Future doMultitest(
- Path filePath, String outputDir, Path suiteDir, CreateTest doTest) {
+ Path filePath,
+ String outputDir,
+ Path suiteDir,
+ CreateTest doTest,
+ bool hotReload) {
void writeFile(String filepath, String content) {
final File file = new File(filepath);
@@ -273,6 +277,13 @@
bool isNegativeIfChecked = outcome.contains('dynamic type error');
bool hasCompileErrorIfChecked =
outcome.contains('checked mode compile-time error');
+ if (hotReload) {
+ if (hasCompileError || hasCompileErrorIfChecked) {
+ // Running a test that expects a compilation error with hot reloading
+ // is redundant with a regular run of the test.
+ continue;
+ }
+ }
doTest(multitestFilename, filePath, hasCompileError, hasRuntimeErrors,
isNegativeIfChecked: isNegativeIfChecked,
hasCompileErrorIfChecked: hasCompileErrorIfChecked,
diff --git a/tools/testing/dart/test_options.dart b/tools/testing/dart/test_options.dart
index da2c5d0..ee9c107 100644
--- a/tools/testing/dart/test_options.dart
+++ b/tools/testing/dart/test_options.dart
@@ -703,7 +703,7 @@
List<Map> _expandConfigurations(Map configuration) {
// Expand the pseudo-values such as 'all'.
if (configuration['arch'] == 'all') {
- configuration['arch'] = 'ia32,x64,simarm,simarm64,simmips,simdbc';
+ configuration['arch'] = 'ia32,x64,simarm,simarm64,simmips,simdbc64';
}
if (configuration['mode'] == 'all') {
configuration['mode'] = 'debug,release,product';
diff --git a/tools/testing/dart/test_suite.dart b/tools/testing/dart/test_suite.dart
index c73dc7c..5dfbd39 100644
--- a/tools/testing/dart/test_suite.dart
+++ b/tools/testing/dart/test_suite.dart
@@ -300,6 +300,15 @@
return;
}
+ if (configuration['hot_reload']) {
+ // Handle reload special cases.
+ if (expectations.contains(Expectation.COMPILETIME_ERROR)) {
+ // Running a test that expects a compilation error with hot reloading
+ // is redundant with a regular run of the test.
+ return;
+ }
+ }
+
// Update Summary report
if (configuration['report']) {
if (testCase.expectCompileError &&
@@ -837,7 +846,11 @@
CreateTest createTestCase = makeTestCaseCreator(optionsFromFile);
if (optionsFromFile['isMultitest']) {
- group.add(doMultitest(filePath, buildDir, suiteDir, createTestCase));
+ group.add(doMultitest(filePath,
+ buildDir,
+ suiteDir,
+ createTestCase,
+ configuration['hot_reload']));
} else {
createTestCase(filePath, filePath, optionsFromFile['hasCompileError'],
optionsFromFile['hasRuntimeError'],