Version 1.1.0-dev.5.0
svn merge -r 31107:31316 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
git-svn-id: http://dart.googlecode.com/svn/trunk@31329 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/pkg/analyzer/lib/src/services/formatter_impl.dart b/pkg/analyzer/lib/src/services/formatter_impl.dart
index f54675a..2bae3ec 100644
--- a/pkg/analyzer/lib/src/services/formatter_impl.dart
+++ b/pkg/analyzer/lib/src/services/formatter_impl.dart
@@ -352,6 +352,10 @@
/// A flag to indicate that a newline should be emitted before the next token.
bool needsNewline = false;
+ /// A flag to indicate that user introduced newlines should be emitted before
+ /// the next token.
+ bool preserveNewlines = false;
+
/// A counter for spaces that should be emitted preceding the next token.
int leadingSpaces = 0;
@@ -422,8 +426,10 @@
visit(node.leftHandSide);
space();
token(node.operator);
- space();
- visit(node.rightHandSide);
+ allowContinuedLines((){
+ space();
+ visit(node.rightHandSide);
+ });
}
visitBinaryExpression(BinaryExpression node) {
@@ -460,7 +466,8 @@
visitCascadeExpression(CascadeExpression node) {
visit(node.target);
indent(2);
- visitNodes(node.cascadeSections);
+ newlines();
+ visitNodes(node.cascadeSections, separatedBy: newlines);
unindent(2);
}
@@ -488,15 +495,18 @@
}
visitClassDeclaration(ClassDeclaration node) {
+ preserveLeadingNewlines();
modifier(node.abstractKeyword);
token(node.classKeyword);
space();
visit(node.name);
- visit(node.typeParameters);
- visitNode(node.extendsClause, precededBy: space);
- visitNode(node.withClause, precededBy: space);
- visitNode(node.implementsClause, precededBy: space);
- space();
+ allowContinuedLines((){
+ visit(node.typeParameters);
+ visitNode(node.extendsClause, precededBy: space);
+ visitNode(node.withClause, precededBy: space);
+ visitNode(node.implementsClause, precededBy: space);
+ space();
+ });
token(node.leftBracket);
indent();
visitNodes(node.members, precededBy: newlines, separatedBy: newlines);
@@ -543,6 +553,8 @@
visitNodes(node.declarations, separatedBy: newlines);
+ preserveLeadingNewlines();
+
// Handle trailing whitespace
token(node.endToken /* EOF */);
@@ -554,12 +566,14 @@
visit(node.condition);
space();
token(node.question);
- space();
- visit(node.thenExpression);
- space();
- token(node.colon);
- space();
- visit(node.elseExpression);
+ allowContinuedLines((){
+ space();
+ visit(node.thenExpression);
+ space();
+ token(node.colon);
+ space();
+ visit(node.elseExpression);
+ });
}
visitConstructorDeclaration(ConstructorDeclaration node) {
@@ -663,8 +677,10 @@
token(node.whileKeyword);
space();
token(node.leftParenthesis);
- visit(node.condition);
- token(node.rightParenthesis);
+ allowContinuedLines((){
+ visit(node.condition);
+ token(node.rightParenthesis);
+ });
token(node.semicolon);
}
@@ -684,7 +700,9 @@
token(node.keyword);
space();
visit(node.uri);
- visitNodes(node.combinators, precededBy: space, separatedBy: space);
+ allowContinuedLines((){
+ visitNodes(node.combinators, precededBy: space, separatedBy: space);
+ });
token(node.semicolon);
}
@@ -791,6 +809,7 @@
}
visitFunctionDeclaration(FunctionDeclaration node) {
+ preserveLeadingNewlines();
visitNode(node.returnType, followedBy: space);
token(node.propertyKeyword, followedBy: space);
visit(node.name);
@@ -837,10 +856,12 @@
visitIfStatement(IfStatement node) {
var hasElse = node.elseStatement != null;
token(node.ifKeyword);
- space();
- token(node.leftParenthesis);
- visit(node.condition);
- token(node.rightParenthesis);
+ allowContinuedLines((){
+ space();
+ token(node.leftParenthesis);
+ visit(node.condition);
+ token(node.rightParenthesis);
+ });
space();
if (hasElse) {
printAsBlock(node.thenStatement);
@@ -864,8 +885,10 @@
space();
visit(node.uri);
token(node.asToken, precededBy: space, followedBy: space);
- visit(node.prefix);
- visitNodes(node.combinators, precededBy: space, separatedBy: space);
+ allowContinuedLines((){
+ visit(node.prefix);
+ visitNodes(node.combinators, precededBy: space, separatedBy: space);
+ });
token(node.semicolon);
}
@@ -951,10 +974,12 @@
modifier(node.constKeyword);
visitNode(node.typeArguments, followedBy: space);
token(node.leftBracket);
+ newlines();
indent();
- visitCommaSeparatedNodes(node.entries);
+ visitCommaSeparatedNodes(node.entries, followedBy: newlines);
optionalTrailingComma(node.rightBracket);
unindent();
+ newlines();
token(node.rightBracket);
}
@@ -1073,9 +1098,11 @@
token(node.semicolon);
} else {
token(node.keyword);
- space();
- expression.accept(this);
- token(node.semicolon);
+ allowContinuedLines((){
+ space();
+ expression.accept(this);
+ token(node.semicolon);
+ });
}
}
@@ -1209,8 +1236,16 @@
if (node.initializer != null) {
space();
token(node.equals);
- space();
- visit(node.initializer);
+ var initializer = node.initializer;
+ if (initializer is! ListLiteral && initializer is! MapLiteral) {
+ allowContinuedLines((){
+ space();
+ visit(initializer);
+ });
+ } else {
+ space();
+ visit(initializer);
+ }
}
}
@@ -1229,8 +1264,10 @@
token(node.keyword);
space();
token(node.leftParenthesis);
- visit(node.condition);
- token(node.rightParenthesis);
+ allowContinuedLines((){
+ visit(node.condition);
+ token(node.rightParenthesis);
+ });
if (node.body is! EmptyStatement) {
space();
}
@@ -1283,7 +1320,11 @@
}
/// Visit a comma-separated list of [nodes] if not null.
- visitCommaSeparatedNodes(NodeList<ASTNode> nodes) {
+ visitCommaSeparatedNodes(NodeList<ASTNode> nodes, {followedBy(): null}) {
+ //TODO(pquitslund): handle this more neatly
+ if (followedBy == null) {
+ followedBy = space;
+ }
if (nodes != null) {
var size = nodes.length;
if (size > 0) {
@@ -1293,7 +1334,7 @@
if (i > 0) {
var comma = node.beginToken.previous;
token(comma);
- space();
+ followedBy();
}
node.accept(this);
}
@@ -1316,6 +1357,12 @@
}
}
+ /// Allow [code] to be continued across lines.
+ allowContinuedLines(code()) {
+ //TODO(pquitslund): add before
+ code();
+ //TODO(pquitslund): add after
+ }
/// Emit the given [modifier] if it's non null, followed by non-breaking
/// whitespace.
@@ -1336,6 +1383,12 @@
}
}
+ /// Indicate that user introduced newlines should be emitted before the next
+ /// token.
+ preserveLeadingNewlines() {
+ preserveNewlines = true;
+ }
+
token(Token token, {precededBy(), followedBy(), int minNewlines: 0}) {
if (token != null) {
if (needsNewline) {
@@ -1446,8 +1499,12 @@
currentToken = comment != null ? comment : token;
}
- var lines = max(min, countNewlinesBetween(previousToken, currentToken));
- writer.newlines(lines);
+ var lines = 0;
+ if (needsNewline || preserveNewlines) {
+ lines = max(min, countNewlinesBetween(previousToken, currentToken));
+ preserveNewlines = false;
+ }
+ emitNewlines(lines);
previousToken =
currentToken.previous != null ? currentToken.previous : token.previous;
@@ -1459,7 +1516,7 @@
var nextToken = comment.next != null ? comment.next : token;
var newlines = calculateNewlinesBetweenComments(comment, nextToken);
if (newlines > 0) {
- writer.newlines(newlines);
+ emitNewlines(newlines);
lines += newlines;
} else {
var spaces = countSpacesBetween(comment, nextToken);
@@ -1476,6 +1533,10 @@
return lines;
}
+ void emitNewlines(lines) {
+ writer.newlines(lines);
+ }
+
ensureTrailingNewline() {
if (writer.lastToken is! NewlineToken) {
writer.newline();
diff --git a/pkg/analyzer/test/services/data/cu_tests.data b/pkg/analyzer/test/services/data/cu_tests.data
new file mode 100644
index 0000000..6e1547a
--- /dev/null
+++ b/pkg/analyzer/test/services/data/cu_tests.data
@@ -0,0 +1,8 @@
+>>>
+class
+A
+{
+}
+<<<
+class A {
+}
\ No newline at end of file
diff --git a/pkg/analyzer/test/services/data/stmt_tests.data b/pkg/analyzer/test/services/data/stmt_tests.data
new file mode 100644
index 0000000..ca6096c
--- /dev/null
+++ b/pkg/analyzer/test/services/data/stmt_tests.data
@@ -0,0 +1,27 @@
+>>>
+if (x &&
+ y) {
+ print('!');
+}
+<<<
+if (x && y) {
+ print('!');
+}
+>>>
+for (var a=0; a<100; ++a) { print(a); }
+<<<
+for (var a = 0; a < 100; ++a) {
+ print(a);
+}
+>>>
+for(
+var a=0;
+a<100;
+++a)
+{
+print(a);
+}
+<<<
+for (var a = 0; a < 100; ++a) {
+ print(a);
+}
\ No newline at end of file
diff --git a/pkg/analyzer/test/services/formatter_test.dart b/pkg/analyzer/test/services/formatter_test.dart
index 61e4356..3d26066 100644
--- a/pkg/analyzer/test/services/formatter_test.dart
+++ b/pkg/analyzer/test/services/formatter_test.dart
@@ -2,6 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+//import 'dart:io';
+
import 'package:unittest/unittest.dart';
import 'package:analyzer/src/generated/java_core.dart' show CharSequence;
@@ -11,6 +13,22 @@
main() {
+//TODO(pquitslund): disabled pending build investigation
+
+// /// Data driven statement tests
+// group('stmt_tests.data', () {
+// runTests(new File('data/stmt_tests.data'), (input, expectedOutput) {
+// expect(formatStatement(input) + '\n', equals(expectedOutput));
+// });
+// });
+//
+// /// Data driven compilation unit tests
+// group('cu_tests.data', () {
+// runTests(new File('data/cu_tests.data'), (input, expectedOutput) {
+// expectCUFormatsTo(input, expectedOutput);
+// });
+// });
+
/// Formatter tests
group('formatter', () {
@@ -566,7 +584,10 @@
test('CU - comments (11)', () {
expectCUFormatsTo(
'var m = {1: 2 /* bang */, 3: 4};\n',
- 'var m = {1: 2 /* bang */, 3: 4};\n'
+ 'var m = {\n'
+ ' 1: 2 /* bang */,\n'
+ ' 3: 4\n'
+ '};\n'
);
});
@@ -787,10 +808,7 @@
'1,\n'
'2,\n'
'];',
- 'var l = [\n'
- ' 1,\n'
- ' 2,\n'
- '];'
+ 'var l = [1, 2,];'
);
//Dangling ','
expectStmtFormatsTo(
@@ -802,24 +820,29 @@
test('stmt (maps)', () {
expectStmtFormatsTo(
'var map = const {"foo": "bar", "fuz": null};',
- 'var map = const {"foo": "bar", "fuz": null};'
+ 'var map = const {\n'
+ ' "foo": "bar",\n'
+ ' "fuz": null\n'
+ '};'
);
expectStmtFormatsTo(
'var map = {\n'
'"foo": "bar",\n'
- '"bar": "baz"'
+ '"bar": "baz"\n'
'};',
'var map = {\n'
' "foo": "bar",\n'
- ' "bar": "baz"'
+ ' "bar": "baz"\n'
'};'
);
//Dangling ','
expectStmtFormatsTo(
'var map = {"foo": "bar",};',
- 'var map = {"foo": "bar",};'
+ 'var map = {\n'
+ ' "foo": "bar",\n'
+ '};'
);
});
@@ -914,6 +937,135 @@
transforms: false);
});
+ // smoketest to ensure we're enforcing the 'no gratuitous linebreaks'
+ // opinion
+ test('CU (eat newlines)', () {
+ expectCUFormatsTo(
+ 'abstract\n'
+ 'class\n'
+ 'A{}',
+ 'abstract class A {\n'
+ '}\n'
+ );
+ });
+
+// test('line continuations - 1', () {
+// expectStmtFormatsTo(
+// 'if (x &&\n'
+// ' y) {\n'
+// ' print("yes!");\n'
+// '}',
+// 'if (x &&\n'
+// ' y) {\n'
+// ' print("yes!");\n'
+// '}'
+// );
+// expectStmtFormatsTo(
+// 'var x =\n'
+// ' 1234567890;',
+// 'var x =\n'
+// ' 1234567890;'
+// );
+// expectStmtFormatsTo(
+// 'foo() {\n'
+// ' var x = 0;\n'
+// ' x =\n'
+// ' 1234567890;\n'
+// '}',
+// 'foo() {\n'
+// ' var x = 0;\n'
+// ' x =\n'
+// ' 1234567890;\n'
+// '}'
+// );
+// expectStmtFormatsTo(
+// 'foo() {\n'
+// ' while (true &&\n'
+// ' true) {\n'
+// ' print("!");\n'
+// ' }\n'
+// '}',
+// 'foo() {\n'
+// ' while (true &&\n'
+// ' true) {\n'
+// ' print("!");\n'
+// ' }\n'
+// '}'
+// );
+// expectStmtFormatsTo(
+// 'foo() {\n'
+// ' do {\n'
+// ' print("!");\n'
+// ' } while (true &&\n'
+// ' true);\n'
+// '}',
+// 'foo() {\n'
+// ' do {\n'
+// ' print("!");\n'
+// ' } while (true &&\n'
+// ' true);\n'
+// '}'
+// );
+// expectStmtFormatsTo(
+// 'int foo() {\n'
+// ' return\n'
+// ' foo();\n'
+// '}',
+// 'int foo() {\n'
+// ' return\n'
+// ' foo();\n'
+// '}'
+// );
+// expectStmtFormatsTo(
+// 'int foo() {\n'
+// ' return\n'
+// ' 13;\n'
+// '}',
+// 'int foo() {\n'
+// ' return\n'
+// ' 13;\n'
+// '}'
+// );
+// expectStmtFormatsTo(
+// 'foo(fn()) {\n'
+// ' return foo(() {\n'
+// ' return 1;\n'
+// '});\n'
+// '}',
+// 'foo(fn()) {\n'
+// ' return foo(() {\n'
+// ' return 1;\n'
+// '});\n'
+// '}'
+// );
+// expectStmtFormatsTo(
+// 'true ? foo() :\n'
+// ' bar();',
+// 'true ? foo() :\n'
+// ' bar();'
+// );
+// expectCUFormatsTo(
+// 'import "dart:core" as\n'
+// ' core;\n',
+// 'import "dart:core" as\n'
+// ' core;\n'
+// );
+// expectCUFormatsTo(
+// 'export "package:foo/foo.dart" show\n'
+// ' Foo;\n',
+// 'export "package:foo/foo.dart" show\n'
+// ' Foo;\n'
+// );
+// expectCUFormatsTo(
+// 'class Foo extends Bar implements\n'
+// ' Baz {\n'
+// '}\n',
+// 'class Foo extends Bar implements\n'
+// ' Baz {\n'
+// '}\n'
+// );
+// });
+
test('initialIndent', () {
var formatter = new CodeFormatter(
new FormatterOptions(initialIndentationLevel: 2));
@@ -1155,3 +1307,22 @@
expectStmtFormatsTo(src, expected, {transforms: true}) =>
expect(formatStatement(src, options:
new FormatterOptions(codeTransforms: transforms)), equals(expected));
+
+runTests(testFile, expectClause(input, output)) {
+
+ var testIndex = 1;
+ var lines = testFile.readAsLinesSync();
+
+ for (var i = 1; i < lines.length; ++i) {
+ var input = '', expectedOutput = '';
+ while(lines[i] != '<<<') {
+ input += lines[i++] + '\n';
+ }
+ while(++i < lines.length && lines[i] != '>>>') {
+ expectedOutput += lines[i] + '\n';
+ }
+ test('test - (${testIndex++})', () {
+ expectClause(input, expectedOutput);
+ });
+ }
+}
diff --git a/pkg/args/lib/args.dart b/pkg/args/lib/args.dart
index a76e726..4b9f857 100644
--- a/pkg/args/lib/args.dart
+++ b/pkg/args/lib/args.dart
@@ -261,7 +261,7 @@
*/
library args;
-import 'package:collection_helpers/wrappers.dart';
+import 'package:collection/wrappers.dart';
import 'src/parser.dart';
import 'src/usage.dart';
diff --git a/pkg/args/lib/src/options.dart b/pkg/args/lib/src/options.dart
index 0b8b404..a4091df 100644
--- a/pkg/args/lib/src/options.dart
+++ b/pkg/args/lib/src/options.dart
@@ -1,6 +1,6 @@
library options;
-import 'package:collection_helpers/wrappers.dart';
+import 'package:collection/wrappers.dart';
/**
* A command-line option. Includes both flags and options which take a value.
diff --git a/pkg/args/pubspec.yaml b/pkg/args/pubspec.yaml
index f907300..771fdb1 100644
--- a/pkg/args/pubspec.yaml
+++ b/pkg/args/pubspec.yaml
@@ -8,7 +8,7 @@
a set of options and values using GNU and POSIX style options.
dependencies:
- collection_helpers: ">=0.9.1 <0.10.0"
+ collection: ">=0.9.0 <0.10.0"
dev_dependencies:
unittest: ">=0.9.0 <0.10.0"
environment:
diff --git a/pkg/async/LICENSE b/pkg/async/LICENSE
new file mode 100644
index 0000000..ee99930
--- /dev/null
+++ b/pkg/async/LICENSE
@@ -0,0 +1,26 @@
+Copyright 2013, the Dart project authors. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google Inc. nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/pkg/async/README.md b/pkg/async/README.md
new file mode 100644
index 0000000..dc34553
--- /dev/null
+++ b/pkg/async/README.md
@@ -0,0 +1,11 @@
+The `async` package will contain tools to work with asynchronous computations.
+
+The package contains sub-libraries with different utilities.
+
+### Zipping streams
+
+The "stream_zip.dart" sub-library contains functionality to combine several streams
+of events into a single stream of tuples of events.
+
+### History.
+This package is unrelated to the discontinued `async` package with version 0.1.7.
diff --git a/runtime/bin/vmservice/service_request_router.dart b/pkg/async/lib/async.dart
similarity index 68%
copy from runtime/bin/vmservice/service_request_router.dart
copy to pkg/async/lib/async.dart
index c889c85..e9d6544 100644
--- a/runtime/bin/vmservice/service_request_router.dart
+++ b/pkg/async/lib/async.dart
@@ -2,8 +2,6 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-part of vmservice;
+library dart.pkg.async;
-abstract class ServiceRequestRouter {
- Future route(ServiceRequest request);
-}
+export "stream_zip.dart";
diff --git a/pkg/async/lib/stream_zip.dart b/pkg/async/lib/stream_zip.dart
new file mode 100644
index 0000000..055489d
--- /dev/null
+++ b/pkg/async/lib/stream_zip.dart
@@ -0,0 +1,119 @@
+// 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.
+
+/**
+ * Help for combining multiple streams into a single stream.
+ */
+library dart.pkg.async.stream_zip;
+
+import "dart:async";
+
+/**
+ * A stream that combines the values of other streams.
+ */
+class StreamZip extends Stream<List> {
+ final Iterable<Stream> _streams;
+ StreamZip(Iterable<Stream> streams) : _streams = streams;
+
+ StreamSubscription<List> listen(void onData(List data), {
+ Function onError,
+ void onDone(),
+ bool cancelOnError}) {
+ cancelOnError = identical(true, cancelOnError);
+ List<StreamSubscription> subscriptions = <StreamSubscription>[];
+ StreamController controller;
+ List current;
+ int dataCount = 0;
+
+ /// Called for each data from a subscription in [subscriptions].
+ void handleData(int index, data) {
+ current[index] = data;
+ dataCount++;
+ if (dataCount == subscriptions.length) {
+ List data = current;
+ current = new List(subscriptions.length);
+ dataCount = 0;
+ for (int i = 0; i < subscriptions.length; i++) {
+ if (i != index) subscriptions[i].resume();
+ }
+ controller.add(data);
+ } else {
+ subscriptions[index].pause();
+ }
+ }
+
+ /// Called for each error from a subscription in [subscriptions].
+ /// Except if [cancelOnError] is true, in which case the function below
+ /// is used instead.
+ void handleError(Object error, StackTrace stackTrace) {
+ controller.addError(error, stackTrace);
+ }
+
+ /// Called when a subscription has an error and [cancelOnError] is true.
+ ///
+ /// Prematurely cancels all subscriptions since we know that we won't
+ /// be needing any more values.
+ void handleErrorCancel(Object error, StackTrace stackTrace) {
+ for (int i = 0; i < subscriptions.length; i++) {
+ subscriptions[i].cancel();
+ }
+ controller.addError(error, stackTrace);
+ }
+
+ void handleDone() {
+ for (int i = 0; i < subscriptions.length; i++) {
+ subscriptions[i].cancel();
+ }
+ controller.close();
+ }
+
+ try {
+ for (Stream stream in _streams) {
+ int index = subscriptions.length;
+ subscriptions.add(stream.listen(
+ (data) { handleData(index, data); },
+ onError: cancelOnError ? handleError : handleErrorCancel,
+ onDone: handleDone,
+ cancelOnError: cancelOnError));
+ }
+ } catch (e) {
+ for (int i = subscriptions.length - 1; i >= 0; i--) {
+ subscriptions[i].cancel();
+ }
+ rethrow;
+ }
+
+ current = new List(subscriptions.length);
+
+ controller = new StreamController<List>(
+ onPause: () {
+ for (int i = 0; i < subscriptions.length; i++) {
+ // This may pause some subscriptions more than once.
+ // These will not be resumed by onResume below, but must wait for the
+ // next round.
+ subscriptions[i].pause();
+ }
+ },
+ onResume: () {
+ for (int i = 0; i < subscriptions.length; i++) {
+ subscriptions[i].resume();
+ }
+ },
+ onCancel: () {
+ for (int i = 0; i < subscriptions.length; i++) {
+ // Canceling more than once is safe.
+ subscriptions[i].cancel();
+ }
+ }
+ );
+
+ if (subscriptions.isEmpty) {
+ controller.close();
+ }
+ return controller.stream.listen(onData,
+ onError: onError,
+ onDone: onDone,
+ cancelOnError: cancelOnError);
+ }
+}
diff --git a/pkg/async/pubspec.yaml b/pkg/async/pubspec.yaml
new file mode 100644
index 0000000..3603226
--- /dev/null
+++ b/pkg/async/pubspec.yaml
@@ -0,0 +1,9 @@
+name: async
+version: 0.9.0
+author: Dart Team <misc@dartlang.org>
+description: Utility functions and classes related to the 'dart:async' library.
+homepage: http://www.dartlang.org
+dev_dependencies:
+ unittest: ">=0.9.0 <0.10.0"
+environment:
+ sdk: ">=1.0.0 <2.0.0"
diff --git a/pkg/sequence_zip/test/stream_test.dart b/pkg/async/test/stream_zip_test.dart
similarity index 98%
rename from pkg/sequence_zip/test/stream_test.dart
rename to pkg/async/test/stream_zip_test.dart
index 2f0de8f..54083b9 100644
--- a/pkg/sequence_zip/test/stream_test.dart
+++ b/pkg/async/test/stream_zip_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import "dart:async";
-import "package:sequence_zip/stream_zip.dart";
+import "package:async/stream_zip.dart";
import "package:unittest/unittest.dart";
/// Create an error with the same values as [base], except that it throwsA
diff --git a/pkg/async/test/stream_zip_zone_test.dart b/pkg/async/test/stream_zip_zone_test.dart
new file mode 100644
index 0000000..d39e3d7
--- /dev/null
+++ b/pkg/async/test/stream_zip_zone_test.dart
@@ -0,0 +1,59 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:async";
+import "package:async/stream_zip.dart";
+import "package:unittest/unittest.dart";
+
+// Test that stream listener callbacks all happen in the zone where the
+// listen occurred.
+
+main() {
+ StreamController controller;
+ controller = new StreamController();
+ testStream("singlesub-async", controller, controller.stream);
+ controller = new StreamController.broadcast();
+ testStream("broadcast-async", controller, controller.stream);
+ controller = new StreamController();
+ testStream("asbroadcast-async", controller,
+ controller.stream.asBroadcastStream());
+
+ controller = new StreamController(sync: true);
+ testStream("singlesub-sync", controller, controller.stream);
+ controller = new StreamController.broadcast(sync: true);
+ testStream("broadcast-sync", controller, controller.stream);
+ controller = new StreamController(sync: true);
+ testStream("asbroadcast-sync", controller,
+ controller.stream.asBroadcastStream());
+}
+
+void testStream(String name, StreamController controller, Stream stream) {
+ test(name, () {
+ Zone outer = Zone.current;
+ runZoned(() {
+ Zone newZone1 = Zone.current;
+ StreamSubscription sub;
+ sub = stream.listen(expectAsync1((v) {
+ expect(v, 42);
+ expect(Zone.current, newZone1);
+ outer.run(() {
+ sub.onData(expectAsync1((v) {
+ expect(v, 37);
+ expect(Zone.current, newZone1);
+ runZoned(() {
+ Zone newZone2 = Zone.current;
+ sub.onData(expectAsync1((v) {
+ expect(v, 87);
+ expect(Zone.current, newZone1);
+ }));
+ });
+ controller.add(87);
+ }));
+ });
+ controller.add(37);
+ }));
+ });
+ controller.add(42);
+ });
+}
diff --git a/pkg/barback/lib/src/package_graph.dart b/pkg/barback/lib/src/package_graph.dart
index 2ecf6b4..c2e1a8e 100644
--- a/pkg/barback/lib/src/package_graph.dart
+++ b/pkg/barback/lib/src/package_graph.dart
@@ -69,13 +69,6 @@
/// The stack trace for [_lastUnexpectedError].
StackTrace _lastUnexpectedErrorTrace;
- // TODO(nweiz): Allow transformers to declare themselves as "lightweight" or
- // "heavyweight" and adjust their restrictions appropriately. Simple
- // transformers may be very efficient to run in parallel, whereas dart2js uses
- // a lot of memory and should be run more sequentially.
- /// A pool that controls how many transformers may be applied at once.
- final Pool transformPool = new Pool(10);
-
/// Creates a new [PackageGraph] that will transform assets in all packages
/// made available by [provider].
PackageGraph(this.provider) {
diff --git a/pkg/barback/lib/src/pool.dart b/pkg/barback/lib/src/pool.dart
index 24100ca..4653722 100644
--- a/pkg/barback/lib/src/pool.dart
+++ b/pkg/barback/lib/src/pool.dart
@@ -138,4 +138,4 @@
_released = true;
_pool._onResourceReleased();
}
-}
\ No newline at end of file
+}
diff --git a/pkg/barback/lib/src/transform_node.dart b/pkg/barback/lib/src/transform_node.dart
index 2a99691..76b29bd 100644
--- a/pkg/barback/lib/src/transform_node.dart
+++ b/pkg/barback/lib/src/transform_node.dart
@@ -128,9 +128,7 @@
_isDirty = false;
- return phase.cascade.graph.transformPool
- .withResource(() => transformer.apply(transform))
- .catchError((error, stack) {
+ return transformer.apply(transform).catchError((error, stack) {
// If the transform became dirty while processing, ignore any errors from
// it.
if (_isDirty) return;
diff --git a/pkg/barback/pubspec.yaml b/pkg/barback/pubspec.yaml
index 5a7b410..c7e59ce 100644
--- a/pkg/barback/pubspec.yaml
+++ b/pkg/barback/pubspec.yaml
@@ -8,7 +8,7 @@
# When the minor version of this is upgraded, you *must* update that version
# number in pub to stay in sync with this. New patch versions are considered
# backwards compatible, and pub will allow later patch versions automatically.
-version: 0.11.0 # Minor version bumped
+version: 0.11.0
author: "Dart Team <misc@dartlang.org>"
homepage: http://www.dartlang.org
diff --git a/pkg/barback/test/package_graph/many_parallel_transformers_test.dart b/pkg/barback/test/package_graph/many_parallel_transformers_test.dart
index 72f19ac..8c47241 100644
--- a/pkg/barback/test/package_graph/many_parallel_transformers_test.dart
+++ b/pkg/barback/test/package_graph/many_parallel_transformers_test.dart
@@ -28,7 +28,5 @@
expectAsset("app|$i.out", "$i.out");
}
buildShouldSucceed();
-
- expect(rewrite.maxParallelRuns, completion(equals(10)));
});
}
diff --git a/pkg/barback/test/transformer/mock.dart b/pkg/barback/test/transformer/mock.dart
index cfbb21a..57d3f07 100644
--- a/pkg/barback/test/transformer/mock.dart
+++ b/pkg/barback/test/transformer/mock.dart
@@ -27,9 +27,6 @@
Future<int> get numRuns => schedule(() => _numRuns);
var _numRuns = 0;
- Future<int> get maxParallelRuns => schedule(() => _maxParallelRuns);
- var _maxParallelRuns = 0;
-
/// The number of currently running transforms.
int _runningTransforms = 0;
@@ -179,9 +176,6 @@
_numRuns++;
if (_runningTransforms == 0) _started.complete();
_runningTransforms++;
- if (_runningTransforms > _maxParallelRuns) {
- _maxParallelRuns = _runningTransforms;
- }
return newFuture(() => doApply(transform)).then((_) {
if (_apply != null) return _apply.future;
}).whenComplete(() {
diff --git a/pkg/collection/LICENSE b/pkg/collection/LICENSE
new file mode 100644
index 0000000..ee99930
--- /dev/null
+++ b/pkg/collection/LICENSE
@@ -0,0 +1,26 @@
+Copyright 2013, the Dart project authors. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google Inc. nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/pkg/collection/README.md b/pkg/collection/README.md
new file mode 100644
index 0000000..bb392fd
--- /dev/null
+++ b/pkg/collection/README.md
@@ -0,0 +1,55 @@
+Helper libraries for working with collections.
+
+The `collection` package contains a number of separate libraries
+with utility functions and classes that makes working with collections easier.
+
+## Using
+
+The `collection` package can be imported as separate libraries, or
+in totality:
+
+ import 'package:collection/equality.dart';
+ import 'package:collection/algorithms.dart';
+ import 'package:collection/wrappers.dart';
+
+or
+
+ import 'package:collection/collection.dart';
+
+## Equality
+
+The equality library gives a way to specify equality of elements and
+collections.
+
+Collections in Dart have no inherent equality. Two sets are not equal, even
+if they contain exactly the same objects as elements.
+
+The equality library provides a way to say define such an equality. In this
+case, for example, `const SetEquality(const IdentityEquality())` is an equality
+that considers two sets equal exactly if they contain identical elements.
+
+The library provides ways to define equalities on `Iterable`s, `List`s, `Set`s, and
+`Map`s, as well as combinations of these, such as:
+
+ const MapEquality(const IdentityEquality(), const ListEquality());
+
+This equality considers maps equal if they have identical keys, and the corresponding values are lists with equal (`operator==`) values.
+
+## Algorithms
+
+The algorithms library contains functions that operate on lists.
+
+It contains ways to shuffle a `List`, do binary search on a sorted `List`, and
+some different sorting algorithms.
+
+
+## Wrappers
+
+The wrappers library contains classes that "wrap" a collection.
+
+A wrapper class contains an object of the same type, and it forwards all
+methods to the wrapped object.
+
+Wrapper classes can be used in various ways, for example to restrict the type
+of an object to that of a supertype, or to change the behavior of selected
+functions on an existing object.
diff --git a/pkg/collection/lib/algorithms.dart b/pkg/collection/lib/algorithms.dart
new file mode 100644
index 0000000..5ff0bb3
--- /dev/null
+++ b/pkg/collection/lib/algorithms.dart
@@ -0,0 +1,301 @@
+// 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.
+
+/**
+ * Operations on collections.
+ */
+library dart.pkg.collection.algorithms;
+
+import "dart:math" show Random;
+
+/** Version of [binarySearch] optimized for comparable keys */
+int _comparableBinarySearch(List<Comparable> list, Comparable key) {
+ int min = 0;
+ int max = list.length;
+ while (min < max) {
+ int mid = min + ((max - min) >> 1);
+ var element = list[mid];
+ int comp = element.compareTo(key);
+ if (comp == 0) return mid;
+ if (comp < 0) {
+ min = mid + 1;
+ } else {
+ max = mid;
+ }
+ }
+ return -1;
+}
+
+/**
+ * Returns a position of the [key] in [sortedList], if it is there.
+ *
+ * If the list isn't sorted according to the [compare] function, the result
+ * is unpredictable.
+ *
+ * If [compare] is omitted, it defaults to calling [Comparable.compareTo] on
+ * the objects.
+ *
+ * Returns -1 if [key] is not in the list by default.
+ */
+int binarySearch(List sortedList, var key,
+ { int compare(var a, var b) }) {
+ if (compare == null) {
+ return _comparableBinarySearch(sortedList, key);
+ }
+ int min = 0;
+ int max = sortedList.length;
+ while (min < max) {
+ int mid = min + ((max - min) >> 1);
+ var element = sortedList[mid];
+ int comp = compare(element, key);
+ if (comp == 0) return mid;
+ if (comp < 0) {
+ min = mid + 1;
+ } else {
+ max = mid;
+ }
+ }
+ return -1;
+}
+
+
+/**
+ * Shuffles a list randomly.
+ *
+ * A sub-range of a list can be shuffled by providing [start] and [end].
+ */
+void shuffle(List list, [int start = 0, int end = null]) {
+ Random random = new Random();
+ if (end == null) end = list.length;
+ int length = end - start;
+ while (length > 1) {
+ int pos = random.nextInt(length);
+ length--;
+ var tmp1 = list[start + pos];
+ list[start + pos] = list[start + length];
+ list[start + length] = tmp1;
+ }
+}
+
+
+/**
+ * Reverses a list, or a part of a list, in-place.
+ */
+void reverse(List list, [int start = 0, int end = null]) {
+ if (end == null) end = list.length;
+ _reverse(list, start, end);
+}
+
+// Internal helper function that assumes valid arguments.
+void _reverse(List list, int start, int end) {
+ for (int i = start, j = end - 1; i < j; i++, j--) {
+ var tmp = list[i];
+ list[i] = list[j];
+ list[j] = tmp;
+ }
+}
+
+/**
+ * Sort a list using insertion sort.
+ *
+ * Insertion sort is a simple sorting algorithm. For `n` elements it does on
+ * the order of `n * log(n)` comparisons but up to `n` squared moves. The
+ * sorting is performed in-place, without using extra memory.
+ *
+ * For short lists the many moves have less impact than the simple algorithm,
+ * and it is often the favored sorting algorithm for short lists.
+ *
+ * This insertion sort is stable: Equal elements end up in the same order
+ * as they started in.
+ */
+void insertionSort(List list,
+ { int compare(a, b),
+ int start: 0,
+ int end: null }) {
+ // If the same method could have both positional and named optional
+ // parameters, this should be (list, [start, end], {compare}).
+ if (end == null) end = list.length;
+ if (compare == null) compare = Comparable.compare;
+ _insertionSort(list, compare, start, end, start + 1);
+}
+
+/**
+ * Internal helper function that assumes arguments correct.
+ *
+ * Assumes that the elements up to [sortedUntil] (not inclusive) are
+ * already sorted. The [sortedUntil] values should always be at least
+ * `start + 1`.
+ */
+void _insertionSort(List list, int compare(a, b), int start, int end,
+ int sortedUntil) {
+ for (int pos = sortedUntil; pos < end; pos++) {
+ int min = start;
+ int max = pos;
+ var element = list[pos];
+ while (min < max) {
+ int mid = min + ((max - min) >> 1);
+ int comparison = compare(element, list[mid]);
+ if (comparison < 0) {
+ max = mid;
+ } else {
+ min = mid + 1;
+ }
+ }
+ list.setRange(min + 1, pos + 1, list, min);
+ list[min] = element;
+ }
+}
+
+/** Limit below which merge sort defaults to insertion sort. */
+const int _MERGE_SORT_LIMIT = 32;
+
+/**
+ * Sorts a list, or a range of a list, using the merge sort algorithm.
+ *
+ * Merge-sorting works by splitting the job into two parts, sorting each
+ * recursively, and then merging the two sorted parts.
+ *
+ * This takes on the order of `n * log(n)` comparisons and moves to sort
+ * `n` elements, but requires extra space of about the same size as the list
+ * being sorted.
+ *
+ * This merge sort is stable: Equal elements end up in the same order
+ * as they started in.
+ */
+void mergeSort(List list, {int start: 0, int end: null, int compare(a, b)}) {
+ if (end == null) end = list.length;
+ if (compare == null) compare = Comparable.compare;
+ int length = end - start;
+ if (length < 2) return;
+ if (length < _MERGE_SORT_LIMIT) {
+ _insertionSort(list, compare, start, end, start + 1);
+ return;
+ }
+ // Special case the first split instead of directly calling
+ // _mergeSort, because the _mergeSort requires its target to
+ // be different from its source, and it requires extra space
+ // of the same size as the list to sort.
+ // This split allows us to have only half as much extra space,
+ // and it ends up in the original place.
+ int middle = start + ((end - start) >> 1);
+ int firstLength = middle - start;
+ int secondLength = end - middle;
+ // secondLength is always the same as firstLength, or one greater.
+ List scratchSpace = new List(secondLength);
+ _mergeSort(list, compare, middle, end, scratchSpace, 0);
+ int firstTarget = end - firstLength;
+ _mergeSort(list, compare, start, middle, list, firstTarget);
+ _merge(compare,
+ list, firstTarget, end,
+ scratchSpace, 0, secondLength,
+ list, start);
+}
+
+/**
+ * Performs an insertion sort into a potentially different list than the
+ * one containing the original values.
+ *
+ * It will work in-place as well.
+ */
+void _movingInsertionSort(List list, int compare(a, b), int start, int end,
+ List target, int targetOffset) {
+ int length = end - start;
+ if (length == 0) return;
+ target[targetOffset] = list[start];
+ for (int i = 1; i < length; i++) {
+ var element = list[start + i];
+ int min = targetOffset;
+ int max = targetOffset + i;
+ while (min < max) {
+ int mid = min + ((max - min) >> 1);
+ if (compare(element, target[mid]) < 0) {
+ max = mid;
+ } else {
+ min = mid + 1;
+ }
+ }
+ target.setRange(min + 1, targetOffset + i + 1,
+ target, min);
+ target[min] = element;
+ }
+}
+
+/**
+ * Sorts [list] from [start] to [end] into [target] at [targetOffset].
+ *
+ * The `target` list must be able to contain the range from `start` to `end`
+ * after `targetOffset`.
+ *
+ * Allows target to be the same list as [list], as long as it's not
+ * overlapping the `start..end` range.
+ */
+void _mergeSort(List list, int compare(a, b), int start, int end,
+ List target, int targetOffset) {
+ int length = end - start;
+ if (length < _MERGE_SORT_LIMIT) {
+ _movingInsertionSort(list, compare, start, end, target, targetOffset);
+ return;
+ }
+ int middle = start + (length >> 1);
+ int firstLength = middle - start;
+ int secondLength = end - middle;
+ // Here secondLength >= firstLength (differs by at most one).
+ int targetMiddle = targetOffset + firstLength;
+ // Sort the second half into the end of the target area.
+ _mergeSort(list, compare, middle, end,
+ target, targetMiddle);
+ // Sort the first half into the end of the source area.
+ _mergeSort(list, compare, start, middle,
+ list, middle);
+ // Merge the two parts into the target area.
+ _merge(compare,
+ list, middle, middle + firstLength,
+ target, targetMiddle, targetMiddle + secondLength,
+ target, targetOffset);
+}
+
+/**
+ * Merges two lists into a target list.
+ *
+ * One of the input lists may be positioned at the end of the target
+ * list.
+ *
+ * For equal object, elements from [firstList] are always preferred.
+ * This allows the merge to be stable if the first list contains elements
+ * that started out earlier than the ones in [secondList]
+ */
+void _merge(int compare(a, b),
+ List firstList, int firstStart, int firstEnd,
+ List secondList, int secondStart, int secondEnd,
+ List target, int targetOffset) {
+ // No empty lists reaches here.
+ assert(firstStart < firstEnd);
+ assert(secondStart < secondEnd);
+ int cursor1 = firstStart;
+ int cursor2 = secondStart;
+ var firstElement = firstList[cursor1++];
+ var secondElement = secondList[cursor2++];
+ while (true) {
+ if (compare(firstElement, secondElement) <= 0) {
+ target[targetOffset++] = firstElement;
+ if (cursor1 == firstEnd) break; // Flushing second list after loop.
+ firstElement = firstList[cursor1++];
+ } else {
+ target[targetOffset++] = secondElement;
+ if (cursor2 != secondEnd) {
+ secondElement = secondList[cursor2++];
+ continue;
+ }
+ // Second list empties first. Flushing first list here.
+ target[targetOffset++] = firstElement;
+ target.setRange(targetOffset, targetOffset + (firstEnd - cursor1),
+ firstList, cursor1);
+ return;
+ }
+ }
+ // First list empties first. Reached by break above.
+ target[targetOffset++] = secondElement;
+ target.setRange(targetOffset, targetOffset + (secondEnd - cursor2),
+ secondList, cursor2);
+}
diff --git a/pkg/collection/lib/collection.dart b/pkg/collection/lib/collection.dart
new file mode 100644
index 0000000..a6f192d
--- /dev/null
+++ b/pkg/collection/lib/collection.dart
@@ -0,0 +1,22 @@
+// 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.
+
+/**
+ * Exports all the individual parts of the collection-helper library.
+ *
+ * The sub-libraries of this package are:
+ *
+ * - `algorithms.dart`: Algorithms that work on lists (shuffle, binary search
+ * and various sorting algorithms).
+ * - `equality.dart`: Different notions of equality of collections.
+ * - `iterable_zip.dart`: Combining multiple iterables into one.
+ * - `wrappers.dart`: Wrapper classes that delegate to a collection object.
+ * Includes unmodifiable views of collections.
+ */
+library dart.pkg.collection;
+
+export "algorithms.dart";
+export "equality.dart";
+export "iterable_zip.dart";
+export "wrappers.dart";
diff --git a/pkg/collection/lib/equality.dart b/pkg/collection/lib/equality.dart
new file mode 100644
index 0000000..c6fdafa
--- /dev/null
+++ b/pkg/collection/lib/equality.dart
@@ -0,0 +1,419 @@
+// 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.
+
+/**
+ * Defines equality relations on collections.
+ */
+library dart.pkg.collection.equality;
+
+import "dart:collection";
+
+const int _HASH_MASK = 0x7fffffff;
+
+/**
+ * A generic equality relation on objects.
+ */
+abstract class Equality<E> {
+ const factory Equality() = DefaultEquality;
+
+ /**
+ * Compare two elements for being equal.
+ *
+ * This should be a proper equality relation.
+ */
+ bool equals(E e1, E e2);
+
+ /**
+ * Get a hashcode of an element.
+ *
+ * The hashcode should be compatible with [equals], so that if
+ * `equals(a, b)` then `hash(a) == hash(b)`.
+ */
+ int hash(E e);
+
+ /**
+ * Test whether an object is a valid argument to [equals] and [hash].
+ *
+ * Some implementations may be restricted to only work on specific types
+ * of objects.
+ */
+ bool isValidKey(Object o);
+}
+
+/**
+ * Equality of objects that compares only the natural equality of the objects.
+ *
+ * This equality uses the objects' own [Object.==] and [Object.hashCode] for
+ * the equality.
+ */
+class DefaultEquality implements Equality {
+ const DefaultEquality();
+ bool equals(Object e1, Object e2) => e1 == e2;
+ int hash(Object e) => e.hashCode;
+ bool isValidKey(Object o) => true;
+}
+
+/**
+ * Equality of objects that compares only the identity of the objects.
+ */
+class IdentityEquality implements Equality {
+ const IdentityEquality();
+ bool equals(Object e1, Object e2) => identical(e1, e2);
+ int hash(Object e) => identityHashCode(e);
+ bool isValidKey(Object o) => true;
+}
+
+/**
+ * Equality on iterables.
+ *
+ * Two iterables are equal if they have the same elements in the same order.
+ */
+class IterableEquality<E> implements Equality<Iterable<E>> {
+ final Equality<E> _elementEquality;
+ const IterableEquality([Equality<E> elementEquality =
+ const DefaultEquality()])
+ : _elementEquality = elementEquality;
+
+ bool equals(Iterable<E> elements1, Iterable<E> elements2) {
+ if (identical(elements1, elements2)) return true;
+ if (elements1 == null || elements2 == null) return false;
+ Iterator it1 = elements1.iterator;
+ Iterator it2 = elements2.iterator;
+ while (true) {
+ bool hasNext = it1.moveNext();
+ if (hasNext != it2.moveNext()) return false;
+ if (!hasNext) return true;
+ if (!_elementEquality.equals(it1.current, it2.current)) return false;
+ }
+ }
+
+ int hash(Iterable<E> elements) {
+ // Jenkins's one-at-a-time hash function.
+ int hash = 0;
+ for (E element in elements) {
+ int c = _elementEquality.hash(element);
+ hash = (hash + c) & _HASH_MASK;
+ hash = (hash + (hash << 10)) & _HASH_MASK;
+ hash ^= (hash >> 6);
+ }
+ hash = (hash + (hash << 3)) & _HASH_MASK;
+ hash ^= (hash >> 11);
+ hash = (hash + (hash << 15)) & _HASH_MASK;
+ return hash;
+ }
+
+ bool isValidKey(Object o) => o is Iterable<E>;
+}
+
+/**
+ * Equality on lists.
+ *
+ * Two lists are equal if they have the same length and their elements
+ * at each index are equal.
+ *
+ * This is effectively the same as [IterableEquality] except that it
+ * accesses elements by index instead of through iteration.
+ */
+class ListEquality<E> implements Equality<List<E>> {
+ final Equality<E> _elementEquality;
+ const ListEquality([Equality<E> elementEquality = const DefaultEquality()])
+ : _elementEquality = elementEquality;
+
+ bool equals(List<E> e1, List<E> e2) {
+ if (identical(e1, e2)) return true;
+ if (e1 == null || e2 == null) return false;
+ int length = e1.length;
+ if (length != e2.length) return false;
+ for (int i = 0; i < length; i++) {
+ if (!_elementEquality.equals(e1[i], e2[i])) return false;
+ }
+ return true;
+ }
+
+ int hash(List<E> e) {
+ // Jenkins's one-at-a-time hash function.
+ // This code is almost identical to the one in IterableEquality, except
+ // that it uses indexing instead of iterating to get the elements.
+ int hash = 0;
+ for (int i = 0; i < e.length; i++) {
+ int c = _elementEquality.hash(e[i]);
+ hash = (hash + c) & _HASH_MASK;
+ hash = (hash + (hash << 10)) & _HASH_MASK;
+ hash ^= (hash >> 6);
+ }
+ hash = (hash + (hash << 3)) & _HASH_MASK;
+ hash ^= (hash >> 11);
+ hash = (hash + (hash << 15)) & _HASH_MASK;
+ return hash;
+ }
+
+ bool isValidKey(Object o) => o is List<E>;
+}
+
+abstract class _UnorderedEquality<E, T extends Iterable<E>>
+ implements Equality<T> {
+ final Equality<E> _elementEquality;
+
+ const _UnorderedEquality(this._elementEquality);
+
+ bool equals(T e1, T e2) {
+ if (identical(e1, e2)) return true;
+ if (e1 == null || e2 == null) return false;
+ HashMap<E, int> counts = new HashMap(
+ equals: _elementEquality.equals,
+ hashCode: _elementEquality.hash,
+ isValidKey: _elementEquality.isValidKey);
+ int length = 0;
+ for (var e in e1) {
+ int count = counts[e];
+ if (count == null) count = 0;
+ counts[e] = count + 1;
+ length++;
+ }
+ for (var e in e2) {
+ int count = counts[e];
+ if (count == null || count == 0) return false;
+ counts[e] = count - 1;
+ length--;
+ }
+ return length == 0;
+ }
+
+ int hash(T e) {
+ int hash = 0;
+ for (E element in e) {
+ int c = _elementEquality.hash(element);
+ hash = (hash + c) & _HASH_MASK;
+ }
+ hash = (hash + (hash << 3)) & _HASH_MASK;
+ hash ^= (hash >> 11);
+ hash = (hash + (hash << 15)) & _HASH_MASK;
+ return hash;
+ }
+}
+
+/**
+ * Equality of the elements of two iterables without considering order.
+ *
+ * Two iterables are considered equal if they have the same number of elements,
+ * and the elements of one set can be paired with the elements
+ * of the other iterable, so that each pair are equal.
+ */
+class UnorderedIterableEquality<E> extends _UnorderedEquality<E, Iterable<E>> {
+ const UnorderedIterableEquality(
+ [Equality<E> elementEquality = const DefaultEquality()])
+ : super(elementEquality);
+
+ bool isValidKey(Object o) => o is Iterable<E>;
+}
+
+/**
+ * Equality of sets.
+ *
+ * Two sets are considered equal if they have the same number of elements,
+ * and the elements of one set can be paired with the elements
+ * of the other set, so that each pair are equal.
+ *
+ * This equality behaves the same as [UnorderedIterableEquality] except that
+ * it expects sets instead of iterables as arguments.
+ */
+class SetEquality<E> extends _UnorderedEquality<E, Set<E>> {
+ const SetEquality(
+ [Equality<E> elementEquality = const DefaultEquality()])
+ : super(elementEquality);
+
+ bool isValidKey(Object o) => o is Set<E>;
+}
+
+/**
+ * Internal class used by [MapEquality].
+ *
+ * The class represents a map entry as a single object,
+ * using a combined hashCode and equality of the key and value.
+ */
+class _MapEntry {
+ final MapEquality equality;
+ final key;
+ final value;
+ _MapEntry(this.equality, this.key, this.value);
+
+ int get hashCode =>
+ (3 * equality._keyEquality.hash(key) +
+ 7 * equality._valueEquality.hash(value)) & _HASH_MASK;
+
+ bool operator==(Object other) {
+ if (other is! _MapEntry) return false;
+ _MapEntry otherEntry = other;
+ return equality._keyEquality.equals(key, otherEntry.key) &&
+ equality._valueEquality.equals(value, otherEntry.value);
+
+ }
+}
+
+/**
+ * Equality on maps.
+ *
+ * Two maps are equal if they have the same number of entries, and if the
+ * entries of the two maps are pairwise equal on both key and value.
+ */
+class MapEquality<K, V> implements Equality<Map<K, V>> {
+ final Equality<K> _keyEquality;
+ final Equality<V> _valueEquality;
+ const MapEquality({ Equality<K> keys : const DefaultEquality(),
+ Equality<V> values : const DefaultEquality() })
+ : _keyEquality = keys, _valueEquality = values;
+
+ bool equals(Map<K, V> e1, Map<K, V> e2) {
+ if (identical(e1, e2)) return true;
+ if (e1 == null || e2 == null) return false;
+ int length = e1.length;
+ if (length != e2.length) return false;
+ Map<_MapEntry, int> equalElementCounts = new HashMap();
+ for (K key in e1.keys) {
+ _MapEntry entry = new _MapEntry(this, key, e1[key]);
+ int count = equalElementCounts[entry];
+ if (count == null) count = 0;
+ equalElementCounts[entry] = count + 1;
+ }
+ for (K key in e2.keys) {
+ _MapEntry entry = new _MapEntry(this, key, e2[key]);
+ int count = equalElementCounts[entry];
+ if (count == null || count == 0) return false;
+ equalElementCounts[entry] = count - 1;
+ }
+ return true;
+ }
+
+ int hash(Map<K, V> map) {
+ int hash = 0;
+ for (K key in map.keys) {
+ int keyHash = _keyEquality.hash(key);
+ int valueHash = _valueEquality.hash(map[key]);
+ hash = (hash + 3 * keyHash + 7 * valueHash) & _HASH_MASK;
+ }
+ hash = (hash + (hash << 3)) & _HASH_MASK;
+ hash ^= (hash >> 11);
+ hash = (hash + (hash << 15)) & _HASH_MASK;
+ return hash;
+ }
+
+ bool isValidKey(Object o) => o is Map<K, V>;
+}
+
+/**
+ * Combines several equalities into a single equality.
+ *
+ * Tries each equality in order, using [Equality.isValidKey], and returns
+ * the result of the first equality that applies to the argument or arguments.
+ *
+ * For `equals`, the first equality that matches the first argument is used,
+ * and if the second argument of `equals` is not valid for that equality,
+ * it returns false.
+ *
+ * Because the equalities are tried in order, they should generally work on
+ * disjoint types. Otherwise the multi-equality may give inconsistent results
+ * for `equals(e1, e2)` and `equals(e2, e1)`. This can happen if one equality
+ * considers only `e1` a valid key, and not `e2`, but an equality which is
+ * checked later, allows both.
+ */
+class MultiEquality<E> implements Equality<E> {
+ final Iterable<Equality<E>> _equalities;
+
+ const MultiEquality(Iterable<Equality<E>> equalities)
+ : _equalities = equalities;
+
+ bool equals(E e1, E e2) {
+ for (Equality<E> eq in _equalities) {
+ if (eq.isValidKey(e1)) return eq.isValidKey(e2) && eq.equals(e1, e2);
+ }
+ return false;
+ }
+
+ int hash(E e) {
+ for (Equality<E> eq in _equalities) {
+ if (eq.isValidKey(e)) return eq.hash(e);
+ }
+ return -1;
+ }
+
+ bool isValidKey(Object o) {
+ for (Equality<E> eq in _equalities) {
+ if (eq.isValidKey(o)) return true;
+ }
+ return false;
+ }
+}
+
+/**
+ * Deep equality on collections.
+ *
+ * Recognizes lists, sets, iterables and maps and compares their elements using
+ * deep equality as well.
+ *
+ * Non-iterable/map objects are compared using a configurable base equality.
+ *
+ * Works in one of two modes: ordered or unordered.
+ *
+ * In ordered mode, lists and iterables are required to have equal elements
+ * in the same order. In unordered mode, the order of elements in iterables
+ * and lists are not importan.
+ *
+ * A list is only equal to another list, likewise for sets and maps. All other
+ * iterables are compared as iterables only.
+ */
+class DeepCollectionEquality implements Equality {
+ final Equality _base;
+ final bool _unordered;
+ const DeepCollectionEquality([Equality base = const DefaultEquality()])
+ : _base = base, _unordered = false;
+
+ /**
+ * Creates a deep equality on collections where the order of lists and
+ * iterables are not considered important. That is, lists and iterables are
+ * treated as unordered iterables.
+ */
+ const DeepCollectionEquality.unordered(
+ [Equality base = const DefaultEquality()])
+ : _base = base, _unordered = true;
+
+ bool equals(e1, e2) {
+ if (e1 is Set) {
+ if (e2 is! Set) return false;
+ return new SetEquality(this).equals(e1, e2);
+ }
+ if (e1 is Map) {
+ if (e2 is! Map) return false;
+ return new MapEquality(keys: this, values: this).equals(e1, e2);
+ }
+ if (!_unordered) {
+ if (e1 is List) {
+ if (e2 is! List) return false;
+ return new ListEquality(this).equals(e1, e2);
+ }
+ if (e1 is Iterable) {
+ if (e2 is! Iterable) return false;
+ return new IterableEquality(this).equals(e1, e2);
+ }
+ } else if (e1 is Iterable) {
+ if (e2 is! Iterable) return false;
+ if (e1 is List != e2 is List) return false;
+ return new UnorderedIterableEquality(this).equals(e1, e2);
+ }
+ return _base.equals(e1, e2);
+ }
+
+ int hash(Object o) {
+ if (o is Set) return new SetEquality(this).hash(o);
+ if (o is Map) return new MapEquality(keys: this, values: this).hash(o);
+ if (!_unordered) {
+ if (o is List) return new ListEquality(this).hash(o);
+ if (o is Iterable) return new IterableEquality(this).hash(o);
+ } else if (o is Iterable) {
+ return new UnorderedIterableEquality(this).hash(o);
+ }
+ return _base.hash(o);
+ }
+
+ bool isValidKey(Object o) => o is Iterable || o is Map || _base.isValidKey(o);
+}
diff --git a/pkg/collection/lib/iterable_zip.dart b/pkg/collection/lib/iterable_zip.dart
new file mode 100644
index 0000000..772b07e
--- /dev/null
+++ b/pkg/collection/lib/iterable_zip.dart
@@ -0,0 +1,59 @@
+// 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.
+
+/**
+ * Zipping multiple iterables into one iterable of tuples of values.
+ */
+library dart.pkg.collection.iterable_zip;
+
+import "dart:collection" show IterableBase;
+
+/**
+ * Iterable that iterates over lists of values from other iterables.
+ *
+ * When [iterator] is read, an [Iterator] is created for each [Iterable] in
+ * the [Iterable] passed to the constructor.
+ *
+ * As long as all these iterators have a next value, those next values are
+ * combined into a single list, which becomes the next value of this
+ * [Iterable]'s [Iterator]. As soon as any of the iterators run out,
+ * the zipped iterator also stops.
+ */
+class IterableZip extends IterableBase<List> {
+ final Iterable<Iterable> _iterables;
+ IterableZip(Iterable<Iterable> iterables)
+ : this._iterables = iterables;
+
+ /**
+ * Returns an iterator that combines values of the iterables' iterators
+ * as long as they all have values.
+ */
+ Iterator<List> get iterator {
+ List iterators = _iterables.map((x) => x.iterator).toList(growable: false);
+ // TODO(lrn): Return an empty iterator directly if iterators is empty?
+ return new _IteratorZip(iterators);
+ }
+}
+
+class _IteratorZip implements Iterator<List> {
+ final List<Iterator> _iterators;
+ List _current;
+ _IteratorZip(List iterators) : _iterators = iterators;
+ bool moveNext() {
+ if (_iterators.isEmpty) return false;
+ for (int i = 0; i < _iterators.length; i++) {
+ if (!_iterators[i].moveNext()) {
+ _current = null;
+ return false;
+ }
+ }
+ _current = new List(_iterators.length);
+ for (int i = 0; i < _iterators.length; i++) {
+ _current[i] = _iterators[i].current;
+ }
+ return true;
+ }
+
+ List get current => _current;
+}
diff --git a/pkg/collection_helpers/lib/unmodifiable_wrappers.dart b/pkg/collection/lib/src/unmodifiable_wrappers.dart
similarity index 99%
rename from pkg/collection_helpers/lib/unmodifiable_wrappers.dart
rename to pkg/collection/lib/src/unmodifiable_wrappers.dart
index b44337f..022bbfe 100644
--- a/pkg/collection_helpers/lib/unmodifiable_wrappers.dart
+++ b/pkg/collection/lib/src/unmodifiable_wrappers.dart
@@ -11,7 +11,7 @@
* The [List] wrapper prevents changes to the length of the wrapped list,
* but allows changes to the contents.
*/
-part of dart.collection_helpers.wrappers;
+part of dart.pkg.collection.wrappers;
/**
* A fixed-length list.
diff --git a/pkg/collection/lib/wrappers.dart b/pkg/collection/lib/wrappers.dart
new file mode 100644
index 0000000..ec78f5c
--- /dev/null
+++ b/pkg/collection/lib/wrappers.dart
@@ -0,0 +1,334 @@
+// 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.
+
+/**
+ * Delegating wrappers for [Iterable], [List], [Set], [Queue] and [Map].
+ *
+ * Also adds unmodifiable views for `Set` and `Map`, and a fixed length
+ * view for `List`. The unmodifable list view from `dart:collection` is exported
+ * as well, just for completeness.
+ */
+library dart.pkg.collection.wrappers;
+
+import "dart:collection";
+import "dart:math" show Random;
+
+export "dart:collection" show UnmodifiableListView;
+
+part "src/unmodifiable_wrappers.dart";
+
+/**
+ * Creates an [Iterable] that delegates all operations to a base iterable.
+ *
+ * This class can be used hide non-`Iterable` methods of an iterable object,
+ * or it can be extended to add extra functionality on top of an existing
+ * iterable object.
+ */
+class DelegatingIterable<E> implements Iterable<E> {
+ Iterable<E> _base;
+
+ /**
+ * Create a wrapper that forwards operations to [base].
+ */
+ DelegatingIterable(Iterable<E> base) : _base = base;
+
+ bool any(bool test(E element)) => _base.any(test);
+
+ bool contains(Object element) => _base.contains(element);
+
+ E elementAt(int index) => _base.elementAt(index);
+
+ bool every(bool test(E element)) => _base.every(test);
+
+ Iterable expand(Iterable f(E element)) => _base.expand(f);
+
+ E get first => _base.first;
+
+ E firstWhere(bool test(E element), {E orElse()}) =>
+ _base.firstWhere(test, orElse: orElse);
+
+ fold(initialValue, combine(previousValue, E element)) =>
+ _base.fold(initialValue, combine);
+
+ void forEach(void f(E element)) => _base.forEach(f);
+
+ bool get isEmpty => _base.isEmpty;
+
+ bool get isNotEmpty => _base.isNotEmpty;
+
+ Iterator<E> get iterator => _base.iterator;
+
+ String join([String separator = ""]) => _base.join(separator);
+
+ E get last => _base.last;
+
+ E lastWhere(bool test(E element), {E orElse()}) =>
+ _base.lastWhere(test, orElse: orElse);
+
+ int get length => _base.length;
+
+ Iterable map(f(E element)) => _base.map(f);
+
+ E reduce(E combine(E value, E element)) => _base.reduce(combine);
+
+ E get single => _base.single;
+
+ E singleWhere(bool test(E element)) => _base.singleWhere(test);
+
+ Iterable<E> skip(int n) => _base.skip(n);
+
+ Iterable<E> skipWhile(bool test(E value)) => _base.skipWhile(test);
+
+ Iterable<E> take(int n) => _base.take(n);
+
+ Iterable<E> takeWhile(bool test(E value)) => _base.takeWhile(test);
+
+ List<E> toList({bool growable: true}) => _base.toList(growable: growable);
+
+ Set<E> toSet() => _base.toSet();
+
+ Iterable<E> where(bool test(E element)) => _base.where(test);
+}
+
+
+/**
+ * Creates a [List] that delegates all operations to a base list.
+ *
+ * This class can be used hide non-`List` methods of a list object,
+ * or it can be extended to add extra functionality on top of an existing
+ * list object.
+ */
+class DelegatingList<E> extends DelegatingIterable<E> implements List<E> {
+ DelegatingList(List<E> base) : super(base);
+
+ List<E> get _listBase => _base;
+
+ E operator [](int index) => _listBase[index];
+
+ void operator []=(int index, E value) {
+ _listBase[index] = value;
+ }
+
+ void add(E value) {
+ _listBase.add(value);
+ }
+
+ void addAll(Iterable<E> iterable) {
+ _listBase.addAll(iterable);
+ }
+
+ Map<int, E> asMap() => _listBase.asMap();
+
+ void clear() {
+ _listBase.clear();
+ }
+
+ void fillRange(int start, int end, [E fillValue]) {
+ _listBase.fillRange(start, end, fillValue);
+ }
+
+ Iterable<E> getRange(int start, int end) => _listBase.getRange(start, end);
+
+ int indexOf(E element, [int start = 0]) => _listBase.indexOf(element, start);
+
+ void insert(int index, E element) {
+ _listBase.insert(index, element);
+ }
+
+ void insertAll(int index, Iterable<E> iterable) {
+ _listBase.insertAll(index, iterable);
+ }
+
+ int lastIndexOf(E element, [int start]) =>
+ _listBase.lastIndexOf(element, start);
+
+ void set length(int newLength) {
+ _listBase.length = newLength;
+ }
+
+ bool remove(Object value) => _listBase.remove(value);
+
+ E removeAt(int index) => _listBase.removeAt(index);
+
+ E removeLast() => _listBase.removeLast();
+
+ void removeRange(int start, int end) {
+ _listBase.removeRange(start, end);
+ }
+
+ void removeWhere(bool test(E element)) {
+ _listBase.removeWhere(test);
+ }
+
+ void replaceRange(int start, int end, Iterable<E> iterable) {
+ _listBase.replaceRange(start, end, iterable);
+ }
+
+ void retainWhere(bool test(E element)) {
+ _listBase.retainWhere(test);
+ }
+
+ Iterable<E> get reversed => _listBase.reversed;
+
+ void setAll(int index, Iterable<E> iterable) {
+ _listBase.setAll(index, iterable);
+ }
+
+ void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
+ _listBase.setRange(start, end, iterable, skipCount);
+ }
+
+ void shuffle([Random random]) {
+ _listBase.shuffle(random);
+ }
+
+ void sort([int compare(E a, E b)]) {
+ _listBase.sort(compare);
+ }
+
+ List<E> sublist(int start, [int end]) => _listBase.sublist(start, end);
+}
+
+
+/**
+ * Creates a [Set] that delegates all operations to a base set.
+ *
+ * This class can be used hide non-`Set` methods of a set object,
+ * or it can be extended to add extra functionality on top of an existing
+ * set object.
+ */
+class DelegatingSet<E> extends DelegatingIterable<E> implements Set<E> {
+ DelegatingSet(Set<E> base) : super(base);
+
+ Set<E> get _setBase => _base;
+
+ bool add(E value) => _setBase.add(value);
+
+ void addAll(Iterable<E> elements) {
+ _setBase.addAll(elements);
+ }
+
+ void clear() {
+ _setBase.clear();
+ }
+
+ bool containsAll(Iterable<Object> other) => _setBase.containsAll(other);
+
+ Set<E> difference(Set<E> other) => _setBase.difference(other);
+
+ Set<E> intersection(Set<Object> other) => _setBase.intersection(other);
+
+ E lookup(E element) => _setBase.lookup(element);
+
+ bool remove(Object value) => _setBase.remove(value);
+
+ void removeAll(Iterable<Object> elements) {
+ _setBase.removeAll(elements);
+ }
+
+ void removeWhere(bool test(E element)) {
+ _setBase.removeWhere(test);
+ }
+
+ void retainAll(Iterable<Object> elements) {
+ _setBase.retainAll(elements);
+ }
+
+ void retainWhere(bool test(E element)) {
+ _setBase.retainWhere(test);
+ }
+
+ Set<E> union(Set<E> other) => _setBase.union(other);
+}
+
+/**
+ * Creates a [Queue] that delegates all operations to a base queue.
+ *
+ * This class can be used hide non-`Queue` methods of a queue object,
+ * or it can be extended to add extra functionality on top of an existing
+ * queue object.
+ */
+class DelegatingQueue<E> extends DelegatingIterable<E> implements Queue<E> {
+ DelegatingQueue(Queue<E> queue) : super(queue);
+
+ Queue<E> get _baseQueue => _base;
+
+ void add(E value) {
+ _baseQueue.add(value);
+ }
+
+ void addAll(Iterable<E> iterable) {
+ _baseQueue.addAll(iterable);
+ }
+
+ void addFirst(E value) {
+ _baseQueue.addFirst(value);
+ }
+
+ void addLast(E value) {
+ _baseQueue.addLast(value);
+ }
+
+ void clear() {
+ _baseQueue.clear();
+ }
+
+ bool remove(Object object) => _baseQueue.remove(object);
+
+ void removeWhere(bool test(E element)) { _baseQueue.removeWhere(test); }
+
+ void retainWhere(bool test(E element)) { _baseQueue.retainWhere(test); }
+
+ E removeFirst() => _baseQueue.removeFirst();
+
+ E removeLast() => _baseQueue.removeLast();
+}
+
+/**
+ * Creates a [Map] that delegates all operations to a base map.
+ *
+ * This class can be used hide non-`Map` methods of an object that extends
+ * `Map`, or it can be extended to add extra functionality on top of an existing
+ * map object.
+ */
+class DelegatingMap<K, V> implements Map<K, V> {
+ Map<K, V> _base;
+ DelegatingMap(Map<K, V> base) : _base = base;
+
+ V operator [](Object key) => _base[key];
+
+ void operator []=(K key, V value) {
+ _base[key] = value;
+ }
+
+ void addAll(Map<K, V> other) {
+ _base.addAll(other);
+ }
+
+ void clear() {
+ _base.clear();
+ }
+
+ bool containsKey(Object key) => _base.containsKey(key);
+
+ bool containsValue(Object value) => _base.containsValue(value);
+
+ void forEach(void f(K key, V value)) {
+ _base.forEach(f);
+ }
+
+ bool get isEmpty => _base.isEmpty;
+
+ bool get isNotEmpty => _base.isNotEmpty;
+
+ Iterable<K> get keys => _base.keys;
+
+ int get length => _base.length;
+
+ V putIfAbsent(K key, V ifAbsent()) => _base.putIfAbsent(key, ifAbsent);
+
+ V remove(Object key) => _base.remove(key);
+
+ Iterable<V> get values => _base.values;
+}
diff --git a/pkg/collection/pubspec.yaml b/pkg/collection/pubspec.yaml
new file mode 100644
index 0000000..0fec04b
--- /dev/null
+++ b/pkg/collection/pubspec.yaml
@@ -0,0 +1,9 @@
+name: collection
+version: 0.9.0
+author: Dart Team <misc@dartlang.org>
+description: Collections and utilities functions and classes related to collections.
+homepage: http://www.dartlang.org
+dev_dependencies:
+ unittest: ">=0.9.0 <0.10.0"
+environment:
+ sdk: ">=1.0.0 <2.0.0"
diff --git a/pkg/collection_helpers/test/algorithms_test.dart b/pkg/collection/test/algorithms_test.dart
similarity index 99%
rename from pkg/collection_helpers/test/algorithms_test.dart
rename to pkg/collection/test/algorithms_test.dart
index ff82fff..933e268 100644
--- a/pkg/collection_helpers/test/algorithms_test.dart
+++ b/pkg/collection/test/algorithms_test.dart
@@ -4,7 +4,7 @@
/// Tests algorithm utilities.
-import "package:collection_helpers/all.dart";
+import "package:collection/collection.dart";
import "package:unittest/unittest.dart";
import 'dart:math';
@@ -268,4 +268,4 @@
OC(this.id, this.order);
int compareTo(OC other) => id - other.id;
String toString() => "OC[$id,$order]";
-}
\ No newline at end of file
+}
diff --git a/pkg/collection_helpers/test/equality_test.dart b/pkg/collection/test/equality_test.dart
similarity index 98%
rename from pkg/collection_helpers/test/equality_test.dart
rename to pkg/collection/test/equality_test.dart
index 00a1505..edabfd5 100644
--- a/pkg/collection_helpers/test/equality_test.dart
+++ b/pkg/collection/test/equality_test.dart
@@ -5,7 +5,7 @@
// Tests equality utilities.
import "dart:collection";
-import "package:collection_helpers/all.dart";
+import "package:collection/collection.dart";
import "package:unittest/unittest.dart";
main() {
diff --git a/pkg/sequence_zip/test/iterable_test.dart b/pkg/collection/test/iterable_zip_test.dart
similarity index 98%
rename from pkg/sequence_zip/test/iterable_test.dart
rename to pkg/collection/test/iterable_zip_test.dart
index 978ee96..ec191fe 100644
--- a/pkg/sequence_zip/test/iterable_test.dart
+++ b/pkg/collection/test/iterable_zip_test.dart
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
import "dart:collection";
-import "package:sequence_zip/iterable_zip.dart";
+import "package:collection/iterable_zip.dart";
import "package:unittest/unittest.dart";
/// Iterable like [base] except that it throws when value equals [errorValue].
diff --git a/pkg/collection_helpers/test/unmodifiable_collection_test.dart b/pkg/collection/test/unmodifiable_collection_test.dart
similarity index 99%
rename from pkg/collection_helpers/test/unmodifiable_collection_test.dart
rename to pkg/collection/test/unmodifiable_collection_test.dart
index ac5bb07..d810b75 100644
--- a/pkg/collection_helpers/test/unmodifiable_collection_test.dart
+++ b/pkg/collection/test/unmodifiable_collection_test.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-import "package:collection_helpers/wrappers.dart";
+import "package:collection/wrappers.dart";
import "package:unittest/unittest.dart";
// Test unmodifiable collection views.
diff --git a/pkg/collection_helpers/test/wrapper_test.dart b/pkg/collection/test/wrapper_test.dart
similarity index 99%
rename from pkg/collection_helpers/test/wrapper_test.dart
rename to pkg/collection/test/wrapper_test.dart
index 3c3da3c..875a70a 100644
--- a/pkg/collection_helpers/test/wrapper_test.dart
+++ b/pkg/collection/test/wrapper_test.dart
@@ -5,7 +5,7 @@
/// Tests wrapper utilities.
import "dart:collection";
-import "package:collection_helpers/all.dart";
+import "package:collection/collection.dart";
import "package:unittest/unittest.dart";
// Test that any member access/call on the wrapper object is equal to
diff --git a/pkg/collection_helpers/LICENSE b/pkg/collection_helpers/LICENSE
new file mode 100644
index 0000000..ee99930
--- /dev/null
+++ b/pkg/collection_helpers/LICENSE
@@ -0,0 +1,26 @@
+Copyright 2013, the Dart project authors. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google Inc. nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/pkg/collection_helpers/README.md b/pkg/collection_helpers/README.md
index 742cc16..fd20bd2 100644
--- a/pkg/collection_helpers/README.md
+++ b/pkg/collection_helpers/README.md
@@ -1,55 +1,9 @@
-Helper libraries for working with collections.
+Deprecated helper libraries for working with collections.
-The `collection_helpers` package contains a number of separate libraries
-with utility functions and classes that makes working with collections easier.
+The `collection_helpers` package has been split into the
+`collection` package (for most of the library)
+and the `typed_data` package (for typed data buffers).
-## Using
+All further development will happen on those libraries.
-The `collection_helpers` library can be imported as separate libraries, or
-in totality:
-
- import 'package:collection_helpers/equality.dart';
- import 'package:collection_helpers/algorithms.dart';
- import 'package:collection_helpers/wrappers.dart';
-
-or
-
- import 'package:collection_helpers/all.dart';
-
-## Equality
-
-The equality library gives a way to specify equality of elements and
-collections.
-
-Collections in Dart have no inherent equality. Two sets are not equal, even
-if they contain exactly the same objects as elements.
-
-The equality library provides a way to say define such an equality. In this
-case, for example, `const SetEquality(const IdentityEquality())` is an equality
-that considers two sets equal exactly if they contain identical elements.
-
-The library provides ways to define equalities on `Iterable`s, `List`s, `Set`s, and
-`Map`s, as well as combinations of these, such as:
-
- const MapEquality(const IdentityEquality(), const ListEquality());
-
-This equality considers maps equal if they have identical keys, and the corresponding values are lists with equal (`operator==`) values.
-
-## Algorithms
-
-The algorithms library contains functions that operate on lists.
-
-It contains ways to shuffle a `List`, do binary search on a sorted `List`, and
-some different sorting algorithms.
-
-
-## Wrappers
-
-The wrappers library contains classes that "wrap" a collection.
-
-A wrapper class contains an object of the same type, and it forwards all
-methods to the wrapped object.
-
-Wrapper classes can be used in various ways, for example to restrict the type
-of an object to that of a supertype, or to change the behavior of selected
-functions on an existing object.
+Please start using those libraries directly.
diff --git a/pkg/collection_helpers/lib/algorithms.dart b/pkg/collection_helpers/lib/algorithms.dart
index 057111a..85d15ba 100644
--- a/pkg/collection_helpers/lib/algorithms.dart
+++ b/pkg/collection_helpers/lib/algorithms.dart
@@ -2,300 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-/**
- * Operations on collections.
- */
+@deprecated
library dart.collection_helpers.algorithms;
-import "dart:math" show Random;
-
-/** Version of [binarySearch] optimized for comparable keys */
-int _comparableBinarySearch(List<Comparable> list, Comparable key) {
- int min = 0;
- int max = list.length;
- while (min < max) {
- int mid = min + ((max - min) >> 1);
- var element = list[mid];
- int comp = element.compareTo(key);
- if (comp == 0) return mid;
- if (comp < 0) {
- min = mid + 1;
- } else {
- max = mid;
- }
- }
- return -1;
-}
-
-/**
- * Returns a position of the [key] in [sortedList], if it is there.
- *
- * If the list isn't sorted according to the [compare] function, the result
- * is unpredictable.
- *
- * If [compare] is omitted, it defaults to calling [Comparable.compareTo] on
- * the objects.
- *
- * Returns -1 if [key] is not in the list by default.
- */
-int binarySearch(List sortedList, var key,
- { int compare(var a, var b) }) {
- if (compare == null) {
- return _comparableBinarySearch(sortedList, key);
- }
- int min = 0;
- int max = sortedList.length;
- while (min < max) {
- int mid = min + ((max - min) >> 1);
- var element = sortedList[mid];
- int comp = compare(element, key);
- if (comp == 0) return mid;
- if (comp < 0) {
- min = mid + 1;
- } else {
- max = mid;
- }
- }
- return -1;
-}
-
-
-/**
- * Shuffles a list randomly.
- *
- * A sub-range of a list can be shuffled by providing [start] and [end].
- */
-void shuffle(List list, [int start = 0, int end = null]) {
- Random random = new Random();
- if (end == null) end = list.length;
- int length = end - start;
- while (length > 1) {
- int pos = random.nextInt(length);
- length--;
- var tmp1 = list[start + pos];
- list[start + pos] = list[start + length];
- list[start + length] = tmp1;
- }
-}
-
-
-/**
- * Reverses a list, or a part of a list, in-place.
- */
-void reverse(List list, [int start = 0, int end = null]) {
- if (end == null) end = list.length;
- _reverse(list, start, end);
-}
-
-// Internal helper function that assumes valid arguments.
-void _reverse(List list, int start, int end) {
- for (int i = start, j = end - 1; i < j; i++, j--) {
- var tmp = list[i];
- list[i] = list[j];
- list[j] = tmp;
- }
-}
-
-/**
- * Sort a list using insertion sort.
- *
- * Insertion sort is a simple sorting algorithm. For `n` elements it does on
- * the order of `n * log(n)` comparisons but up to `n` squared moves. The
- * sorting is performed in-place, without using extra memory.
- *
- * For short lists the many moves have less impact than the simple algorithm,
- * and it is often the favored sorting algorithm for short lists.
- *
- * This insertion sort is stable: Equal elements end up in the same order
- * as they started in.
- */
-void insertionSort(List list,
- { int compare(a, b),
- int start: 0,
- int end: null }) {
- // If the same method could have both positional and named optional
- // parameters, this should be (list, [start, end], {compare}).
- if (end == null) end = list.length;
- if (compare == null) compare = Comparable.compare;
- _insertionSort(list, compare, start, end, start + 1);
-}
-
-/**
- * Internal helper function that assumes arguments correct.
- *
- * Assumes that the elements up to [sortedUntil] (not inclusive) are
- * already sorted. The [sortedUntil] values should always be at least
- * `start + 1`.
- */
-void _insertionSort(List list, int compare(a, b), int start, int end,
- int sortedUntil) {
- for (int pos = sortedUntil; pos < end; pos++) {
- int min = start;
- int max = pos;
- var element = list[pos];
- while (min < max) {
- int mid = min + ((max - min) >> 1);
- int comparison = compare(element, list[mid]);
- if (comparison < 0) {
- max = mid;
- } else {
- min = mid + 1;
- }
- }
- list.setRange(min + 1, pos + 1, list, min);
- list[min] = element;
- }
-}
-
-/** Limit below which merge sort defaults to insertion sort. */
-const int _MERGE_SORT_LIMIT = 32;
-
-/**
- * Sorts a list, or a range of a list, using the merge sort algorithm.
- *
- * Merge-sorting works by splitting the job into two parts, sorting each
- * recursively, and then merging the two sorted parts.
- *
- * This takes on the order of `n * log(n)` comparisons and moves to sort
- * `n` elements, but requires extra space of about the same size as the list
- * being sorted.
- *
- * This merge sort is stable: Equal elements end up in the same order
- * as they started in.
- */
-void mergeSort(List list, {int start: 0, int end: null, int compare(a, b)}) {
- if (end == null) end = list.length;
- if (compare == null) compare = Comparable.compare;
- int length = end - start;
- if (length < 2) return;
- if (length < _MERGE_SORT_LIMIT) {
- _insertionSort(list, compare, start, end, start + 1);
- return;
- }
- // Special case the first split instead of directly calling
- // _mergeSort, because the _mergeSort requires its target to
- // be different from its source, and it requires extra space
- // of the same size as the list to sort.
- // This split allows us to have only half as much extra space,
- // and it ends up in the original place.
- int middle = start + ((end - start) >> 1);
- int firstLength = middle - start;
- int secondLength = end - middle;
- // secondLength is always the same as firstLength, or one greater.
- List scratchSpace = new List(secondLength);
- _mergeSort(list, compare, middle, end, scratchSpace, 0);
- int firstTarget = end - firstLength;
- _mergeSort(list, compare, start, middle, list, firstTarget);
- _merge(compare,
- list, firstTarget, end,
- scratchSpace, 0, secondLength,
- list, start);
-}
-
-/**
- * Performs an insertion sort into a potentially different list than the
- * one containing the original values.
- *
- * It will work in-place as well.
- */
-void _movingInsertionSort(List list, int compare(a, b), int start, int end,
- List target, int targetOffset) {
- int length = end - start;
- if (length == 0) return;
- target[targetOffset] = list[start];
- for (int i = 1; i < length; i++) {
- var element = list[start + i];
- int min = targetOffset;
- int max = targetOffset + i;
- while (min < max) {
- int mid = min + ((max - min) >> 1);
- if (compare(element, target[mid]) < 0) {
- max = mid;
- } else {
- min = mid + 1;
- }
- }
- target.setRange(min + 1, targetOffset + i + 1,
- target, min);
- target[min] = element;
- }
-}
-
-/**
- * Sorts [list] from [start] to [end] into [target] at [targetOffset].
- *
- * The `target` list must be able to contain the range from `start` to `end`
- * after `targetOffset`.
- *
- * Allows target to be the same list as [list], as long as it's not
- * overlapping the `start..end` range.
- */
-void _mergeSort(List list, int compare(a, b), int start, int end,
- List target, int targetOffset) {
- int length = end - start;
- if (length < _MERGE_SORT_LIMIT) {
- _movingInsertionSort(list, compare, start, end, target, targetOffset);
- return;
- }
- int middle = start + (length >> 1);
- int firstLength = middle - start;
- int secondLength = end - middle;
- // Here secondLength >= firstLength (differs by at most one).
- int targetMiddle = targetOffset + firstLength;
- // Sort the second half into the end of the target area.
- _mergeSort(list, compare, middle, end,
- target, targetMiddle);
- // Sort the first half into the end of the source area.
- _mergeSort(list, compare, start, middle,
- list, middle);
- // Merge the two parts into the target area.
- _merge(compare,
- list, middle, middle + firstLength,
- target, targetMiddle, targetMiddle + secondLength,
- target, targetOffset);
-}
-
-/**
- * Merges two lists into a target list.
- *
- * One of the input lists may be positioned at the end of the target
- * list.
- *
- * For equal object, elements from [firstList] are always preferred.
- * This allows the merge to be stable if the first list contains elements
- * that started out earlier than the ones in [secondList]
- */
-void _merge(int compare(a, b),
- List firstList, int firstStart, int firstEnd,
- List secondList, int secondStart, int secondEnd,
- List target, int targetOffset) {
- // No empty lists reaches here.
- assert(firstStart < firstEnd);
- assert(secondStart < secondEnd);
- int cursor1 = firstStart;
- int cursor2 = secondStart;
- var firstElement = firstList[cursor1++];
- var secondElement = secondList[cursor2++];
- while (true) {
- if (compare(firstElement, secondElement) <= 0) {
- target[targetOffset++] = firstElement;
- if (cursor1 == firstEnd) break; // Flushing second list after loop.
- firstElement = firstList[cursor1++];
- } else {
- target[targetOffset++] = secondElement;
- if (cursor2 != secondEnd) {
- secondElement = secondList[cursor2++];
- continue;
- }
- // Second list empties first. Flushing first list here.
- target[targetOffset++] = firstElement;
- target.setRange(targetOffset, targetOffset + (firstEnd - cursor1),
- firstList, cursor1);
- return;
- }
- }
- // First list empties first. Reached by break above.
- target[targetOffset++] = secondElement;
- target.setRange(targetOffset, targetOffset + (secondEnd - cursor2),
- secondList, cursor2);
-}
+export "package:collection/algorithms.dart";
diff --git a/pkg/collection_helpers/lib/all.dart b/pkg/collection_helpers/lib/all.dart
index 3658cf1..a9f6b63 100644
--- a/pkg/collection_helpers/lib/all.dart
+++ b/pkg/collection_helpers/lib/all.dart
@@ -2,18 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-/**
- * Exports all the individual parts of the collection-helper library.
- *
- * The sub-libraries of this package are:
- *
- * - `algorithms.dart`: Algorithms that work on lists (shuffle, binary search
- * and various sorting algorithms).
- * - `equality.dart`: Different notions of equality of collections.
- * - `typed_buffers.dart`: Growable typed data lists.
- * - `wrappers.dart`: Wrapper classes that delegate to a collection object.
- * Includes unmodifiable views of collections.
- */
+@deprecated
library dart.collection_helper;
export "algorithms.dart";
diff --git a/pkg/collection_helpers/lib/equality.dart b/pkg/collection_helpers/lib/equality.dart
index 2b46266..c47d635 100644
--- a/pkg/collection_helpers/lib/equality.dart
+++ b/pkg/collection_helpers/lib/equality.dart
@@ -2,418 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-/**
- * Defines equality relations on collections.
- */
+@deprecated
library dart.collection_helpers.equality;
-import "dart:collection";
-
-const int _HASH_MASK = 0x7fffffff;
-
-/**
- * A generic equality relation on objects.
- */
-abstract class Equality<E> {
- const factory Equality() = DefaultEquality;
-
- /**
- * Compare two elements for being equal.
- *
- * This should be a proper equality relation.
- */
- bool equals(E e1, E e2);
-
- /**
- * Get a hashcode of an element.
- *
- * The hashcode should be compatible with [equals], so that if
- * `equals(a, b)` then `hash(a) == hash(b)`.
- */
- int hash(E e);
-
- /**
- * Test whether an object is a valid argument to [equals] and [hash].
- *
- * Some implementations may be restricted to only work on specific types
- * of objects.
- */
- bool isValidKey(Object o);
-}
-
-/**
- * Equality of objects that compares only the natural equality of the objects.
- *
- * This equality uses the objects' own [Object.==] and [Object.hashCode] for
- * the equality.
- */
-class DefaultEquality implements Equality {
- const DefaultEquality();
- bool equals(Object e1, Object e2) => e1 == e2;
- int hash(Object e) => e.hashCode;
- bool isValidKey(Object o) => true;
-}
-
-/**
- * Equality of objects that compares only the identity of the objects.
- */
-class IdentityEquality implements Equality {
- const IdentityEquality();
- bool equals(Object e1, Object e2) => identical(e1, e2);
- int hash(Object e) => identityHashCode(e);
- bool isValidKey(Object o) => true;
-}
-
-/**
- * Equality on iterables.
- *
- * Two iterables are equal if they have the same elements in the same order.
- */
-class IterableEquality<E> implements Equality<Iterable<E>> {
- final Equality<E> _elementEquality;
- const IterableEquality([Equality<E> elementEquality =
- const DefaultEquality()])
- : _elementEquality = elementEquality;
-
- bool equals(Iterable<E> elements1, Iterable<E> elements2) {
- if (identical(elements1, elements2)) return true;
- if (elements1 == null || elements2 == null) return false;
- Iterator it1 = elements1.iterator;
- Iterator it2 = elements2.iterator;
- while (true) {
- bool hasNext = it1.moveNext();
- if (hasNext != it2.moveNext()) return false;
- if (!hasNext) return true;
- if (!_elementEquality.equals(it1.current, it2.current)) return false;
- }
- }
-
- int hash(Iterable<E> elements) {
- // Jenkins's one-at-a-time hash function.
- int hash = 0;
- for (E element in elements) {
- int c = _elementEquality.hash(element);
- hash = (hash + c) & _HASH_MASK;
- hash = (hash + (hash << 10)) & _HASH_MASK;
- hash ^= (hash >> 6);
- }
- hash = (hash + (hash << 3)) & _HASH_MASK;
- hash ^= (hash >> 11);
- hash = (hash + (hash << 15)) & _HASH_MASK;
- return hash;
- }
-
- bool isValidKey(Object o) => o is Iterable<E>;
-}
-
-/**
- * Equality on lists.
- *
- * Two lists are equal if they have the same length and their elements
- * at each index are equal.
- *
- * This is effectively the same as [IterableEquality] except that it
- * accesses elements by index instead of through iteration.
- */
-class ListEquality<E> implements Equality<List<E>> {
- final Equality<E> _elementEquality;
- const ListEquality([Equality<E> elementEquality = const DefaultEquality()])
- : _elementEquality = elementEquality;
-
- bool equals(List<E> e1, List<E> e2) {
- if (identical(e1, e2)) return true;
- if (e1 == null || e2 == null) return false;
- int length = e1.length;
- if (length != e2.length) return false;
- for (int i = 0; i < length; i++) {
- if (!_elementEquality.equals(e1[i], e2[i])) return false;
- }
- return true;
- }
-
- int hash(List<E> e) {
- // Jenkins's one-at-a-time hash function.
- // This code is almost identical to the one in IterableEquality, except
- // that it uses indexing instead of iterating to get the elements.
- int hash = 0;
- for (int i = 0; i < e.length; i++) {
- int c = _elementEquality.hash(e[i]);
- hash = (hash + c) & _HASH_MASK;
- hash = (hash + (hash << 10)) & _HASH_MASK;
- hash ^= (hash >> 6);
- }
- hash = (hash + (hash << 3)) & _HASH_MASK;
- hash ^= (hash >> 11);
- hash = (hash + (hash << 15)) & _HASH_MASK;
- return hash;
- }
-
- bool isValidKey(Object o) => o is List<E>;
-}
-
-abstract class _UnorderedEquality<E, T extends Iterable<E>>
- implements Equality<T> {
- final Equality<E> _elementEquality;
-
- const _UnorderedEquality(this._elementEquality);
-
- bool equals(T e1, T e2) {
- if (identical(e1, e2)) return true;
- if (e1 == null || e2 == null) return false;
- HashMap<E, int> counts = new HashMap(
- equals: _elementEquality.equals,
- hashCode: _elementEquality.hash,
- isValidKey: _elementEquality.isValidKey);
- int length = 0;
- for (var e in e1) {
- int count = counts[e];
- if (count == null) count = 0;
- counts[e] = count + 1;
- length++;
- }
- for (var e in e2) {
- int count = counts[e];
- if (count == null || count == 0) return false;
- counts[e] = count - 1;
- length--;
- }
- return length == 0;
- }
-
- int hash(T e) {
- int hash = 0;
- for (E element in e) {
- int c = _elementEquality.hash(element);
- hash = (hash + c) & _HASH_MASK;
- }
- hash = (hash + (hash << 3)) & _HASH_MASK;
- hash ^= (hash >> 11);
- hash = (hash + (hash << 15)) & _HASH_MASK;
- return hash;
- }
-}
-
-/**
- * Equality of the elements of two iterables without considering order.
- *
- * Two iterables are considered equal if they have the same number of elements,
- * and the elements of one set can be paired with the elements
- * of the other iterable, so that each pair are equal.
- */
-class UnorderedIterableEquality<E> extends _UnorderedEquality<E, Iterable<E>> {
- const UnorderedIterableEquality(
- [Equality<E> elementEquality = const DefaultEquality()])
- : super(elementEquality);
-
- bool isValidKey(Object o) => o is Iterable<E>;
-}
-
-/**
- * Equality of sets.
- *
- * Two sets are considered equal if they have the same number of elements,
- * and the elements of one set can be paired with the elements
- * of the other set, so that each pair are equal.
- *
- * This equality behaves the same as [UnorderedIterableEquality] except that
- * it expects sets instead of iterables as arguments.
- */
-class SetEquality<E> extends _UnorderedEquality<E, Set<E>> {
- const SetEquality(
- [Equality<E> elementEquality = const DefaultEquality()])
- : super(elementEquality);
-
- bool isValidKey(Object o) => o is Set<E>;
-}
-
-/**
- * Internal class used by [MapEquality].
- *
- * The class represents a map entry as a single object,
- * using a combined hashCode and equality of the key and value.
- */
-class _MapEntry {
- final MapEquality equality;
- final key;
- final value;
- _MapEntry(this.equality, this.key, this.value);
-
- int get hashCode =>
- (3 * equality._keyEquality.hash(key) +
- 7 * equality._valueEquality.hash(value)) & _HASH_MASK;
-
- bool operator==(Object other) {
- if (other is! _MapEntry) return false;
- _MapEntry otherEntry = other;
- return equality._keyEquality.equals(key, otherEntry.key) &&
- equality._valueEquality.equals(value, otherEntry.value);
-
- }
-}
-
-/**
- * Equality on maps.
- *
- * Two maps are equal if they have the same number of entries, and if the
- * entries of the two maps are pairwise equal on both key and value.
- */
-class MapEquality<K, V> implements Equality<Map<K, V>> {
- final Equality<K> _keyEquality;
- final Equality<V> _valueEquality;
- const MapEquality({ Equality<K> keys : const DefaultEquality(),
- Equality<V> values : const DefaultEquality() })
- : _keyEquality = keys, _valueEquality = values;
-
- bool equals(Map<K, V> e1, Map<K, V> e2) {
- if (identical(e1, e2)) return true;
- if (e1 == null || e2 == null) return false;
- int length = e1.length;
- if (length != e2.length) return false;
- Map<_MapEntry, int> equalElementCounts = new HashMap();
- for (K key in e1.keys) {
- _MapEntry entry = new _MapEntry(this, key, e1[key]);
- int count = equalElementCounts[entry];
- if (count == null) count = 0;
- equalElementCounts[entry] = count + 1;
- }
- for (K key in e2.keys) {
- _MapEntry entry = new _MapEntry(this, key, e2[key]);
- int count = equalElementCounts[entry];
- if (count == null || count == 0) return false;
- equalElementCounts[entry] = count - 1;
- }
- return true;
- }
-
- int hash(Map<K, V> map) {
- int hash = 0;
- for (K key in map.keys) {
- int keyHash = _keyEquality.hash(key);
- int valueHash = _valueEquality.hash(map[key]);
- hash = (hash + 3 * keyHash + 7 * valueHash) & _HASH_MASK;
- }
- hash = (hash + (hash << 3)) & _HASH_MASK;
- hash ^= (hash >> 11);
- hash = (hash + (hash << 15)) & _HASH_MASK;
- return hash;
- }
-
- bool isValidKey(Object o) => o is Map<K, V>;
-}
-
-/**
- * Combines several equalities into a single equality.
- *
- * Tries each equality in order, using [Equality.isValidKey], and returns
- * the result of the first equality that applies to the argument or arguments.
- *
- * For `equals`, the first equality that matches the first argument is used,
- * and if the second argument of `equals` is not valid for that equality,
- * it returns false.
- *
- * Because the equalities are tried in order, they should generally work on
- * disjoint types. Otherwise the multi-equality may give inconsistent results
- * for `equals(e1, e2)` and `equals(e2, e1)`. This can happen if one equality
- * considers only `e1` a valid key, and not `e2`, but an equality which is
- * checked later, allows both.
- */
-class MultiEquality<E> implements Equality<E> {
- final Iterable<Equality<E>> _equalities;
-
- const MultiEquality(Iterable<Equality<E>> equalities)
- : _equalities = equalities;
-
- bool equals(E e1, E e2) {
- for (Equality<E> eq in _equalities) {
- if (eq.isValidKey(e1)) return eq.isValidKey(e2) && eq.equals(e1, e2);
- }
- return false;
- }
-
- int hash(E e) {
- for (Equality<E> eq in _equalities) {
- if (eq.isValidKey(e)) return eq.hash(e);
- }
- return -1;
- }
-
- bool isValidKey(Object o) {
- for (Equality<E> eq in _equalities) {
- if (eq.isValidKey(o)) return true;
- }
- return false;
- }
-}
-
-/**
- * Deep equality on collections.
- *
- * Recognizes lists, sets, iterables and maps and compares their elements using
- * deep equality as well.
- *
- * Non-iterable/map objects are compared using a configurable base equality.
- *
- * Works in one of two modes: ordered or unordered.
- *
- * In ordered mode, lists and iterables are required to have equal elements
- * in the same order. In unordered mode, the order of elements in iterables
- * and lists are not importan.
- *
- * A list is only equal to another list, likewise for sets and maps. All other
- * iterables are compared as iterables only.
- */
-class DeepCollectionEquality implements Equality {
- final Equality _base;
- final bool _unordered;
- const DeepCollectionEquality([Equality base = const DefaultEquality()])
- : _base = base, _unordered = false;
-
- /**
- * Creates a deep equality on collections where the order of lists and
- * iterables are not considered important. That is, lists and iterables are
- * treated as unordered iterables.
- */
- const DeepCollectionEquality.unordered(
- [Equality base = const DefaultEquality()])
- : _base = base, _unordered = true;
-
- bool equals(e1, e2) {
- if (e1 is Set) {
- if (e2 is! Set) return false;
- return new SetEquality(this).equals(e1, e2);
- }
- if (e1 is Map) {
- if (e2 is! Map) return false;
- return new MapEquality(keys: this, values: this).equals(e1, e2);
- }
- if (!_unordered) {
- if (e1 is List) {
- if (e2 is! List) return false;
- return new ListEquality(this).equals(e1, e2);
- }
- if (e1 is Iterable) {
- if (e2 is! Iterable) return false;
- return new IterableEquality(this).equals(e1, e2);
- }
- } else if (e1 is Iterable) {
- if (e2 is! Iterable) return false;
- if (e1 is List != e2 is List) return false;
- return new UnorderedIterableEquality(this).equals(e1, e2);
- }
- return _base.equals(e1, e2);
- }
-
- int hash(Object o) {
- if (o is Set) return new SetEquality(this).hash(o);
- if (o is Map) return new MapEquality(keys: this, values: this).hash(o);
- if (!_unordered) {
- if (o is List) return new ListEquality(this).hash(o);
- if (o is Iterable) return new IterableEquality(this).hash(o);
- } else if (o is Iterable) {
- return new UnorderedIterableEquality(this).hash(o);
- }
- return _base.hash(o);
- }
-
- bool isValidKey(Object o) => o is Iterable || o is Map || _base.isValidKey(o);
-}
+export "package:collection/equality.dart";
diff --git a/pkg/collection_helpers/lib/typed_buffers.dart b/pkg/collection_helpers/lib/typed_buffers.dart
index 2f331e7..612e3df 100644
--- a/pkg/collection_helpers/lib/typed_buffers.dart
+++ b/pkg/collection_helpers/lib/typed_buffers.dart
@@ -2,234 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-/**
- * Growable typed-data lists.
- *
- * These lists works just as a typed-data list, except that they are growable.
- * They use an underlying buffer, and when that buffer becomes too small, it
- * is replaced by a new buffer.
- *
- * That means that using the [TypedDataView.buffer] getter is not guaranteed
- * to return the same result each time it is used, and that the buffer may
- * be larger than what the list is using.
- */
+@deprecated
library dart.collection_helpers.typed_buffers;
-import "dart:collection" show ListBase;
-import "dart:typed_data";
-
-abstract class _TypedDataBuffer<E> extends ListBase<E> {
- static const int INITIAL_LENGTH = 8;
-
- /// This is a Uint8List for Uint8Buffer. It's both a List<E> and a TypedData,
- /// which we don't have a type for here.
- var _buffer;
- /// The length of the list being built.
- int _length;
-
- _TypedDataBuffer(List<E> buffer)
- : this._buffer = buffer, this._length = buffer.length;
-
- int get length => _length;
- E operator[](int index) {
- if (index >= length) throw new RangeError.range(index, 0, length - 1);
- return _buffer[index];
- }
-
- void operator[]=(int index, E value) {
- if (index >= length) throw new RangeError.range(index, 0, length - 1);
- _buffer[index] = value;
- }
-
- void set length(int newLength) {
- if (newLength < _length) {
- E defaultValue = _defaultValue;
- for (int i = newLength; i < _length; i++) {
- _buffer[i] = defaultValue;
- }
- } else if (newLength > _buffer.length) {
- List<E> newBuffer;
- if (_buffer.length == 0) {
- newBuffer = _createBuffer(newLength);
- } else {
- newBuffer = _createBiggerBuffer(newLength);
- }
- newBuffer.setRange(0, _length, _buffer);
- _buffer = newBuffer;
- }
- _length = newLength;
- }
-
- void _add(E value) {
- if (_length == _buffer.length) _grow();
- _buffer[_length++] = value;
- }
-
- // We override the default implementation of `add` and `addAll` because
- // they grow by setting the length in increments of one. We want to grow
- // by doubling capacity in most cases.
- void add(E value) { _add(value); }
-
- void addAll(Iterable<E> values) {
- for (E value in values) _add(value);
- }
-
- void insert(int index, E element) {
- if (index < 0 || index > _length) {
- throw new RangeError.range(index, 0, _length);
- }
- if (_length < _buffer.length) {
- _buffer.setRange(index + 1, _length + 1, _buffer, index);
- _buffer[index] = element;
- _length++;
- return;
- }
- List<E> newBuffer = _createBiggerBuffer(null);
- newBuffer.setRange(0, index, _buffer);
- newBuffer.setRange(index + 1, _length + 1, _buffer, index);
- newBuffer[index] = element;
- _length++;
- _buffer = newBuffer;
- }
-
- /**
- * Create a bigger buffer.
- *
- * This method determines how much bigger a bigger buffer should
- * be. If [requiredLength] is not null, it will be at least that
- * size. It will always have at least have double the capacity of
- * the current buffer.
- */
- List<E> _createBiggerBuffer(int requiredLength) {
- int newLength = _buffer.length * 2;
- if (requiredLength != null && newLength < requiredLength) {
- newLength = requiredLength;
- } else if (newLength < INITIAL_LENGTH) {
- newLength = INITIAL_LENGTH;
- }
- return _createBuffer(newLength);
- }
-
- void _grow() {
- _buffer = _createBiggerBuffer(null)..setRange(0, _length, _buffer);
- }
-
- void setRange(int start, int end, Iterable<E> source, [int skipCount = 0]) {
- if (end > _length) throw new RangeError.range(end, 0, _length);
- if (source is _TypedDataBuffer<E>) {
- _buffer.setRange(start, end, source._buffer, skipCount);
- } else {
- _buffer.setRange(start, end, source, skipCount);
- }
- }
-
- // TypedData.
-
- int get elementSizeInBytes => _buffer.elementSizeInBytes;
-
- int get lengthInBytes => _length * _buffer.elementSizeInBytes;
-
- int get offsetInBytes => _buffer.offsetInBytes;
-
- /**
- * Returns the underlying [ByteBuffer].
- *
- * The returned buffer may be replaced by operations that change the [length]
- * of this list.
- *
- * The buffer may be larger than [lengthInBytes] bytes, but never smaller.
- */
- ByteBuffer get buffer => _buffer.buffer;
-
- // Specialization for the specific type.
-
- // Return zero for integers, 0.0 for floats, etc.
- // Used to fill buffer when changing length.
- E get _defaultValue;
-
- // Create a new typed list to use as buffer.
- List<E> _createBuffer(int size);
-}
-
-abstract class _IntBuffer extends _TypedDataBuffer<int> {
- _IntBuffer(buffer): super(buffer);
- int get _defaultValue => 0;
-}
-
-abstract class _FloatBuffer extends _TypedDataBuffer<double> {
- _FloatBuffer(buffer): super(buffer);
- double get _defaultValue => 0.0;
-}
-
-class Uint8Buffer extends _IntBuffer {
- Uint8Buffer([int initialLength = 0]) : super(new Uint8List(initialLength));
- Uint8List _createBuffer(int size) => new Uint8List(size);
-}
-
-class Int8Buffer extends _IntBuffer {
- Int8Buffer([int initialLength = 0]) : super(new Int8List(initialLength));
- Int8List _createBuffer(int size) => new Int8List(size);
-}
-
-class Uint8ClampedBuffer extends _IntBuffer {
- Uint8ClampedBuffer([int initialLength = 0])
- : super(new Uint8ClampedList(initialLength));
- Uint8ClampedList _createBuffer(int size) => new Uint8ClampedList(size);
-}
-
-class Uint16Buffer extends _IntBuffer {
- Uint16Buffer([int initialLength = 0]) : super(new Uint16List(initialLength));
- Uint16List _createBuffer(int size) => new Uint16List(size);
-}
-
-class Int16Buffer extends _IntBuffer {
- Int16Buffer([int initialLength = 0]) : super(new Int16List(initialLength));
- Int16List _createBuffer(int size) => new Int16List(size);
-}
-
-class Uint32Buffer extends _IntBuffer {
- Uint32Buffer([int initialLength = 0]) : super(new Uint32List(initialLength));
- Uint32List _createBuffer(int size) => new Uint32List(size);
-}
-
-class Int32Buffer extends _IntBuffer {
- Int32Buffer([int initialLength = 0]) : super(new Int32List(initialLength));
- Int32List _createBuffer(int size) => new Int32List(size);
-}
-
-class Uint64Buffer extends _IntBuffer {
- Uint64Buffer([int initialLength = 0]) : super(new Uint64List(initialLength));
- Uint64List _createBuffer(int size) => new Uint64List(size);
-}
-
-class Int64Buffer extends _IntBuffer {
- Int64Buffer([int initialLength = 0]) : super(new Int64List(initialLength));
- Int64List _createBuffer(int size) => new Int64List(size);
-}
-
-class Float32Buffer extends _FloatBuffer {
- Float32Buffer([int initialLength = 0])
- : super(new Float32List(initialLength));
- Float32List _createBuffer(int size) => new Float32List(size);
-}
-
-class Float64Buffer extends _FloatBuffer {
- Float64Buffer([int initialLength = 0])
- : super(new Float64List(initialLength));
- Float64List _createBuffer(int size) => new Float64List(size);
-}
-
-class Int32x4Buffer extends _TypedDataBuffer<Int32x4> {
- static Int32x4 _zero = new Int32x4(0, 0, 0, 0);
- Int32x4Buffer([int initialLength = 0])
- : super(new Int32x4List(initialLength));
- Int32x4 get _defaultValue => _zero;
- Int32x4List _createBuffer(int size) => new Int32x4List(size);
-}
-
-class Float32x4Buffer extends _TypedDataBuffer<Float32x4> {
- Float32x4Buffer([int initialLength = 0])
- : super(new Float32x4List(initialLength));
- Float32x4 get _defaultValue => new Float32x4.zero();
- Float32x4List _createBuffer(int size) => new Float32x4List(size);
-}
+export "package:typed_data/typed_buffers.dart";
diff --git a/pkg/collection_helpers/lib/wrappers.dart b/pkg/collection_helpers/lib/wrappers.dart
index 3576cc0..d408151 100644
--- a/pkg/collection_helpers/lib/wrappers.dart
+++ b/pkg/collection_helpers/lib/wrappers.dart
@@ -2,333 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-/**
- * Delegating wrappers for [Iterable], [List], [Set], [Queue] and [Map].
- *
- * Also adds unmodifiable views for `Set` and `Map`, and a fixed length
- * view for `List`. The unmodifable list view from `dart:collection` is exported
- * as well, just for completeness.
- */
+@deprecated
library dart.collection_helpers.wrappers;
-import "dart:collection";
-import "dart:math" show Random;
-
-export "dart:collection" show UnmodifiableListView;
-
-part "unmodifiable_wrappers.dart";
-
-/**
- * Creates an [Iterable] that delegates all operations to a base iterable.
- *
- * This class can be used hide non-`Iterable` methods of an iterable object,
- * or it can be extended to add extra functionality on top of an existing
- * iterable object.
- */
-class DelegatingIterable<E> implements Iterable<E> {
- Iterable<E> _base;
-
- /**
- * Create a wrapper that forwards operations to [base].
- */
- DelegatingIterable(Iterable<E> base) : _base = base;
-
- bool any(bool test(E element)) => _base.any(test);
-
- bool contains(Object element) => _base.contains(element);
-
- E elementAt(int index) => _base.elementAt(index);
-
- bool every(bool test(E element)) => _base.every(test);
-
- Iterable expand(Iterable f(E element)) => _base.expand(f);
-
- E get first => _base.first;
-
- E firstWhere(bool test(E element), {E orElse()}) =>
- _base.firstWhere(test, orElse: orElse);
-
- fold(initialValue, combine(previousValue, E element)) =>
- _base.fold(initialValue, combine);
-
- void forEach(void f(E element)) => _base.forEach(f);
-
- bool get isEmpty => _base.isEmpty;
-
- bool get isNotEmpty => _base.isNotEmpty;
-
- Iterator<E> get iterator => _base.iterator;
-
- String join([String separator = ""]) => _base.join(separator);
-
- E get last => _base.last;
-
- E lastWhere(bool test(E element), {E orElse()}) =>
- _base.lastWhere(test, orElse: orElse);
-
- int get length => _base.length;
-
- Iterable map(f(E element)) => _base.map(f);
-
- E reduce(E combine(E value, E element)) => _base.reduce(combine);
-
- E get single => _base.single;
-
- E singleWhere(bool test(E element)) => _base.singleWhere(test);
-
- Iterable<E> skip(int n) => _base.skip(n);
-
- Iterable<E> skipWhile(bool test(E value)) => _base.skipWhile(test);
-
- Iterable<E> take(int n) => _base.take(n);
-
- Iterable<E> takeWhile(bool test(E value)) => _base.takeWhile(test);
-
- List<E> toList({bool growable: true}) => _base.toList(growable: growable);
-
- Set<E> toSet() => _base.toSet();
-
- Iterable<E> where(bool test(E element)) => _base.where(test);
-}
-
-
-/**
- * Creates a [List] that delegates all operations to a base list.
- *
- * This class can be used hide non-`List` methods of a list object,
- * or it can be extended to add extra functionality on top of an existing
- * list object.
- */
-class DelegatingList<E> extends DelegatingIterable<E> implements List<E> {
- DelegatingList(List<E> base) : super(base);
-
- List<E> get _listBase => _base;
-
- E operator [](int index) => _listBase[index];
-
- void operator []=(int index, E value) {
- _listBase[index] = value;
- }
-
- void add(E value) {
- _listBase.add(value);
- }
-
- void addAll(Iterable<E> iterable) {
- _listBase.addAll(iterable);
- }
-
- Map<int, E> asMap() => _listBase.asMap();
-
- void clear() {
- _listBase.clear();
- }
-
- void fillRange(int start, int end, [E fillValue]) {
- _listBase.fillRange(start, end, fillValue);
- }
-
- Iterable<E> getRange(int start, int end) => _listBase.getRange(start, end);
-
- int indexOf(E element, [int start = 0]) => _listBase.indexOf(element, start);
-
- void insert(int index, E element) {
- _listBase.insert(index, element);
- }
-
- void insertAll(int index, Iterable<E> iterable) {
- _listBase.insertAll(index, iterable);
- }
-
- int lastIndexOf(E element, [int start]) =>
- _listBase.lastIndexOf(element, start);
-
- void set length(int newLength) {
- _listBase.length = newLength;
- }
-
- bool remove(Object value) => _listBase.remove(value);
-
- E removeAt(int index) => _listBase.removeAt(index);
-
- E removeLast() => _listBase.removeLast();
-
- void removeRange(int start, int end) {
- _listBase.removeRange(start, end);
- }
-
- void removeWhere(bool test(E element)) {
- _listBase.removeWhere(test);
- }
-
- void replaceRange(int start, int end, Iterable<E> iterable) {
- _listBase.replaceRange(start, end, iterable);
- }
-
- void retainWhere(bool test(E element)) {
- _listBase.retainWhere(test);
- }
-
- Iterable<E> get reversed => _listBase.reversed;
-
- void setAll(int index, Iterable<E> iterable) {
- _listBase.setAll(index, iterable);
- }
-
- void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
- _listBase.setRange(start, end, iterable, skipCount);
- }
-
- void shuffle([Random random]) {
- _listBase.shuffle(random);
- }
-
- void sort([int compare(E a, E b)]) {
- _listBase.sort(compare);
- }
-
- List<E> sublist(int start, [int end]) => _listBase.sublist(start, end);
-}
-
-
-/**
- * Creates a [Set] that delegates all operations to a base set.
- *
- * This class can be used hide non-`Set` methods of a set object,
- * or it can be extended to add extra functionality on top of an existing
- * set object.
- */
-class DelegatingSet<E> extends DelegatingIterable<E> implements Set<E> {
- DelegatingSet(Set<E> base) : super(base);
-
- Set<E> get _setBase => _base;
-
- bool add(E value) => _setBase.add(value);
-
- void addAll(Iterable<E> elements) {
- _setBase.addAll(elements);
- }
-
- void clear() {
- _setBase.clear();
- }
-
- bool containsAll(Iterable<Object> other) => _setBase.containsAll(other);
-
- Set<E> difference(Set<E> other) => _setBase.difference(other);
-
- Set<E> intersection(Set<Object> other) => _setBase.intersection(other);
-
- E lookup(E element) => _setBase.lookup(element);
-
- bool remove(Object value) => _setBase.remove(value);
-
- void removeAll(Iterable<Object> elements) {
- _setBase.removeAll(elements);
- }
-
- void removeWhere(bool test(E element)) {
- _setBase.removeWhere(test);
- }
-
- void retainAll(Iterable<Object> elements) {
- _setBase.retainAll(elements);
- }
-
- void retainWhere(bool test(E element)) {
- _setBase.retainWhere(test);
- }
-
- Set<E> union(Set<E> other) => _setBase.union(other);
-}
-
-/**
- * Creates a [Queue] that delegates all operations to a base queue.
- *
- * This class can be used hide non-`Queue` methods of a queue object,
- * or it can be extended to add extra functionality on top of an existing
- * queue object.
- */
-class DelegatingQueue<E> extends DelegatingIterable<E> implements Queue<E> {
- DelegatingQueue(Queue<E> queue) : super(queue);
-
- Queue<E> get _baseQueue => _base;
-
- void add(E value) {
- _baseQueue.add(value);
- }
-
- void addAll(Iterable<E> iterable) {
- _baseQueue.addAll(iterable);
- }
-
- void addFirst(E value) {
- _baseQueue.addFirst(value);
- }
-
- void addLast(E value) {
- _baseQueue.addLast(value);
- }
-
- void clear() {
- _baseQueue.clear();
- }
-
- bool remove(Object object) => _baseQueue.remove(object);
-
- void removeWhere(bool test(E element)) { _baseQueue.removeWhere(test); }
-
- void retainWhere(bool test(E element)) { _baseQueue.retainWhere(test); }
-
- E removeFirst() => _baseQueue.removeFirst();
-
- E removeLast() => _baseQueue.removeLast();
-}
-
-/**
- * Creates a [Map] that delegates all operations to a base map.
- *
- * This class can be used hide non-`Map` methods of an object that extends
- * `Map`, or it can be extended to add extra functionality on top of an existing
- * map object.
- */
-class DelegatingMap<K, V> implements Map<K, V> {
- Map<K, V> _base;
- DelegatingMap(Map<K, V> base) : _base = base;
-
- V operator [](Object key) => _base[key];
-
- void operator []=(K key, V value) {
- _base[key] = value;
- }
-
- void addAll(Map<K, V> other) {
- _base.addAll(other);
- }
-
- void clear() {
- _base.clear();
- }
-
- bool containsKey(Object key) => _base.containsKey(key);
-
- bool containsValue(Object value) => _base.containsValue(value);
-
- void forEach(void f(K key, V value)) {
- _base.forEach(f);
- }
-
- bool get isEmpty => _base.isEmpty;
-
- bool get isNotEmpty => _base.isNotEmpty;
-
- Iterable<K> get keys => _base.keys;
-
- int get length => _base.length;
-
- V putIfAbsent(K key, V ifAbsent()) => _base.putIfAbsent(key, ifAbsent);
-
- V remove(Object key) => _base.remove(key);
-
- Iterable<V> get values => _base.values;
-}
+export "package:collection/wrappers.dart";
diff --git a/pkg/collection_helpers/pubspec.yaml b/pkg/collection_helpers/pubspec.yaml
index 482ca1c..0002f71 100644
--- a/pkg/collection_helpers/pubspec.yaml
+++ b/pkg/collection_helpers/pubspec.yaml
@@ -1,9 +1,10 @@
name: collection_helpers
-version: 0.9.1
-author: "Dart Team <misc@dartlang.org>"
-description: Utility functions and classes for working with collections.
+version: 0.9.2
+author: Dart Team <misc@dartlang.org>
+description: Discontinued. Use package:collection or package:typed_data.
homepage: http://www.dartlang.org
-dev_dependencies:
- unittest: ">=0.9.0 <0.10.0"
+dependencies:
+ collection: "0.9.0"
+ typed_data: "0.9.0"
environment:
sdk: ">=1.0.0 <2.0.0"
diff --git a/pkg/custom_element/lib/custom-elements.debug.js b/pkg/custom_element/lib/custom-elements.debug.js
index fff3b8a..3860932a 100644
--- a/pkg/custom_element/lib/custom-elements.debug.js
+++ b/pkg/custom_element/lib/custom-elements.debug.js
@@ -1151,6 +1151,11 @@
// getPrototypeOf(Element), we cannot do so when
// we use mixin, so we install a magic reference
customMixin(element, definition.prototype, definition.native);
+
+ // Dart note: make sure we pick up the right constructor.
+ // dart2js depends on this for dart:mirrors caching to work.
+ // See tests/html/custom/mirrors_test.dart
+ element.constructor = definition.prototype.constructor;
element.__proto__ = definition.prototype;
}
}
diff --git a/pkg/custom_element/lib/custom-elements.min.js b/pkg/custom_element/lib/custom-elements.min.js
index cb5746f..713ae84 100644
--- a/pkg/custom_element/lib/custom-elements.min.js
+++ b/pkg/custom_element/lib/custom-elements.min.js
@@ -25,4 +25,4 @@
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-"undefined"==typeof WeakMap&&!function(){var a=Object.defineProperty,b=Date.now()%1e9,c=function(){this.name="__st"+(1e9*Math.random()>>>0)+(b++ +"__")};c.prototype={set:function(b,c){var d=b[this.name];d&&d[0]===b?d[1]=c:a(b,this.name,{value:[b,c],writable:!0})},get:function(a){var b;return(b=a[this.name])&&b[0]===a?b[1]:void 0},"delete":function(a){this.set(a,void 0)}},window.WeakMap=c}(),function(a){function b(a){u.push(a),t||(t=!0,q(d))}function c(a){return window.ShadowDOMPolyfill&&window.ShadowDOMPolyfill.wrapIfNeeded(a)||a}function d(){t=!1;var a=u;u=[],a.sort(function(a,b){return a.uid_-b.uid_});var b=!1;a.forEach(function(a){var c=a.takeRecords();e(a),c.length&&(a.callback_(c,a),b=!0)}),b&&d()}function e(a){a.nodes_.forEach(function(b){var c=p.get(b);c&&c.forEach(function(b){b.observer===a&&b.removeTransientObservers()})})}function f(a,b){for(var c=a;c;c=c.parentNode){var d=p.get(c);if(d)for(var e=0;e<d.length;e++){var f=d[e],g=f.options;if(c===a||g.subtree){var h=b(g);h&&f.enqueue(h)}}}}function g(a){this.callback_=a,this.nodes_=[],this.records_=[],this.uid_=++v}function h(a,b){this.type=a,this.target=b,this.addedNodes=[],this.removedNodes=[],this.previousSibling=null,this.nextSibling=null,this.attributeName=null,this.attributeNamespace=null,this.oldValue=null}function i(a){var b=new h(a.type,a.target);return b.addedNodes=a.addedNodes.slice(),b.removedNodes=a.removedNodes.slice(),b.previousSibling=a.previousSibling,b.nextSibling=a.nextSibling,b.attributeName=a.attributeName,b.attributeNamespace=a.attributeNamespace,b.oldValue=a.oldValue,b}function j(a,b){return w=new h(a,b)}function k(a){return x?x:(x=i(w),x.oldValue=a,x)}function l(){w=x=void 0}function m(a){return a===x||a===w}function n(a,b){return a===b?a:x&&m(a)?x:null}function o(a,b,c){this.observer=a,this.target=b,this.options=c,this.transientObservedNodes=[]}var p=new WeakMap,q=window.msSetImmediate;if(!q){var r=[],s=String(Math.random());window.addEventListener("message",function(a){if(a.data===s){var b=r;r=[],b.forEach(function(a){a()})}}),q=function(a){r.push(a),window.postMessage(s,"*")}}var t=!1,u=[],v=0;g.prototype={observe:function(a,b){if(a=c(a),!b.childList&&!b.attributes&&!b.characterData||b.attributeOldValue&&!b.attributes||b.attributeFilter&&b.attributeFilter.length&&!b.attributes||b.characterDataOldValue&&!b.characterData)throw new SyntaxError;var d=p.get(a);d||p.set(a,d=[]);for(var e,f=0;f<d.length;f++)if(d[f].observer===this){e=d[f],e.removeListeners(),e.options=b;break}e||(e=new o(this,a,b),d.push(e),this.nodes_.push(a)),e.addListeners()},disconnect:function(){this.nodes_.forEach(function(a){for(var b=p.get(a),c=0;c<b.length;c++){var d=b[c];if(d.observer===this){d.removeListeners(),b.splice(c,1);break}}},this),this.records_=[]},takeRecords:function(){var a=this.records_;return this.records_=[],a}};var w,x;o.prototype={enqueue:function(a){var c=this.observer.records_,d=c.length;if(c.length>0){var e=c[d-1],f=n(e,a);if(f)return c[d-1]=f,void 0}else b(this.observer);c[d]=a},addListeners:function(){this.addListeners_(this.target)},addListeners_:function(a){var b=this.options;b.attributes&&a.addEventListener("DOMAttrModified",this,!0),b.characterData&&a.addEventListener("DOMCharacterDataModified",this,!0),b.childList&&a.addEventListener("DOMNodeInserted",this,!0),(b.childList||b.subtree)&&a.addEventListener("DOMNodeRemoved",this,!0)},removeListeners:function(){this.removeListeners_(this.target)},removeListeners_:function(a){var b=this.options;b.attributes&&a.removeEventListener("DOMAttrModified",this,!0),b.characterData&&a.removeEventListener("DOMCharacterDataModified",this,!0),b.childList&&a.removeEventListener("DOMNodeInserted",this,!0),(b.childList||b.subtree)&&a.removeEventListener("DOMNodeRemoved",this,!0)},addTransientObserver:function(a){if(a!==this.target){this.addListeners_(a),this.transientObservedNodes.push(a);var b=p.get(a);b||p.set(a,b=[]),b.push(this)}},removeTransientObservers:function(){var a=this.transientObservedNodes;this.transientObservedNodes=[],a.forEach(function(a){this.removeListeners_(a);for(var b=p.get(a),c=0;c<b.length;c++)if(b[c]===this){b.splice(c,1);break}},this)},handleEvent:function(a){switch(a.stopImmediatePropagation(),a.type){case"DOMAttrModified":var b=a.attrName,c=a.relatedNode.namespaceURI,d=a.target,e=new j("attributes",d);e.attributeName=b,e.attributeNamespace=c;var g=a.attrChange===MutationEvent.ADDITION?null:a.prevValue;f(d,function(a){return!a.attributes||a.attributeFilter&&a.attributeFilter.length&&-1===a.attributeFilter.indexOf(b)&&-1===a.attributeFilter.indexOf(c)?void 0:a.attributeOldValue?k(g):e});break;case"DOMCharacterDataModified":var d=a.target,e=j("characterData",d),g=a.prevValue;f(d,function(a){return a.characterData?a.characterDataOldValue?k(g):e:void 0});break;case"DOMNodeRemoved":this.addTransientObserver(a.target);case"DOMNodeInserted":var h,i,d=a.relatedNode,m=a.target;"DOMNodeInserted"===a.type?(h=[m],i=[]):(h=[],i=[m]);var n=m.previousSibling,o=m.nextSibling,e=j("childList",d);e.addedNodes=h,e.removedNodes=i,e.previousSibling=n,e.nextSibling=o,f(d,function(a){return a.childList?e:void 0})}l()}},a.JsMutationObserver=g,!a.MutationObserver&&a.WebKitMutationObserver&&(a.MutationObserver=a.WebKitMutationObserver),a.MutationObserver||(a.MutationObserver=g)}(this),window.CustomElements=window.CustomElements||{flags:{}},function(a){function b(a,c,d){var e=a.firstElementChild;if(!e)for(e=a.firstChild;e&&e.nodeType!==Node.ELEMENT_NODE;)e=e.nextSibling;for(;e;)c(e,d)!==!0&&b(e,c,d),e=e.nextElementSibling;return null}function c(a,b){for(var c=a.shadowRoot;c;)d(c,b),c=c.olderShadowRoot}function d(a,d){b(a,function(a){return d(a)?!0:(c(a,d),void 0)}),c(a,d)}function e(a){return h(a)?(i(a),!0):(l(a),void 0)}function f(a){d(a,function(a){return e(a)?!0:void 0})}function g(a){return e(a)||f(a)}function h(b){if(!b.__upgraded__&&b.nodeType===Node.ELEMENT_NODE){var c=b.getAttribute("is")||b.localName,d=a.registry[c];if(d)return y.dom&&console.group("upgrade:",b.localName),a.upgrade(b),y.dom&&console.groupEnd(),!0}}function i(a){l(a),q(a)&&d(a,function(a){l(a)})}function j(a){if(B.push(a),!A){A=!0;var b=window.Platform&&window.Platform.endOfMicrotask||setTimeout;b(k)}}function k(){A=!1;for(var a,b=B,c=0,d=b.length;d>c&&(a=b[c]);c++)a();B=[]}function l(a){z?j(function(){m(a)}):m(a)}function m(a){(a.enteredViewCallback||a.__upgraded__&&y.dom)&&(y.dom&&console.group("inserted:",a.localName),q(a)&&(a.__inserted=(a.__inserted||0)+1,a.__inserted<1&&(a.__inserted=1),a.__inserted>1?y.dom&&console.warn("inserted:",a.localName,"insert/remove count:",a.__inserted):a.enteredViewCallback&&(y.dom&&console.log("inserted:",a.localName),a.enteredViewCallback())),y.dom&&console.groupEnd())}function n(a){o(a),d(a,function(a){o(a)})}function o(a){z?j(function(){p(a)}):p(a)}function p(a){(a.leftViewCallback||a.__upgraded__&&y.dom)&&(y.dom&&console.log("removed:",a.localName),q(a)||(a.__inserted=(a.__inserted||0)-1,a.__inserted>0&&(a.__inserted=0),a.__inserted<0?y.dom&&console.warn("removed:",a.localName,"insert/remove count:",a.__inserted):a.leftViewCallback&&a.leftViewCallback()))}function q(a){for(var b=a,c=window.ShadowDOMPolyfill&&window.ShadowDOMPolyfill.wrapIfNeeded(document)||document;b;){if(b==c)return!0;b=b.parentNode||b.host}}function r(a){if(a.shadowRoot&&!a.shadowRoot.__watched){y.dom&&console.log("watching shadow-root for: ",a.localName);for(var b=a.shadowRoot;b;)s(b),b=b.olderShadowRoot}}function s(a){a.__watched||(v(a),a.__watched=!0)}function t(a){if(y.dom){var b=a[0];if(b&&"childList"===b.type&&b.addedNodes&&b.addedNodes){for(var c=b.addedNodes[0];c&&c!==document&&!c.host;)c=c.parentNode;var d=c&&(c.URL||c._URL||c.host&&c.host.localName)||"";d=d.split("/?").shift().split("/").pop()}console.group("mutations (%d) [%s]",a.length,d||"")}a.forEach(function(a){"childList"===a.type&&(D(a.addedNodes,function(a){a.localName&&g(a)}),D(a.removedNodes,function(a){a.localName&&n(a)}))}),y.dom&&console.groupEnd()}function u(){t(C.takeRecords()),k()}function v(a){C.observe(a,{childList:!0,subtree:!0})}function w(a){v(a)}function x(a){y.dom&&console.group("upgradeDocument: ",(a.URL||a._URL||"").split("/").pop()),g(a),y.dom&&console.groupEnd()}var y=window.logFlags||{},z=!window.MutationObserver||window.MutationObserver===window.JsMutationObserver;a.hasPolyfillMutations=z;var A=!1,B=[],C=new MutationObserver(t),D=Array.prototype.forEach.call.bind(Array.prototype.forEach);a.watchShadow=r,a.upgradeAll=g,a.upgradeSubtree=f,a.observeDocument=w,a.upgradeDocument=x,a.takeRecords=u}(window.CustomElements),function(a){function b(b,f){var g=f||{};if(!b)throw new Error("document.register: first argument `name` must not be empty");if(b.indexOf("-")<0)throw new Error("document.register: first argument ('name') must contain a dash ('-'). Argument provided was '"+String(b)+"'.");if(m(b))throw new Error("DuplicateDefinitionError: a type with name '"+String(b)+"' is already registered");if(!g.prototype)throw new Error("Options missing required prototype property");return g.name=b.toLowerCase(),g.lifecycle=g.lifecycle||{},g.ancestry=c(g.extends),d(g),e(g),k(g.prototype),n(g.name,g),g.ctor=o(g),g.ctor.prototype=g.prototype,g.prototype.constructor=g.ctor,(a.ready||a.performedInitialDocumentUpgrade)&&a.upgradeAll(document),g.ctor}function c(a){var b=m(a);return b?c(b.extends).concat([b]):[]}function d(a){for(var b,c=a.extends,d=0;b=a.ancestry[d];d++)c=b.is&&b.tag;a.tag=c||a.name,c&&(a.is=a.name)}function e(a){if(!Object.__proto__){var b=HTMLElement.prototype;if(a.is){var c=document.createElement(a.tag);b=Object.getPrototypeOf(c)}for(var d,e=a.prototype;e&&e!==b;){var d=Object.getPrototypeOf(e);e.__proto__=d,e=d}}a.native=b}function f(a){return g(x(a.tag),a)}function g(b,c){return c.is&&b.setAttribute("is",c.is),b.removeAttribute("unresolved"),h(b,c),b.__upgraded__=!0,a.upgradeSubtree(b),j(b),b}function h(a,b){Object.__proto__?a.__proto__=b.prototype:(i(a,b.prototype,b.native),a.__proto__=b.prototype)}function i(a,b,c){for(var d={},e=b;e!==c&&e!==HTMLUnknownElement.prototype;){for(var f,g=Object.getOwnPropertyNames(e),h=0;f=g[h];h++)d[f]||(Object.defineProperty(a,f,Object.getOwnPropertyDescriptor(e,f)),d[f]=1);e=Object.getPrototypeOf(e)}}function j(a){a.createdCallback&&a.createdCallback()}function k(a){if(!a.setAttribute._polyfilled){var b=a.setAttribute;a.setAttribute=function(a,c){l.call(this,a,c,b)};var c=a.removeAttribute;a.removeAttribute=function(a){l.call(this,a,null,c)},a.setAttribute._polyfilled=!0}}function l(a,b,c){var d=this.getAttribute(a);c.apply(this,arguments);var e=this.getAttribute(a);this.attributeChangedCallback&&e!==d&&this.attributeChangedCallback(a,d,e)}function m(a){return a?w[a.toLowerCase()]:void 0}function n(a,b){if(w[a])throw new Error("a type with that name is already registered.");w[a]=b}function o(a){return function(){return f(a)}}function p(a,b){var c=m(b||a);if(c){if(a==c.tag&&b==c.is)return new c.ctor;if(!b&&!c.is)return new c.ctor}if(b){var d=p(a);return d.setAttribute("is",b),d}var d=x(a);return a.indexOf("-")>=0&&h(d,HTMLElement),d}function q(a){if(!a.__upgraded__&&a.nodeType===Node.ELEMENT_NODE){var b=a.getAttribute("is"),c=w[b||a.localName];if(c){if(b&&c.tag==a.localName)return g(a,c);if(!b&&!c.extends)return g(a,c)}}}function r(b){var c=y.call(this,b);return a.upgradeAll(c),c}a||(a=window.CustomElements={flags:{}});var s=a.flags,t=Boolean(document.register),u=!s.register&&t;if(u){var v=function(){};a.registry={},a.upgradeElement=v,a.watchShadow=v,a.upgrade=v,a.upgradeAll=v,a.upgradeSubtree=v,a.observeDocument=v,a.upgradeDocument=v,a.takeRecords=v}else{var w={},x=document.createElement.bind(document),y=Node.prototype.cloneNode;document.register=b,document.createElement=p,Node.prototype.cloneNode=r,a.registry=w,a.upgrade=q}a.hasNative=t,a.useNative=u}(window.CustomElements),function(){function a(a){return"link"===a.localName&&a.getAttribute("rel")===b}var b=window.HTMLImports?HTMLImports.IMPORT_LINK_TYPE:"none",c={selectors:["link[rel="+b+"]"],map:{link:"parseLink"},parse:function(a){if(!a.__parsed){a.__parsed=!0;var b=a.querySelectorAll(c.selectors);d(b,function(a){c[c.map[a.localName]](a)}),CustomElements.upgradeDocument(a),CustomElements.observeDocument(a)}},parseLink:function(b){a(b)&&this.parseImport(b)},parseImport:function(a){a.content&&c.parse(a.content)}},d=Array.prototype.forEach.call.bind(Array.prototype.forEach);CustomElements.parser=c}(),function(a){function b(){CustomElements.parser.parse(document),CustomElements.upgradeDocument(document),CustomElements.performedInitialDocumentUpgrade=!0;var a=window.Platform&&Platform.endOfMicrotask?Platform.endOfMicrotask:setTimeout;a(function(){CustomElements.ready=!0,CustomElements.readyTime=Date.now(),window.HTMLImports&&(CustomElements.elapsed=CustomElements.readyTime-HTMLImports.readyTime),document.body.dispatchEvent(new CustomEvent("WebComponentsReady",{bubbles:!0}))})}if("function"!=typeof window.CustomEvent&&(window.CustomEvent=function(a){var b=document.createEvent("HTMLEvents");return b.initEvent(a,!0,!0),b}),"complete"===document.readyState||a.flags.eager)b();else if("interactive"!==document.readyState||window.attachEvent||window.HTMLImports&&!window.HTMLImports.ready){var c=window.HTMLImports?"HTMLImportsLoaded":"loading"==document.readyState?"DOMContentLoaded":"load";window.addEventListener(c,b)}else b()}(window.CustomElements),function(){if(HTMLElement.prototype.createShadowRoot){var a=HTMLElement.prototype.createShadowRoot;HTMLElement.prototype.createShadowRoot=function(){var b=a.call(this);return b.host=this,CustomElements.watchShadow(this),b}}if(window.ShadowDOMPolyfill){var b=["upgradeAll","upgradeSubtree","observeDocument","upgradeDocument"],c={};b.forEach(function(a){c[a]=CustomElements[a]}),b.forEach(function(a){CustomElements[a]=function(b){return c[a](window.ShadowDOMPolyfill.wrapIfNeeded(b))}})}if(window.CustomElements&&!CustomElements.useNative){var d=Document.prototype.importNode;Document.prototype.importNode=function(a,b){var c=d.call(this,a,b);return CustomElements.upgradeAll(c),c}}}();
\ No newline at end of file
+"undefined"==typeof WeakMap&&!function(){var a=Object.defineProperty,b=Date.now()%1e9,c=function(){this.name="__st"+(1e9*Math.random()>>>0)+(b++ +"__")};c.prototype={set:function(b,c){var d=b[this.name];d&&d[0]===b?d[1]=c:a(b,this.name,{value:[b,c],writable:!0})},get:function(a){var b;return(b=a[this.name])&&b[0]===a?b[1]:void 0},"delete":function(a){this.set(a,void 0)}},window.WeakMap=c}(),function(a){function b(a){u.push(a),t||(t=!0,q(d))}function c(a){return window.ShadowDOMPolyfill&&window.ShadowDOMPolyfill.wrapIfNeeded(a)||a}function d(){t=!1;var a=u;u=[],a.sort(function(a,b){return a.uid_-b.uid_});var b=!1;a.forEach(function(a){var c=a.takeRecords();e(a),c.length&&(a.callback_(c,a),b=!0)}),b&&d()}function e(a){a.nodes_.forEach(function(b){var c=p.get(b);c&&c.forEach(function(b){b.observer===a&&b.removeTransientObservers()})})}function f(a,b){for(var c=a;c;c=c.parentNode){var d=p.get(c);if(d)for(var e=0;e<d.length;e++){var f=d[e],g=f.options;if(c===a||g.subtree){var h=b(g);h&&f.enqueue(h)}}}}function g(a){this.callback_=a,this.nodes_=[],this.records_=[],this.uid_=++v}function h(a,b){this.type=a,this.target=b,this.addedNodes=[],this.removedNodes=[],this.previousSibling=null,this.nextSibling=null,this.attributeName=null,this.attributeNamespace=null,this.oldValue=null}function i(a){var b=new h(a.type,a.target);return b.addedNodes=a.addedNodes.slice(),b.removedNodes=a.removedNodes.slice(),b.previousSibling=a.previousSibling,b.nextSibling=a.nextSibling,b.attributeName=a.attributeName,b.attributeNamespace=a.attributeNamespace,b.oldValue=a.oldValue,b}function j(a,b){return w=new h(a,b)}function k(a){return x?x:(x=i(w),x.oldValue=a,x)}function l(){w=x=void 0}function m(a){return a===x||a===w}function n(a,b){return a===b?a:x&&m(a)?x:null}function o(a,b,c){this.observer=a,this.target=b,this.options=c,this.transientObservedNodes=[]}var p=new WeakMap,q=window.msSetImmediate;if(!q){var r=[],s=String(Math.random());window.addEventListener("message",function(a){if(a.data===s){var b=r;r=[],b.forEach(function(a){a()})}}),q=function(a){r.push(a),window.postMessage(s,"*")}}var t=!1,u=[],v=0;g.prototype={observe:function(a,b){if(a=c(a),!b.childList&&!b.attributes&&!b.characterData||b.attributeOldValue&&!b.attributes||b.attributeFilter&&b.attributeFilter.length&&!b.attributes||b.characterDataOldValue&&!b.characterData)throw new SyntaxError;var d=p.get(a);d||p.set(a,d=[]);for(var e,f=0;f<d.length;f++)if(d[f].observer===this){e=d[f],e.removeListeners(),e.options=b;break}e||(e=new o(this,a,b),d.push(e),this.nodes_.push(a)),e.addListeners()},disconnect:function(){this.nodes_.forEach(function(a){for(var b=p.get(a),c=0;c<b.length;c++){var d=b[c];if(d.observer===this){d.removeListeners(),b.splice(c,1);break}}},this),this.records_=[]},takeRecords:function(){var a=this.records_;return this.records_=[],a}};var w,x;o.prototype={enqueue:function(a){var c=this.observer.records_,d=c.length;if(c.length>0){var e=c[d-1],f=n(e,a);if(f)return c[d-1]=f,void 0}else b(this.observer);c[d]=a},addListeners:function(){this.addListeners_(this.target)},addListeners_:function(a){var b=this.options;b.attributes&&a.addEventListener("DOMAttrModified",this,!0),b.characterData&&a.addEventListener("DOMCharacterDataModified",this,!0),b.childList&&a.addEventListener("DOMNodeInserted",this,!0),(b.childList||b.subtree)&&a.addEventListener("DOMNodeRemoved",this,!0)},removeListeners:function(){this.removeListeners_(this.target)},removeListeners_:function(a){var b=this.options;b.attributes&&a.removeEventListener("DOMAttrModified",this,!0),b.characterData&&a.removeEventListener("DOMCharacterDataModified",this,!0),b.childList&&a.removeEventListener("DOMNodeInserted",this,!0),(b.childList||b.subtree)&&a.removeEventListener("DOMNodeRemoved",this,!0)},addTransientObserver:function(a){if(a!==this.target){this.addListeners_(a),this.transientObservedNodes.push(a);var b=p.get(a);b||p.set(a,b=[]),b.push(this)}},removeTransientObservers:function(){var a=this.transientObservedNodes;this.transientObservedNodes=[],a.forEach(function(a){this.removeListeners_(a);for(var b=p.get(a),c=0;c<b.length;c++)if(b[c]===this){b.splice(c,1);break}},this)},handleEvent:function(a){switch(a.stopImmediatePropagation(),a.type){case"DOMAttrModified":var b=a.attrName,c=a.relatedNode.namespaceURI,d=a.target,e=new j("attributes",d);e.attributeName=b,e.attributeNamespace=c;var g=a.attrChange===MutationEvent.ADDITION?null:a.prevValue;f(d,function(a){return!a.attributes||a.attributeFilter&&a.attributeFilter.length&&-1===a.attributeFilter.indexOf(b)&&-1===a.attributeFilter.indexOf(c)?void 0:a.attributeOldValue?k(g):e});break;case"DOMCharacterDataModified":var d=a.target,e=j("characterData",d),g=a.prevValue;f(d,function(a){return a.characterData?a.characterDataOldValue?k(g):e:void 0});break;case"DOMNodeRemoved":this.addTransientObserver(a.target);case"DOMNodeInserted":var h,i,d=a.relatedNode,m=a.target;"DOMNodeInserted"===a.type?(h=[m],i=[]):(h=[],i=[m]);var n=m.previousSibling,o=m.nextSibling,e=j("childList",d);e.addedNodes=h,e.removedNodes=i,e.previousSibling=n,e.nextSibling=o,f(d,function(a){return a.childList?e:void 0})}l()}},a.JsMutationObserver=g,!a.MutationObserver&&a.WebKitMutationObserver&&(a.MutationObserver=a.WebKitMutationObserver),a.MutationObserver||(a.MutationObserver=g)}(this),window.CustomElements=window.CustomElements||{flags:{}},function(a){function b(a,c,d){var e=a.firstElementChild;if(!e)for(e=a.firstChild;e&&e.nodeType!==Node.ELEMENT_NODE;)e=e.nextSibling;for(;e;)c(e,d)!==!0&&b(e,c,d),e=e.nextElementSibling;return null}function c(a,b){for(var c=a.shadowRoot;c;)d(c,b),c=c.olderShadowRoot}function d(a,d){b(a,function(a){return d(a)?!0:(c(a,d),void 0)}),c(a,d)}function e(a){return h(a)?(i(a),!0):(l(a),void 0)}function f(a){d(a,function(a){return e(a)?!0:void 0})}function g(a){return e(a)||f(a)}function h(b){if(!b.__upgraded__&&b.nodeType===Node.ELEMENT_NODE){var c=b.getAttribute("is")||b.localName,d=a.registry[c];if(d)return y.dom&&console.group("upgrade:",b.localName),a.upgrade(b),y.dom&&console.groupEnd(),!0}}function i(a){l(a),q(a)&&d(a,function(a){l(a)})}function j(a){if(B.push(a),!A){A=!0;var b=window.Platform&&window.Platform.endOfMicrotask||setTimeout;b(k)}}function k(){A=!1;for(var a,b=B,c=0,d=b.length;d>c&&(a=b[c]);c++)a();B=[]}function l(a){z?j(function(){m(a)}):m(a)}function m(a){(a.enteredViewCallback||a.__upgraded__&&y.dom)&&(y.dom&&console.group("inserted:",a.localName),q(a)&&(a.__inserted=(a.__inserted||0)+1,a.__inserted<1&&(a.__inserted=1),a.__inserted>1?y.dom&&console.warn("inserted:",a.localName,"insert/remove count:",a.__inserted):a.enteredViewCallback&&(y.dom&&console.log("inserted:",a.localName),a.enteredViewCallback())),y.dom&&console.groupEnd())}function n(a){o(a),d(a,function(a){o(a)})}function o(a){z?j(function(){p(a)}):p(a)}function p(a){(a.leftViewCallback||a.__upgraded__&&y.dom)&&(y.dom&&console.log("removed:",a.localName),q(a)||(a.__inserted=(a.__inserted||0)-1,a.__inserted>0&&(a.__inserted=0),a.__inserted<0?y.dom&&console.warn("removed:",a.localName,"insert/remove count:",a.__inserted):a.leftViewCallback&&a.leftViewCallback()))}function q(a){for(var b=a,c=window.ShadowDOMPolyfill&&window.ShadowDOMPolyfill.wrapIfNeeded(document)||document;b;){if(b==c)return!0;b=b.parentNode||b.host}}function r(a){if(a.shadowRoot&&!a.shadowRoot.__watched){y.dom&&console.log("watching shadow-root for: ",a.localName);for(var b=a.shadowRoot;b;)s(b),b=b.olderShadowRoot}}function s(a){a.__watched||(v(a),a.__watched=!0)}function t(a){if(y.dom){var b=a[0];if(b&&"childList"===b.type&&b.addedNodes&&b.addedNodes){for(var c=b.addedNodes[0];c&&c!==document&&!c.host;)c=c.parentNode;var d=c&&(c.URL||c._URL||c.host&&c.host.localName)||"";d=d.split("/?").shift().split("/").pop()}console.group("mutations (%d) [%s]",a.length,d||"")}a.forEach(function(a){"childList"===a.type&&(D(a.addedNodes,function(a){a.localName&&g(a)}),D(a.removedNodes,function(a){a.localName&&n(a)}))}),y.dom&&console.groupEnd()}function u(){t(C.takeRecords()),k()}function v(a){C.observe(a,{childList:!0,subtree:!0})}function w(a){v(a)}function x(a){y.dom&&console.group("upgradeDocument: ",(a.URL||a._URL||"").split("/").pop()),g(a),y.dom&&console.groupEnd()}var y=window.logFlags||{},z=!window.MutationObserver||window.MutationObserver===window.JsMutationObserver;a.hasPolyfillMutations=z;var A=!1,B=[],C=new MutationObserver(t),D=Array.prototype.forEach.call.bind(Array.prototype.forEach);a.watchShadow=r,a.upgradeAll=g,a.upgradeSubtree=f,a.observeDocument=w,a.upgradeDocument=x,a.takeRecords=u}(window.CustomElements),function(a){function b(b,f){var g=f||{};if(!b)throw new Error("document.register: first argument `name` must not be empty");if(b.indexOf("-")<0)throw new Error("document.register: first argument ('name') must contain a dash ('-'). Argument provided was '"+String(b)+"'.");if(m(b))throw new Error("DuplicateDefinitionError: a type with name '"+String(b)+"' is already registered");if(!g.prototype)throw new Error("Options missing required prototype property");return g.name=b.toLowerCase(),g.lifecycle=g.lifecycle||{},g.ancestry=c(g.extends),d(g),e(g),k(g.prototype),n(g.name,g),g.ctor=o(g),g.ctor.prototype=g.prototype,g.prototype.constructor=g.ctor,(a.ready||a.performedInitialDocumentUpgrade)&&a.upgradeAll(document),g.ctor}function c(a){var b=m(a);return b?c(b.extends).concat([b]):[]}function d(a){for(var b,c=a.extends,d=0;b=a.ancestry[d];d++)c=b.is&&b.tag;a.tag=c||a.name,c&&(a.is=a.name)}function e(a){if(!Object.__proto__){var b=HTMLElement.prototype;if(a.is){var c=document.createElement(a.tag);b=Object.getPrototypeOf(c)}for(var d,e=a.prototype;e&&e!==b;){var d=Object.getPrototypeOf(e);e.__proto__=d,e=d}}a.native=b}function f(a){return g(x(a.tag),a)}function g(b,c){return c.is&&b.setAttribute("is",c.is),b.removeAttribute("unresolved"),h(b,c),b.__upgraded__=!0,a.upgradeSubtree(b),j(b),b}function h(a,b){Object.__proto__?a.__proto__=b.prototype:(i(a,b.prototype,b.native),a.constructor=b.prototype.constructor,a.__proto__=b.prototype)}function i(a,b,c){for(var d={},e=b;e!==c&&e!==HTMLUnknownElement.prototype;){for(var f,g=Object.getOwnPropertyNames(e),h=0;f=g[h];h++)d[f]||(Object.defineProperty(a,f,Object.getOwnPropertyDescriptor(e,f)),d[f]=1);e=Object.getPrototypeOf(e)}}function j(a){a.createdCallback&&a.createdCallback()}function k(a){if(!a.setAttribute._polyfilled){var b=a.setAttribute;a.setAttribute=function(a,c){l.call(this,a,c,b)};var c=a.removeAttribute;a.removeAttribute=function(a){l.call(this,a,null,c)},a.setAttribute._polyfilled=!0}}function l(a,b,c){var d=this.getAttribute(a);c.apply(this,arguments);var e=this.getAttribute(a);this.attributeChangedCallback&&e!==d&&this.attributeChangedCallback(a,d,e)}function m(a){return a?w[a.toLowerCase()]:void 0}function n(a,b){if(w[a])throw new Error("a type with that name is already registered.");w[a]=b}function o(a){return function(){return f(a)}}function p(a,b){var c=m(b||a);if(c){if(a==c.tag&&b==c.is)return new c.ctor;if(!b&&!c.is)return new c.ctor}if(b){var d=p(a);return d.setAttribute("is",b),d}var d=x(a);return a.indexOf("-")>=0&&h(d,HTMLElement),d}function q(a){if(!a.__upgraded__&&a.nodeType===Node.ELEMENT_NODE){var b=a.getAttribute("is"),c=w[b||a.localName];if(c){if(b&&c.tag==a.localName)return g(a,c);if(!b&&!c.extends)return g(a,c)}}}function r(b){var c=y.call(this,b);return a.upgradeAll(c),c}a||(a=window.CustomElements={flags:{}});var s=a.flags,t=Boolean(document.register),u=!s.register&&t;if(u){var v=function(){};a.registry={},a.upgradeElement=v,a.watchShadow=v,a.upgrade=v,a.upgradeAll=v,a.upgradeSubtree=v,a.observeDocument=v,a.upgradeDocument=v,a.takeRecords=v}else{var w={},x=document.createElement.bind(document),y=Node.prototype.cloneNode;document.register=b,document.createElement=p,Node.prototype.cloneNode=r,a.registry=w,a.upgrade=q}a.hasNative=t,a.useNative=u}(window.CustomElements),function(){function a(a){return"link"===a.localName&&a.getAttribute("rel")===b}var b=window.HTMLImports?HTMLImports.IMPORT_LINK_TYPE:"none",c={selectors:["link[rel="+b+"]"],map:{link:"parseLink"},parse:function(a){if(!a.__parsed){a.__parsed=!0;var b=a.querySelectorAll(c.selectors);d(b,function(a){c[c.map[a.localName]](a)}),CustomElements.upgradeDocument(a),CustomElements.observeDocument(a)}},parseLink:function(b){a(b)&&this.parseImport(b)},parseImport:function(a){a.content&&c.parse(a.content)}},d=Array.prototype.forEach.call.bind(Array.prototype.forEach);CustomElements.parser=c}(),function(a){function b(){CustomElements.parser.parse(document),CustomElements.upgradeDocument(document),CustomElements.performedInitialDocumentUpgrade=!0;var a=window.Platform&&Platform.endOfMicrotask?Platform.endOfMicrotask:setTimeout;a(function(){CustomElements.ready=!0,CustomElements.readyTime=Date.now(),window.HTMLImports&&(CustomElements.elapsed=CustomElements.readyTime-HTMLImports.readyTime),document.body.dispatchEvent(new CustomEvent("WebComponentsReady",{bubbles:!0}))})}if("function"!=typeof window.CustomEvent&&(window.CustomEvent=function(a){var b=document.createEvent("HTMLEvents");return b.initEvent(a,!0,!0),b}),"complete"===document.readyState||a.flags.eager)b();else if("interactive"!==document.readyState||window.attachEvent||window.HTMLImports&&!window.HTMLImports.ready){var c=window.HTMLImports?"HTMLImportsLoaded":"loading"==document.readyState?"DOMContentLoaded":"load";window.addEventListener(c,b)}else b()}(window.CustomElements),function(){if(HTMLElement.prototype.createShadowRoot){var a=HTMLElement.prototype.createShadowRoot;HTMLElement.prototype.createShadowRoot=function(){var b=a.call(this);return b.host=this,CustomElements.watchShadow(this),b}}if(window.ShadowDOMPolyfill){var b=["upgradeAll","upgradeSubtree","observeDocument","upgradeDocument"],c={};b.forEach(function(a){c[a]=CustomElements[a]}),b.forEach(function(a){CustomElements[a]=function(b){return c[a](window.ShadowDOMPolyfill.wrapIfNeeded(b))}})}if(window.CustomElements&&!CustomElements.useNative){var d=Document.prototype.importNode;Document.prototype.importNode=function(a,b){var c=d.call(this,a,b);return CustomElements.upgradeAll(c),c}}}();
\ No newline at end of file
diff --git a/pkg/custom_element/pubspec.yaml b/pkg/custom_element/pubspec.yaml
index 2ed1f29..39302d5 100644
--- a/pkg/custom_element/pubspec.yaml
+++ b/pkg/custom_element/pubspec.yaml
@@ -1,5 +1,5 @@
name: custom_element
-version: 0.9.1+1
+version: 0.9.1+2
author: "Polymer.dart Team <web-ui-dev@dartlang.org>"
homepage: http://www.dartlang.org/
description: >
diff --git a/pkg/intl/lib/intl.dart b/pkg/intl/lib/intl.dart
index d14cb12..7fff850 100644
--- a/pkg/intl/lib/intl.dart
+++ b/pkg/intl/lib/intl.dart
@@ -29,6 +29,7 @@
import 'src/date_format_internal.dart';
import "number_symbols.dart";
import "number_symbols_data.dart";
+import "src/temporary_debugging.dart";
part 'date_format.dart';
part 'src/date_format_field.dart';
diff --git a/pkg/intl/lib/src/date_format_helpers.dart b/pkg/intl/lib/src/date_format_helpers.dart
index 253a4e6..5508586 100644
--- a/pkg/intl/lib/src/date_format_helpers.dart
+++ b/pkg/intl/lib/src/date_format_helpers.dart
@@ -39,8 +39,22 @@
DateTime asDate() {
// TODO(alanknight): Validate the date, especially for things which
// can crash the VM, e.g. large month values.
+ if (debugLogDateCreation) {
+ debugDateCreationLog
+ ..write(" Creating Date from\n")
+ ..write(" UTC: $utc\n")
+ ..write(" year: $year\n")
+ ..write(" month: $month\n")
+ ..write(" day: $day\n")
+ ..write(" pm: $pm\n")
+ ..write(" hour: $hour\n")
+ ..write(" minute: $minute\n")
+ ..write(" second: $second\n")
+ ..write(" fractionalSecond: $fractionalSecond\n");
+ }
+ var result;
if (utc) {
- return new DateTime.utc(
+ result = new DateTime.utc(
year,
month,
day,
@@ -49,7 +63,7 @@
second,
fractionalSecond);
} else {
- return new DateTime(
+ result = new DateTime(
year,
month,
day,
@@ -58,6 +72,11 @@
second,
fractionalSecond);
}
+ if (debugLogDateCreation) {
+ debugDateCreationLog
+ ..write("Created $result");
+ }
+ return result;
}
}
diff --git a/pkg/intl/lib/src/temporary_debugging.dart b/pkg/intl/lib/src/temporary_debugging.dart
new file mode 100644
index 0000000..f96b56d
--- /dev/null
+++ b/pkg/intl/lib/src/temporary_debugging.dart
@@ -0,0 +1,10 @@
+// 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.
+
+/// This library contains temporary debugging code that should be
+/// removed once its purpose is finished. You would be crazy to use it.
+
+bool debugLogDateCreation = false;
+
+StringBuffer debugDateCreationLog = new StringBuffer();
\ No newline at end of file
diff --git a/pkg/intl/test/date_time_format_test_core.dart b/pkg/intl/test/date_time_format_test_core.dart
index 65461e2..989b264 100644
--- a/pkg/intl/test/date_time_format_test_core.dart
+++ b/pkg/intl/test/date_time_format_test_core.dart
@@ -14,6 +14,7 @@
import 'date_time_format_test_data.dart';
import 'package:intl/intl.dart';
import 'package:intl/src/date_format_internal.dart';
+import 'package:intl/src/temporary_debugging.dart';
var formatsToTest = const [
DateFormat.DAY,
@@ -164,6 +165,7 @@
if (!badSkeletons.any((x) => x == skeleton)) {
var format = new DateFormat(skeleton, localeName);
var actualResult = format.format(date);
+ debugLogDateCreation = true;
var parsed = format.parse(actualResult);
var thenPrintAgain = format.format(parsed);
// We've seen a case where this failed in a way that seemed like a time
@@ -172,11 +174,17 @@
// as possible if it occurs again.
if (thenPrintAgain != actualResult) {
print("Date mismatch!");
+ print("Date creation log: $debugDateCreationLog");
+ debugDateCreationLog.clear();
print(" Expected $actualResult");
print(" Got $thenPrintAgain");
print(" Original date = $date");
print(" Original ms = ${date.millisecondsSinceEpoch}");
print(" Parsed back to $parsed");
+ var parsed2 = format.parse(actualResult);
+ print(" Parsing again yields $parsed2");
+ print(" Logged as: $debugDateCreationLog");
+ debugDateCreationLog.clear();
print(" Parsed ms = ${parsed.millisecondsSinceEpoch}");
print(" Original tz = $originalTimeZoneOffset");
print(" Current tz name = $originalTimeZoneName");
@@ -185,6 +193,7 @@
print(" Start time = $originalTime");
print(" Current time ${new DateTime.now()}");
}
+ debugLogDateCreation = false;
expect(thenPrintAgain, equals(actualResult));
}
}
diff --git a/pkg/logging/lib/logging.dart b/pkg/logging/lib/logging.dart
index 8bff36b..ba342f7 100644
--- a/pkg/logging/lib/logging.dart
+++ b/pkg/logging/lib/logging.dart
@@ -51,7 +51,7 @@
library logging;
import 'dart:async';
-import 'package:collection_helpers/wrappers.dart';
+import 'package:collection/wrappers.dart';
/**
* Whether to allow fine-grain logging and configuration of loggers in a
diff --git a/pkg/logging/pubspec.yaml b/pkg/logging/pubspec.yaml
index 098558c..ef3a4cc 100644
--- a/pkg/logging/pubspec.yaml
+++ b/pkg/logging/pubspec.yaml
@@ -10,6 +10,6 @@
environment:
sdk: '>=1.0.0 <2.0.0'
dependencies:
- collection_helpers: '>=0.9.1 <0.10.0'
+ collection: '>=0.9.0 <0.10.0'
dev_dependencies:
unittest: '>=0.9.0 <0.10.0'
diff --git a/pkg/math/LICENSE b/pkg/math/LICENSE
new file mode 100644
index 0000000..ee99930
--- /dev/null
+++ b/pkg/math/LICENSE
@@ -0,0 +1,26 @@
+Copyright 2013, the Dart project authors. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google Inc. nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/runtime/bin/vmservice/service_request_router.dart b/pkg/math/lib/math.dart
similarity index 68%
copy from runtime/bin/vmservice/service_request_router.dart
copy to pkg/math/lib/math.dart
index c889c85..9958bec 100644
--- a/runtime/bin/vmservice/service_request_router.dart
+++ b/pkg/math/lib/math.dart
@@ -2,8 +2,6 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-part of vmservice;
+library dart.pkg.math;
-abstract class ServiceRequestRouter {
- Future route(ServiceRequest request);
-}
+// Placeholder library, reserved for future extension.
diff --git a/pkg/math/pubspec.yaml b/pkg/math/pubspec.yaml
new file mode 100644
index 0000000..4a20312
--- /dev/null
+++ b/pkg/math/pubspec.yaml
@@ -0,0 +1,9 @@
+name: math
+version: 0.9.0
+author: Dart Team <misc@dartlang.org>
+description: Utility functions and classes related to the 'dart:math' library.
+homepage: http://www.dartlang.org
+dev_dependencies:
+ unittest: ">=0.9.0 <0.10.0"
+environment:
+ sdk: ">=1.0.0 <2.0.0"
diff --git a/pkg/observe/pubspec.yaml b/pkg/observe/pubspec.yaml
index 0bb50ce..87c8727 100644
--- a/pkg/observe/pubspec.yaml
+++ b/pkg/observe/pubspec.yaml
@@ -1,5 +1,5 @@
name: observe
-version: 0.9.2
+version: 0.9.3
author: Polymer.dart Authors <web-ui-dev@dartlang.org>
description: >
Observable properties and objects for use in Model-Driven-Views (MDV).
@@ -10,7 +10,7 @@
homepage: https://www.dartlang.org/polymer-dart/
dependencies:
analyzer: ">=0.10.1 <0.11.0"
- barback: ">=0.9.0 <0.11.0"
+ barback: ">=0.9.0 <0.12.0"
logging: ">=0.9.0 <0.10.0"
path: ">=0.9.0 <2.0.0"
source_maps: ">=0.9.0 <0.10.0"
diff --git a/pkg/pkg.status b/pkg/pkg.status
index 9c4ab8b..36160f6 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -22,14 +22,16 @@
third_party/html5lib/test/dom_compat_test: Skip
third_party/html5lib/test/browser/browser_test: Skip
+http/test/http_test: Pass, RuntimeError # Issue 15652
+
[ $compiler == dart2js ]
-collection_helpers/test/equality_test/01: Fail # Issue 1533
-collection_helpers/test/equality_test/02: Fail # Issue 1533
-collection_helpers/test/equality_test/03: Fail # Issue 1533
-collection_helpers/test/equality_test/04: Fail # Issue 1533
-collection_helpers/test/equality_test/05: Fail # Issue 1533
-collection_helpers/test/equality_test/none: Pass, Fail # Issue 14348
-collection_helpers/test/typed_buffers_test/01: Fail # Not supporting Int64List, Uint64List.
+collection/test/equality_test/01: Fail # Issue 1533
+collection/test/equality_test/02: Fail # Issue 1533
+collection/test/equality_test/03: Fail # Issue 1533
+collection/test/equality_test/04: Fail # Issue 1533
+collection/test/equality_test/05: Fail # Issue 1533
+collection/test/equality_test/none: Pass, Fail # Issue 14348
+typed_data/test/typed_buffers_test/01: Fail # Not supporting Int64List, Uint64List.
[ $compiler == dart2js && $checked ]
crypto/test/base64_test: Slow, Pass
@@ -42,7 +44,7 @@
unittest/test/unittest_nested_groups_setup_teardown_test: RuntimeError # http://dartbug.com/10109
stack_trace/test/vm_test: RuntimeError, OK # VM-specific traces
stack_trace/test/chain_test: Fail # Issues 15171 and 15105
-sequence_zip/test/stream_test: RuntimeError, OK # Timers are not supported.
+async/test/stream_zip_test: RuntimeError, OK # Timers are not supported.
unittest/test/missing_tick_test: Fail # Timer interface not supported: dartbug.com/7728.
[ $runtime == vm || $runtime == d8 || $runtime == jsshell ]
@@ -81,7 +83,7 @@
# Bug in Spidermonkey's Uint8ClampedArray on x64 (non-Win FF is x64, Win is x86)
# See https://bugzilla.mozilla.org/show_bug.cgi?id=940972
# Likely to get patched only on some versions of Firefox.
-collection_helpers/test/typed_buffers_test: RuntimeError
+typed_data/test/typed_buffers_test: RuntimeError
[ $runtime == opera && $compiler == dart2js ]
intl/test/find_default_locale_browser_test: Fail
@@ -90,38 +92,21 @@
[ $runtime == ie9 ]
intl/test/date_time_format_http_request_test: Fail # Issue 8983
mime/test/mime_multipart_transformer_test: Skip # No typed_data on IE9.
-collection_helpers/test/typed_buffers_test: Fail, Crash # No typed_data on IE9.
+typed_data/test/typed_buffers_test: Fail, Crash # No typed_data on IE9.
polymer/test/instance_attrs_test: Pass, Fail # Issue 14167
[ $runtime == safari ]
fixnum/test/int_64_test: Pass, Fail # Bug in JSC.
# Unexplained errors only occuring on Safari.
-collection_helpers/test/typed_buffers_test: RuntimeError
+typed_data/test/typed_buffers_test: RuntimeError
[ $runtime == ie9 || $runtime == ie10 ]
-polymer/example/canonicalization/test/canonicalization_deploy_test: Pass, Timeout
-polymer/example/canonicalization/test/canonicalization_test: Timeout, OK # tests development only behavior
-polymer/test/attr_deserialize_test: Pass, Timeout # Issue 13260
-polymer/test/attr_mustache_test: Pass, Timeout # Issue 13260
-polymer/test/bind_test: Timeout # Issue 13260
polymer/test/bind_mdv_test: RuntimeError # Issue 14412, 13260
-polymer/test/custom_event_test: Timeout # Issue 13260
-polymer/test/entered_view_test: Timeout # Issue 13260
-polymer/test/event_handlers_test: Timeout # Issue 13260
-polymer/test/event_path_declarative_test: Timeout # Issue 13260
-polymer/test/event_path_test: Timeout # Issue 13260
-polymer/test/events_test: Timeout # Issue 13260
-polymer/test/nested_binding_test: Timeout # Issue 13260
-polymer/test/noscript_test: Timeout # Issue 13260
-polymer/test/property_change_test: Timeout # Issue 13260
-polymer/test/prop_attr_reflection_test: Timeout # Issue 13260
-polymer/test/prop_attr_bind_reflection_test: Timeout # Issue 13260
-polymer/test/publish_attributes_test: Timeout # Issue 13260
-polymer/test/publish_inherited_properties_test: Timeout # Issue 13260
-polymer/test/take_attributes_test: Timeout # Issue 13260
-polymer/test/template_distribute_dynamic_test: Pass, Timeout # Issue 13260
-polymer/test/unbind_test: Timeout # Issue 13260, 15259
+polymer/test/noscript_test: RuntimeError # Issue 13260
+
+[ ($runtime == ie9 || $runtime == ie10) && $checked ]
+polymer/test/take_attributes_test: RuntimeError # Issue 13260
# Skip browser-specific tests on VM
[ $runtime == vm ]
diff --git a/pkg/polymer/CHANGELOG.md b/pkg/polymer/CHANGELOG.md
index d2e3eba..3aad33a 100644
--- a/pkg/polymer/CHANGELOG.md
+++ b/pkg/polymer/CHANGELOG.md
@@ -5,6 +5,24 @@
impact polymer: custom_element, html_import, observe, shadow_dom,
and template_binding.
+#### Pub version 0.9.3+3
+ * Removes workaround now that mirrors implement a missing feature. Requires
+ SDK >= 1.1.0-dev.5.0.
+
+#### Pub version 0.9.3+2
+ * Fix rare canonicalization bug
+ [15694](https://code.google.com/p/dart/issues/detail?id=15694)
+
+#### Pub version 0.9.3+1
+ * Fix type error in runner.dart
+ [15649](https://code.google.com/p/dart/issues/detail?id=15649).
+
+#### Pub version 0.9.3
+ * pub-build now runs the linter automatically
+
+#### Pub version 0.9.2+4
+ * fix linter on SVG and MathML tags with XML namespaces
+
#### Pub version 0.9.2+3
* fix [15574](https://code.google.com/p/dart/issues/detail?id=15574),
event bindings in dart2js, by working around issue
diff --git a/pkg/polymer/lib/builder.dart b/pkg/polymer/lib/builder.dart
index 440c2723..26813e7 100644
--- a/pkg/polymer/lib/builder.dart
+++ b/pkg/polymer/lib/builder.dart
@@ -39,25 +39,27 @@
* import 'package:polymer/builder.dart';
*
* main() {
- * lint().then((_) => deploy());
+ * deploy(); // deploy also calls the linter internally.
* }
*
- * **Example 3**: Runs the linter, but conditionally does the deploy step. See
- * [parseOptions] for a description of options parsed automatically by this
- * helper library.
+ * **Example 3**: Always run the linter, but conditionally build a deployable
+ * version. See [parseOptions] for a description of options parsed automatically
+ * by this helper library.
*
* import 'dart:io';
* import 'package:polymer/builder.dart';
*
* main(args) {
* var options = parseOptions(args);
- * lint().then((_) {
- * if (options.forceDeploy) deploy();
- * });
+ * if (options.forceDeploy) {
+ * deploy();
+ * } else {
+ * lint();
+ * }
* }
*
- * **Example 4**: Same as above, but uses [build] (which internally calls [lint]
- * and optionally calls [deploy]).
+ * **Example 4**: Same as above, but uses [build] (which internally calls either
+ * [lint] or [deploy]).
*
* import 'dart:io';
* import 'package:polymer/builder.dart';
@@ -118,13 +120,11 @@
' options to build(). Running as if no options were passed.');
options = parseOptions([]);
}
- return lint(entryPoints: entryPoints, options: options,
- currentPackage: currentPackage, packageDirs: packageDirs).then((res) {
- if (options.forceDeploy) {
- return deploy(entryPoints: entryPoints, options: options,
- currentPackage: currentPackage, packageDirs: packageDirs);
- }
- });
+ return options.forceDeploy
+ ? deploy(entryPoints: entryPoints, options: options,
+ currentPackage: currentPackage, packageDirs: packageDirs)
+ : lint(entryPoints: entryPoints, options: options,
+ currentPackage: currentPackage, packageDirs: packageDirs);
}
@@ -152,36 +152,10 @@
}
if (currentPackage == null) currentPackage = readCurrentPackageFromPubspec();
var linterOptions = new TransformOptions(entryPoints: entryPoints);
- var formatter = options.machineFormat ? jsonFormatter : consoleFormatter;
- var linter = new Linter(linterOptions, formatter);
+ var linter = new Linter(linterOptions);
return runBarback(new BarbackOptions([[linter]], null,
- currentPackage: currentPackage, packageDirs: packageDirs)).then((assets) {
- var messages = {};
- var futures = [];
- for (var asset in assets) {
- var id = asset.id;
- if (id.package == currentPackage && id.path.endsWith('.messages')) {
- futures.add(asset.readAsString().then((content) {
- if (content.isEmpty) return;
- messages[id] = content;
- }));
- }
- }
-
- return Future.wait(futures).then((_) {
- // Print messages sorting by package and filepath.
- var orderedKeys = messages.keys.toList();
- orderedKeys.sort((a, b) {
- int packageCompare = a.package.compareTo(b.package);
- if (packageCompare != 0) return packageCompare;
- return a.path.compareTo(b.path);
- });
-
- for (var key in orderedKeys) {
- print(messages[key]);
- }
- });
- });
+ currentPackage: currentPackage, packageDirs: packageDirs,
+ machineFormat: options.machineFormat));
}
/**
@@ -220,7 +194,7 @@
var barbackOptions = new BarbackOptions(
new PolymerTransformerGroup(transformOptions).phases,
options.outDir, currentPackage: currentPackage,
- packageDirs: packageDirs);
+ packageDirs: packageDirs, machineFormat: options.machineFormat);
return runBarback(barbackOptions)
.then((_) => print('Done! All files written to "${options.outDir}"'));
}
diff --git a/pkg/polymer/lib/polymer.dart b/pkg/polymer/lib/polymer.dart
index baf1a6c..ff80921 100644
--- a/pkg/polymer/lib/polymer.dart
+++ b/pkg/polymer/lib/polymer.dart
@@ -59,7 +59,6 @@
import 'package:template_binding/template_binding.dart';
import 'deserialize.dart' as deserialize;
-import 'src/reflected_type.dart';
export 'package:observe/observe.dart';
export 'package:observe/html.dart';
diff --git a/pkg/polymer/lib/src/build/common.dart b/pkg/polymer/lib/src/build/common.dart
index 655ccbf..ebedf23 100644
--- a/pkg/polymer/lib/src/build/common.dart
+++ b/pkg/polymer/lib/src/build/common.dart
@@ -112,6 +112,8 @@
Future<bool> assetExists(AssetId id, Transform transform) =>
transform.getInput(id).then((_) => true).catchError((_) => false);
+
+ String toString() => 'polymer ($runtimeType)';
}
/** Create an [AssetId] for a [url] seen in the [source] asset. */
diff --git a/pkg/polymer/lib/src/build/linter.dart b/pkg/polymer/lib/src/build/linter.dart
index 75374f5..07e0153 100644
--- a/pkg/polymer/lib/src/build/linter.dart
+++ b/pkg/polymer/lib/src/build/linter.dart
@@ -21,8 +21,6 @@
import 'common.dart';
import 'utils.dart';
-typedef String MessageFormatter(String kind, String message, Span span);
-
/**
* A linter that checks for common Polymer errors and produces warnings to
* show on the editor or the command line. Leaves sources unchanged, but creates
@@ -34,24 +32,19 @@
/** Only run on .html files. */
final String allowedExtensions = '.html';
- final MessageFormatter _formatter;
-
- Linter(this.options, [this._formatter]);
+ Linter(this.options);
Future apply(Transform transform) {
- var wrapper = new _LoggerInterceptor(transform, _formatter);
var seen = new Set<AssetId>();
var primary = transform.primaryInput;
var id = primary.id;
- wrapper.addOutput(primary); // this phase is analysis only
+ transform.addOutput(primary); // this phase is analysis only
seen.add(id);
- return readPrimaryAsHtml(wrapper).then((document) {
- return _collectElements(document, id, wrapper, seen).then((elements) {
+ return readPrimaryAsHtml(transform).then((document) {
+ return _collectElements(document, id, transform, seen).then((elements) {
bool isEntrypoint = options.isHtmlEntryPoint(id);
- new _LinterVisitor(wrapper, elements, isEntrypoint).run(document);
- var messagesId = id.addExtension('.messages');
- wrapper.addOutput(new Asset.fromString(messagesId,
- wrapper._messages.join('\n')));
+ new _LinterVisitor(transform.logger, elements, isEntrypoint)
+ .run(document);
});
});
}
@@ -129,70 +122,6 @@
}
}
-/** A proxy of [Transform] that returns a different logger. */
-// TODO(sigmund): get rid of this when barback supports a better way to log
-// messages without printing them.
-class _LoggerInterceptor implements Transform, TransformLogger {
- final Transform _original;
- final List<String> _messages = [];
- final MessageFormatter _formatter;
-
- _LoggerInterceptor(this._original, MessageFormatter formatter)
- : _formatter = formatter == null ? consoleFormatter : formatter;
-
- TransformLogger get logger => this;
-
- noSuchMethod(Invocation m) => reflect(_original).delegate(m);
-
- // form TransformLogger:
- void warning(String message, {AssetId asset, Span span})
- => _write('warning', message, span);
-
- void error(String message, {AssetId asset, Span span})
- => _write('error', message, span);
-
- void _write(String kind, String message, Span span) {
- _messages.add(_formatter(kind, message, span));
- }
-}
-
-/**
- * Formatter that generates messages using a format that can be parsed
- * by tools, such as the Dart Editor, for reporting error messages.
- */
-String jsonFormatter(String kind, String message, Span span) {
- return JSON.encode((span == null)
- ? [{'method': 'warning', 'params': {'message': message}}]
- : [{'method': kind,
- 'params': {
- 'file': span.sourceUrl,
- 'message': message,
- 'line': span.start.line + 1,
- 'charStart': span.start.offset,
- 'charEnd': span.end.offset,
- }}]);
-}
-
-/**
- * Formatter that generates messages that are easy to read on the console (used
- * by default).
- */
-String consoleFormatter(String kind, String message, Span span) {
- var useColors = stdioType(stdout) == StdioType.TERMINAL;
- var levelColor = (kind == 'error') ? _RED_COLOR : _MAGENTA_COLOR;
- var output = new StringBuffer();
- if (useColors) output.write(levelColor);
- output..write(kind)..write(' ');
- if (useColors) output.write(_NO_COLOR);
- if (span == null) {
- output.write(message);
- } else {
- output.write(span.getLocationMessage(message,
- useColors: useColors,
- color: levelColor));
- }
- return output.toString();
-}
/**
* Information needed about other polymer-element tags in order to validate
@@ -395,7 +324,7 @@
void _validateNormalElement(Element node) {
// Event handlers only allowed inside polymer-elements
node.attributes.forEach((name, value) {
- if (name.startsWith('on')) {
+ if (name is String && name.startsWith('on')) {
_validateEventHandler(node, name, value);
}
});
@@ -517,10 +446,6 @@
return !_invalidTagNames.containsKey(name);
}
-const String _RED_COLOR = '\u001b[31m';
-const String _MAGENTA_COLOR = '\u001b[35m';
-const String _NO_COLOR = '\u001b[0m';
-
const String USE_INIT_DART =
'To run a polymer application, you need to call "initPolymer". You can '
'either include a generic script tag that does this for you:'
diff --git a/pkg/polymer/lib/src/build/runner.dart b/pkg/polymer/lib/src/build/runner.dart
index c7658de..87db2ae 100644
--- a/pkg/polymer/lib/src/build/runner.dart
+++ b/pkg/polymer/lib/src/build/runner.dart
@@ -12,7 +12,6 @@
import 'dart:convert';
import 'dart:io';
-import 'package:args/args.dart';
import 'package:barback/barback.dart';
import 'package:path/path.dart' as path;
import 'package:stack_trace/stack_trace.dart';
@@ -42,8 +41,15 @@
/** Directory where to generate code, if any. */
final String outDir;
+ /**
+ * Whether to print error messages using a json-format that tools, such as the
+ * Dart Editor, can process.
+ */
+ final bool machineFormat;
+
BarbackOptions(this.phases, this.outDir, {currentPackage, packageDirs,
- this.transformTests: false, this.transformPolymerDependencies: false})
+ this.transformTests: false, this.transformPolymerDependencies: false,
+ this.machineFormat: false})
: currentPackage = (currentPackage != null
? currentPackage : readCurrentPackageFromPubspec()),
packageDirs = (packageDirs != null
@@ -59,7 +65,7 @@
Future<AssetSet> runBarback(BarbackOptions options) {
var barback = new Barback(new _PolymerPackageProvider(options.packageDirs));
_initBarback(barback, options);
- _attachListeners(barback);
+ _attachListeners(barback, options);
if (options.outDir == null) return barback.getAllAssets();
return _emitAllFiles(barback, options);
}
@@ -80,7 +86,7 @@
* Extract a mapping between package names and the path in the file system where
* to find the sources of such package. This map will contain an entry for the
* current package and everything it depends on (extracted via `pub
- * list-pacakge-dirs`).
+ * list-package-dirs`).
*/
Map<String, String> _readPackageDirsFromPub(String currentPackage) {
var dartExec = Platform.executable;
@@ -171,7 +177,7 @@
}
/** Attach error listeners on [barback] so we can report errors. */
-void _attachListeners(Barback barback) {
+void _attachListeners(Barback barback, BarbackOptions options) {
// Listen for errors and results
barback.errors.listen((e) {
var trace = null;
@@ -189,6 +195,14 @@
exit(1);
}
});
+
+ barback.log.listen((entry) {
+ if (options.machineFormat) {
+ print(_jsonFormatter(entry));
+ } else {
+ print(_consoleFormatter(entry));
+ }
+ });
}
/**
@@ -311,3 +325,54 @@
_ensureDir(path.dirname(filepath));
return asset.read().pipe(new File(filepath).openWrite());
}
+
+String _kindFromEntry(LogEntry entry) {
+ var level = entry.level;
+ return level == LogLevel.ERROR ? 'error'
+ : (level == LogLevel.WARNING ? 'warning' : 'info');
+}
+
+/**
+ * Formatter that generates messages using a format that can be parsed
+ * by tools, such as the Dart Editor, for reporting error messages.
+ */
+String _jsonFormatter(LogEntry entry) {
+ var kind = _kindFromEntry(entry);
+ var span = entry.span;
+ return JSON.encode((span == null)
+ ? [{'method': kind, 'params': {'message': entry.message}}]
+ : [{'method': kind,
+ 'params': {
+ 'file': span.sourceUrl,
+ 'message': entry.message,
+ 'line': span.start.line + 1,
+ 'charStart': span.start.offset,
+ 'charEnd': span.end.offset,
+ }}]);
+}
+
+/**
+ * Formatter that generates messages that are easy to read on the console (used
+ * by default).
+ */
+String _consoleFormatter(LogEntry entry) {
+ var kind = _kindFromEntry(entry);
+ var useColors = stdioType(stdout) == StdioType.TERMINAL;
+ var levelColor = (kind == 'error') ? _RED_COLOR : _MAGENTA_COLOR;
+ var output = new StringBuffer();
+ if (useColors) output.write(levelColor);
+ output..write(kind)..write(' ');
+ if (useColors) output.write(_NO_COLOR);
+ if (entry.span == null) {
+ output.write(entry.message);
+ } else {
+ output.write(entry.span.getLocationMessage(entry.message,
+ useColors: useColors,
+ color: levelColor));
+ }
+ return output.toString();
+}
+
+const String _RED_COLOR = '\u001b[31m';
+const String _MAGENTA_COLOR = '\u001b[35m';
+const String _NO_COLOR = '\u001b[0m';
diff --git a/pkg/polymer/lib/src/loader.dart b/pkg/polymer/lib/src/loader.dart
index 5ee0915..48085e3 100644
--- a/pkg/polymer/lib/src/loader.dart
+++ b/pkg/polymer/lib/src/loader.dart
@@ -139,7 +139,8 @@
final _rootUri = currentMirrorSystem().isolate.rootLibrary.uri;
final String _packageRoot =
- '${path.dirname(Uri.parse(window.location.href).path)}/packages/';
+ path.url.join(path.url.dirname(Uri.parse(window.location.href).path),
+ 'packages') + '/';
final Logger _loaderLog = new Logger('polymer.loader');
@@ -180,7 +181,7 @@
for (var m in c.metadata) {
var meta = m.reflectee;
if (meta is CustomTag) {
- Polymer.register(meta.tagName, getReflectedTypeWorkaround(c));
+ Polymer.register(meta.tagName, c.reflectedType);
}
}
diff --git a/pkg/polymer/lib/src/reflected_type.dart b/pkg/polymer/lib/src/reflected_type.dart
deleted file mode 100644
index 6486abc..0000000
--- a/pkg/polymer/lib/src/reflected_type.dart
+++ /dev/null
@@ -1,31 +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 polymer.src.reflected_type;
-
-// These are used by _getReflectedTypeWorkaround, see http://dartbug.com/12607
-@MirrorsUsed(targets:
- const ['_js_helper.createRuntimeType', 'dart._js_mirrors.JsClassMirror'],
- override: 'polymer.src.reflected_type')
-import 'dart:mirrors';
-
-// Horrible hack to work around: http://dartbug.com/12607
-Type getReflectedTypeWorkaround(ClassMirror cls) {
- // On Dart VM, just return reflectedType.
- if (1.0 is! int) return cls.reflectedType;
-
- var mangledName = reflect(cls).getField(_mangledNameField).reflectee;
- Type type = _jsHelper.invoke(#createRuntimeType, [mangledName]).reflectee;
- return type;
-}
-
-final LibraryMirror _jsHelper =
- currentMirrorSystem().libraries[Uri.parse('dart:_js_helper')];
-
-final Symbol _mangledNameField = () {
- var jsClassMirrorMirror = reflect(reflectClass(ClassMirror)).type;
- for (var name in jsClassMirrorMirror.declarations.keys) {
- if (MirrorSystem.getName(name) == '_mangledName') return name;
- }
-}();
diff --git a/pkg/polymer/lib/transformer.dart b/pkg/polymer/lib/transformer.dart
index 735fac3..960d9df 100644
--- a/pkg/polymer/lib/transformer.dart
+++ b/pkg/polymer/lib/transformer.dart
@@ -12,6 +12,7 @@
import 'src/build/code_extractor.dart';
import 'src/build/common.dart';
import 'src/build/import_inliner.dart';
+import 'src/build/linter.dart';
import 'src/build/polyfill_injector.dart';
import 'src/build/script_compactor.dart';
@@ -69,6 +70,7 @@
List<List<Transformer>> _createDeployPhases(TransformOptions options) {
return [
+ [new Linter(options)],
[new InlineCodeExtractor(options)],
[new ObservableTransformer()],
[new ImportInliner(options)],
diff --git a/pkg/polymer/pubspec.yaml b/pkg/polymer/pubspec.yaml
index db8f3ce..7a348ce 100644
--- a/pkg/polymer/pubspec.yaml
+++ b/pkg/polymer/pubspec.yaml
@@ -1,5 +1,5 @@
name: polymer
-version: 0.9.2+3
+version: 0.9.3+3
author: Polymer.dart Authors <web-ui-dev@dartlang.org>
description: >
Polymer.dart is a new type of library for the web, built on top of Web
@@ -9,7 +9,7 @@
dependencies:
analyzer: ">=0.10.1 <0.11.0"
args: ">=0.9.0 <0.10.0"
- barback: ">=0.9.0 <0.11.0"
+ barback: ">=0.9.0 <0.12.0"
browser: ">=0.9.0 <0.10.0"
csslib: ">=0.9.0 <0.10.0"
custom_element: ">=0.9.1+1 <0.10.0"
@@ -29,4 +29,4 @@
dev_dependencies:
unittest: ">=0.9.0 <0.10.0"
environment:
- sdk: ">=1.0.0 <2.0.0"
+ sdk: ">=1.1.0-dev.5.0 <2.0.0"
diff --git a/pkg/polymer/test/build/common.dart b/pkg/polymer/test/build/common.dart
index 592f92f..d38fb3d 100644
--- a/pkg/polymer/test/build/common.dart
+++ b/pkg/polymer/test/build/common.dart
@@ -31,20 +31,27 @@
*/
final Map<String, String> files;
final Iterable<String> packages;
+ final List<String> messages;
+ int messagesSeen = 0;
+ bool errorSeen = false;
Barback barback;
var errorSubscription;
var resultSubscription;
+ var logSubscription;
Future<Asset> getAsset(AssetId id) =>
new Future.value(new Asset.fromString(id, files[idToString(id)]));
- TestHelper(List<List<Transformer>> transformers, Map<String, String> files)
+
+ TestHelper(List<List<Transformer>> transformers, Map<String, String> files,
+ this.messages)
: files = files,
packages = files.keys.map((s) => idFromString(s).package) {
barback = new Barback(this);
for (var p in packages) {
barback.updateTransformers(p, transformers);
}
+
errorSubscription = barback.errors.listen((e) {
var trace = null;
if (e is Error) trace = e.stackTrace;
@@ -53,14 +60,30 @@
}
fail('error running barback: $e');
});
+
resultSubscription = barback.results.listen((result) {
- expect(result.succeeded, isTrue, reason: "${result.errors}");
+ expect(result.succeeded, !errorSeen, reason: "${result.errors}");
+ });
+
+ logSubscription = barback.log.listen((entry) {
+ if (entry.level == LogLevel.ERROR) errorSeen = true;
+ // We only check messages when an expectation is provided.
+ if (messages == null) return;
+
+ var msg = '${entry.level.name.toLowerCase()}: ${entry.message}';
+ var span = entry.span;
+ var spanInfo = span == null ? '' :
+ ' (${span.sourceUrl} ${span.start.line} ${span.start.column})';
+ expect(messagesSeen, lessThan(messages.length),
+ reason: 'more messages than expected.\nMessage seen: $msg$spanInfo');
+ expect('$msg$spanInfo', messages[messagesSeen++]);
});
}
void tearDown() {
errorSubscription.cancel();
resultSubscription.cancel();
+ logSubscription.cancel();
}
/**
@@ -90,14 +113,20 @@
files.forEach((k, v) {
futures.add(check(k, v));
});
- return Future.wait(futures);
+ return Future.wait(futures).then((_) {
+ // We only check messages when an expectation is provided.
+ if (messages == null) return;
+ expect(messages.length, messagesSeen,
+ reason: 'less messages than expected');
+ });
}
}
testPhases(String testName, List<List<Transformer>> phases,
- Map<String, String> inputFiles, Map<String, String> expectedFiles) {
+ Map<String, String> inputFiles, Map<String, String> expectedFiles,
+ [List<String> expectedMessages]) {
test(testName, () {
- var helper = new TestHelper(phases, inputFiles)..run();
+ var helper = new TestHelper(phases, inputFiles, expectedMessages)..run();
return helper.checkAll(expectedFiles).then((_) => helper.tearDown());
});
}
diff --git a/pkg/polymer/test/build/linter_test.dart b/pkg/polymer/test/build/linter_test.dart
index 46964be..1641b64 100644
--- a/pkg/polymer/test/build/linter_test.dart
+++ b/pkg/polymer/test/build/linter_test.dart
@@ -16,9 +16,7 @@
useCompactVMConfiguration();
_testLinter('nothing to report', {
'a|lib/test.html': '<!DOCTYPE html><html></html>',
- }, {
- 'a|lib/test.html.messages': ''
- });
+ }, []);
group('must have Dart code to invoke initPolymer, dart.js, not boot.js', () {
_testLinter('nothing to report', {
@@ -27,15 +25,13 @@
'</script>'
'<script src="packages/browser/dart.js"></script>'
'</html>',
- }, {
- 'a|web/test.html.messages': '',
- });
+ }, []);
_testLinter('missing Dart code and dart.js', {
'a|web/test.html': '<!DOCTYPE html><html></html>',
- }, {
- 'a|web/test.html.messages': 'error: $USE_INIT_DART',
- });
+ }, [
+ 'error: $USE_INIT_DART',
+ ]);
_testLinter('using deprecated boot.js', {
'a|web/test.html': '<!DOCTYPE html><html>\n'
@@ -44,10 +40,9 @@
'</script>'
'<script src="packages/browser/dart.js"></script>'
'</html>',
- }, {
- 'a|web/test.html.messages': 'warning: $BOOT_JS_DEPRECATED '
- '(web/test.html 1 0)',
- });
+ }, [
+ 'warning: $BOOT_JS_DEPRECATED (web/test.html 1 0)',
+ ]);
});
group('single script tag per document', () {
_testLinter('two top-level tags', {
@@ -57,11 +52,10 @@
'<script type="application/dart" src="b.dart">'
'</script>'
'<script src="packages/browser/dart.js"></script>'
- }, {
- 'a|web/test.html.messages':
- 'warning: Only one "application/dart" script tag per document is'
- ' allowed. (web/test.html 1 0)',
- });
+ }, [
+ 'warning: Only one "application/dart" script tag per document is'
+ ' allowed. (web/test.html 1 0)',
+ ]);
_testLinter('two top-level tags, non entrypoint', {
'a|lib/test.html': '<!DOCTYPE html><html>'
@@ -70,11 +64,10 @@
'<script type="application/dart" src="b.dart">'
'</script>'
'<script src="packages/browser/dart.js"></script>'
- }, {
- 'a|lib/test.html.messages':
- 'warning: Only one "application/dart" script tag per document is'
- ' allowed. (lib/test.html 1 0)',
- });
+ }, [
+ 'warning: Only one "application/dart" script tag per document is'
+ ' allowed. (lib/test.html 1 0)',
+ ]);
_testLinter('tags inside elements', {
'a|web/test.html': '<!DOCTYPE html><html>'
@@ -85,28 +78,24 @@
'<script type="application/dart" src="b.dart">'
'</script>'
'<script src="packages/browser/dart.js"></script>'
- }, {
- 'a|web/test.html.messages':
- 'warning: Only one "application/dart" script tag per document is'
- ' allowed. (web/test.html 1 0)',
- });
+ }, [
+ 'warning: Only one "application/dart" script tag per document is'
+ ' allowed. (web/test.html 1 0)',
+ ]);
});
group('doctype warning', () {
_testLinter('in web', {
'a|web/test.html': '<html></html>',
- }, {
- 'a|web/test.html.messages':
- 'warning: Unexpected start tag (html). Expected DOCTYPE. '
- '(web/test.html 0 0)\n'
- 'error: $USE_INIT_DART',
- });
+ }, [
+ 'warning: Unexpected start tag (html). Expected DOCTYPE. '
+ '(web/test.html 0 0)',
+ 'error: $USE_INIT_DART',
+ ]);
_testLinter('in lib', {
'a|lib/test.html': '<html></html>',
- }, {
- 'a|lib/test.html.messages': '',
- });
+ }, []);
});
group('duplicate polymer-elements,', () {
@@ -115,13 +104,12 @@
<polymer-element name="x-a"></polymer-element>
<polymer-element name="x-a"></polymer-element>
</html>'''.replaceAll(' ', ''),
- }, {
- 'a|lib/test.html.messages':
- 'warning: duplicate definition for custom tag "x-a". '
- '(lib/test.html 1 0)\n'
- 'warning: duplicate definition for custom tag "x-a" '
- '(second definition). (lib/test.html 2 0)'
- });
+ }, [
+ 'warning: duplicate definition for custom tag "x-a". '
+ '(lib/test.html 1 0)',
+ 'warning: duplicate definition for custom tag "x-a" '
+ '(second definition). (lib/test.html 2 0)'
+ ]);
_testLinter('other file', {
'a|lib/b.html': '''<html>
@@ -131,24 +119,22 @@
<link rel="import" href="b.html">
<polymer-element name="x-a"></polymer-element>
</html>'''.replaceAll(' ', ''),
- }, {
- 'a|lib/test.html.messages':
- 'warning: duplicate definition for custom tag "x-a". '
- '(lib/b.html 1 0)\n'
- 'warning: duplicate definition for custom tag "x-a" '
- '(second definition). (lib/test.html 2 0)'
- });
+ }, [
+ 'warning: duplicate definition for custom tag "x-a". '
+ '(lib/b.html 1 0)',
+ 'warning: duplicate definition for custom tag "x-a" '
+ '(second definition). (lib/test.html 2 0)'
+ ]);
_testLinter('non existing file', {
'a|lib/test.html': '''<html>
<link rel="import" href="b.html">
<polymer-element name="x-a"></polymer-element>
</html>'''.replaceAll(' ', ''),
- }, {
- 'a|lib/test.html.messages':
- 'error: couldn\'t find imported asset "lib/b.html" in package '
- '"a". (lib/test.html 1 0)'
- });
+ }, [
+ 'error: couldn\'t find imported asset "lib/b.html" in package '
+ '"a". (lib/test.html 1 0)'
+ ]);
_testLinter('other package', {
'b|lib/b.html': '''<html>
@@ -158,13 +144,12 @@
<link rel="import" href="../../packages/b/b.html">
<polymer-element name="x-a"></polymer-element>
</html>'''.replaceAll(' ', ''),
- }, {
- 'a|lib/test.html.messages':
- 'warning: duplicate definition for custom tag "x-a". '
- '(package:b/b.html 1 0)\n'
- 'warning: duplicate definition for custom tag "x-a" '
- '(second definition). (lib/test.html 2 0)'
- });
+ }, [
+ 'warning: duplicate definition for custom tag "x-a". '
+ '(package:b/b.html 1 0)',
+ 'warning: duplicate definition for custom tag "x-a" '
+ '(second definition). (lib/test.html 2 0)'
+ ]);
});
_testLinter('bad link-rel tag (href missing)', {
@@ -174,22 +159,20 @@
<link rel="foo">
<link rel="import" href="">
</html>'''.replaceAll(' ', ''),
- }, {
- 'a|lib/test.html.messages':
- 'warning: link rel="import" missing href. (lib/test.html 1 0)\n'
- 'warning: link rel="stylesheet" missing href. (lib/test.html 2 0)\n'
- 'warning: link rel="import" missing href. (lib/test.html 4 0)'
- });
+ }, [
+ 'warning: link rel="import" missing href. (lib/test.html 1 0)',
+ 'warning: link rel="stylesheet" missing href. (lib/test.html 2 0)',
+ 'warning: link rel="import" missing href. (lib/test.html 4 0)'
+ ]);
_testLinter('<element> is not supported', {
'a|lib/test.html': '''<html>
<element name="x-a"></element>
</html>'''.replaceAll(' ', ''),
- }, {
- 'a|lib/test.html.messages':
- 'warning: <element> elements are not supported, use <polymer-element>'
- ' instead (lib/test.html 1 0)'
- });
+ }, [
+ 'warning: <element> elements are not supported, use <polymer-element>'
+ ' instead (lib/test.html 1 0)'
+ ]);
_testLinter('do not nest <polymer-element>', {
'a|lib/test.html': '''<html>
@@ -199,51 +182,44 @@
</div></template>
</polymer-element>
</html>'''.replaceAll(' ', ''),
- }, {
- 'a|lib/test.html.messages':
- 'error: Nested polymer element definitions are not allowed.'
- ' (lib/test.html 3 4)'
- });
+ }, [
+ 'error: Nested polymer element definitions are not allowed.'
+ ' (lib/test.html 3 4)'
+ ]);
_testLinter('need a name for <polymer-element>', {
'a|lib/test.html': '''<html>
<polymer-element></polymer-element>
</html>'''.replaceAll(' ', ''),
- }, {
- 'a|lib/test.html.messages':
- 'error: Missing tag name of the custom element. Please include an '
- 'attribute like \'name="your-tag-name"\'. (lib/test.html 1 0)'
- });
+ }, [
+ 'error: Missing tag name of the custom element. Please include an '
+ 'attribute like \'name="your-tag-name"\'. (lib/test.html 1 0)'
+ ]);
_testLinter('name for <polymer-element> should have dashes', {
'a|lib/test.html': '''<html>
<polymer-element name="a"></polymer-element>
</html>'''.replaceAll(' ', ''),
- }, {
- 'a|lib/test.html.messages':
- 'error: Invalid name "a". Custom element names must have at least one'
- ' dash and can\'t be any of the following names: annotation-xml, '
- 'color-profile, font-face, font-face-src, font-face-uri, '
- 'font-face-format, font-face-name, missing-glyph. (lib/test.html 1 0)'
- });
+ }, [
+ 'error: Invalid name "a". Custom element names must have at least one'
+ ' dash and can\'t be any of the following names: annotation-xml, '
+ 'color-profile, font-face, font-face-src, font-face-uri, '
+ 'font-face-format, font-face-name, missing-glyph. (lib/test.html 1 0)'
+ ]);
_testLinter('extend is a valid element or existing tag', {
'a|lib/test.html': '''<html>
<polymer-element name="x-a" extends="li"></polymer-element>
</html>'''.replaceAll(' ', ''),
- }, {
- 'a|lib/test.html.messages': ''
- });
+ }, []);
_testLinter('extend is a valid element or existing tag', {
'a|lib/test.html': '''<html>
<polymer-element name="x-a" extends="x-b"></polymer-element>
</html>'''.replaceAll(' ', ''),
- }, {
- 'a|lib/test.html.messages': ''
- 'warning: custom element with name "x-b" not found. '
- '(lib/test.html 1 0)'
- });
+ }, [
+ 'warning: custom element with name "x-b" not found. (lib/test.html 1 0)'
+ ]);
group('script type matches code', () {
@@ -251,11 +227,10 @@
'a|lib/test.html': '''<html>
<script src="foo.dart"></script>
</html>'''.replaceAll(' ', ''),
- }, {
- 'a|lib/test.html.messages':
- 'warning: Wrong script type, expected type="application/dart".'
- ' (lib/test.html 1 0)'
- });
+ }, [
+ 'warning: Wrong script type, expected type="application/dart".'
+ ' (lib/test.html 1 0)'
+ ]);
_testLinter('in polymer-element, .dart url', {
'a|lib/test.html': '''<html>
@@ -263,11 +238,10 @@
<script src="foo.dart"></script>
</polymer-element>
</html>'''.replaceAll(' ', ''),
- }, {
- 'a|lib/test.html.messages':
- 'warning: Wrong script type, expected type="application/dart".'
- ' (lib/test.html 2 0)'
- });
+ }, [
+ 'warning: Wrong script type, expected type="application/dart".'
+ ' (lib/test.html 2 0)'
+ ]);
_testLinter('in polymer-element, .js url', {
'a|lib/test.html': '''<html>
@@ -275,9 +249,7 @@
<script src="foo.js"></script>
</polymer-element>
</html>'''.replaceAll(' ', ''),
- }, {
- 'a|lib/test.html.messages': ''
- });
+ }, []);
_testLinter('in polymer-element, inlined', {
'a|lib/test.html': '''<html>
@@ -285,126 +257,113 @@
<script>foo...</script>
</polymer-element>
</html>'''.replaceAll(' ', ''),
- }, {
- 'a|lib/test.html.messages':
- 'warning: script tag in polymer element with no type will '
- 'be treated as JavaScript. Did you forget type="application/dart"?'
- ' (lib/test.html 2 0)'
- });
+ }, [
+ 'warning: script tag in polymer element with no type will '
+ 'be treated as JavaScript. Did you forget type="application/dart"?'
+ ' (lib/test.html 2 0)'
+ ]);
_testLinter('top-level, dart type & .dart url', {
'a|lib/test.html': '''<html>
<script type="application/dart" src="foo.dart"></script>
</html>'''.replaceAll(' ', ''),
- }, {
- 'a|lib/test.html.messages': ''
- });
+ }, []);
_testLinter('top-level, dart type & .js url', {
'a|lib/test.html': '''<html>
<script type="application/dart" src="foo.js"></script>
</html>'''.replaceAll(' ', ''),
- }, {
- 'a|lib/test.html.messages':
- 'warning: "application/dart" scripts should use the .dart file '
- 'extension. (lib/test.html 1 0)'
- });
+ }, [
+ 'warning: "application/dart" scripts should use the .dart file '
+ 'extension. (lib/test.html 1 0)'
+ ]);
});
_testLinter('script tags should have only src url or inline code', {
'a|lib/test.html': '''<html>
<script type="application/dart" src="foo.dart">more</script>
</html>'''.replaceAll(' ', ''),
- }, {
- 'a|lib/test.html.messages':
- 'warning: script tag has "src" attribute and also has script text. '
- '(lib/test.html 1 0)'
- });
+ }, [
+ 'warning: script tag has "src" attribute and also has script text. '
+ '(lib/test.html 1 0)'
+ ]);
group('event handlers', () {
_testLinter('onfoo is not polymer', {
'a|lib/test.html': '''<html><body>
<div onfoo="something"></div>
'''.replaceAll(' ', ''),
- }, {
- 'a|lib/test.html.messages':
- 'warning: Event handler "onfoo" will be interpreted as an inline '
- 'JavaScript event handler. Use the form '
- 'on-event-name="handlerName" if you want a Dart handler '
- 'that will automatically update the UI based on model changes. '
- '(lib/test.html 1 5)'
- });
+ }, [
+ 'warning: Event handler "onfoo" will be interpreted as an inline '
+ 'JavaScript event handler. Use the form '
+ 'on-event-name="handlerName" if you want a Dart handler '
+ 'that will automatically update the UI based on model changes. '
+ '(lib/test.html 1 5)'
+ ]);
_testLinter('on-foo is only supported in polymer elements', {
'a|lib/test.html': '''<html><body>
<div on-foo="something"></div>
'''.replaceAll(' ', ''),
- }, {
- 'a|lib/test.html.messages':
- 'warning: Inline event handlers are only supported inside '
- 'declarations of <polymer-element>. '
- '(lib/test.html 1 5)'
- });
+ }, [
+ 'warning: Inline event handlers are only supported inside '
+ 'declarations of <polymer-element>. '
+ '(lib/test.html 1 5)'
+ ]);
_testLinter('on-foo is not an expression', {
'a|lib/test.html': '''<html><body>
<polymer-element name="x-a"><div on-foo="bar()"></div>
</polymer-element>
'''.replaceAll(' ', ''),
- }, {
- 'a|lib/test.html.messages':
- 'warning: Invalid event handler body "bar()". Declare a method '
- 'in your custom element "void handlerName(event, detail, target)" '
- 'and use the form on-foo="handlerName". '
- '(lib/test.html 1 33)'
- });
+ }, [
+ 'warning: Invalid event handler body "bar()". Declare a method '
+ 'in your custom element "void handlerName(event, detail, target)" '
+ 'and use the form on-foo="handlerName". '
+ '(lib/test.html 1 33)'
+ ]);
_testLinter('on-foo-bar is supported as a custom event name', {
'a|lib/test.html': '''<html><body>
<polymer-element name="x-a"><div on-foo-bar="quux"></div>
</polymer-element>
'''.replaceAll(' ', ''),
- }, {});
+ }, []);
});
group('using custom tags', () {
_testLinter('tag exists (x-tag)', {
'a|lib/test.html': '<x-foo></x-foo>',
- }, {
- 'a|lib/test.html.messages':
- 'warning: definition for Polymer element with tag name "x-foo" not '
- 'found. (lib/test.html 0 0)'
- });
+ }, [
+ 'warning: definition for Polymer element with tag name "x-foo" not '
+ 'found. (lib/test.html 0 0)'
+ ]);
_testLinter('tag exists (type extension)', {
'a|lib/test.html': '<div is="x-foo"></div>',
- }, {
- 'a|lib/test.html.messages':
- 'warning: definition for Polymer element with tag name "x-foo" not '
- 'found. (lib/test.html 0 0)'
- });
+ }, [
+ 'warning: definition for Polymer element with tag name "x-foo" not '
+ 'found. (lib/test.html 0 0)'
+ ]);
_testLinter('used correctly (no base tag)', {
'a|lib/test.html': '''
<polymer-element name="x-a"></polymer-element>
<x-a></x-a>
'''.replaceAll(' ', ''),
- }, {
- 'a|lib/test.html.messages': ''
- });
+ }, []);
_testLinter('used incorrectly (no base tag)', {
'a|lib/test.html': '''
<polymer-element name="x-a"></polymer-element>
<div is="x-a"></div>
'''.replaceAll(' ', ''),
- }, {
- 'a|lib/test.html.messages':
- 'warning: custom element "x-a" doesn\'t declare any type '
- 'extensions. To fix this, either rewrite this tag as '
- '<x-a> or add \'extends="div"\' to '
- 'the custom element declaration. (lib/test.html 1 0)'
- });
+ }, [
+ 'warning: custom element "x-a" doesn\'t declare any type '
+ 'extensions. To fix this, either rewrite this tag as '
+ '<x-a> or add \'extends="div"\' to '
+ 'the custom element declaration. (lib/test.html 1 0)'
+ ]);
_testLinter('used incorrectly, imported def (no base tag)', {
'a|lib/b.html': '<polymer-element name="x-a"></polymer-element>',
@@ -412,13 +371,12 @@
<link rel="import" href="b.html">
<div is="x-a"></div>
'''.replaceAll(' ', ''),
- }, {
- 'a|lib/test.html.messages':
- 'warning: custom element "x-a" doesn\'t declare any type '
- 'extensions. To fix this, either rewrite this tag as '
- '<x-a> or add \'extends="div"\' to '
- 'the custom element declaration. (lib/test.html 1 0)'
- });
+ }, [
+ 'warning: custom element "x-a" doesn\'t declare any type '
+ 'extensions. To fix this, either rewrite this tag as '
+ '<x-a> or add \'extends="div"\' to '
+ 'the custom element declaration. (lib/test.html 1 0)'
+ ]);
_testLinter('used correctly (base tag)', {
'a|lib/b.html': '''
@@ -429,9 +387,7 @@
<link rel="import" href="b.html">
<div is="x-a"></div>
'''.replaceAll(' ', ''),
- }, {
- 'a|lib/test.html.messages': ''
- });
+ }, []);
_testLinter('used incorrectly (missing base tag)', {
'a|lib/b.html': '''
@@ -442,13 +398,12 @@
<link rel="import" href="b.html">
<x-a></x-a>
'''.replaceAll(' ', ''),
- }, {
- 'a|lib/test.html.messages': ''
- 'warning: custom element "x-a" extends from "div", but this tag '
- 'will not include the default properties of "div". To fix this, '
- 'either write this tag as <div is="x-a"> or remove the "extends" '
- 'attribute from the custom element declaration. (lib/test.html 1 0)'
- });
+ }, [
+ 'warning: custom element "x-a" extends from "div", but this tag '
+ 'will not include the default properties of "div". To fix this, '
+ 'either write this tag as <div is="x-a"> or remove the "extends" '
+ 'attribute from the custom element declaration. (lib/test.html 1 0)'
+ ]);
_testLinter('used incorrectly (wrong base tag)', {
'a|lib/b.html': '''
@@ -459,11 +414,10 @@
<link rel="import" href="b.html">
<span is="x-a"></span>
'''.replaceAll(' ', ''),
- }, {
- 'a|lib/test.html.messages': ''
- 'warning: custom element "x-a" extends from "div". Did you mean '
- 'to write <div is="x-a">? (lib/test.html 1 0)'
- });
+ }, [
+ 'warning: custom element "x-a" extends from "div". Did you mean '
+ 'to write <div is="x-a">? (lib/test.html 1 0)'
+ ]);
_testLinter('used incorrectly (wrong base tag, transitive)', {
'a|lib/c.html': '''
@@ -481,11 +435,10 @@
<link rel="import" href="b.html">
<span is="x-a"></span>
'''.replaceAll(' ', ''),
- }, {
- 'a|lib/test.html.messages': ''
- 'warning: custom element "x-a" extends from "li". Did you mean '
- 'to write <li is="x-a">? (lib/test.html 1 0)'
- });
+ }, [
+ 'warning: custom element "x-a" extends from "li". Did you mean '
+ 'to write <li is="x-a">? (lib/test.html 1 0)'
+ ]);
});
group('custom attributes', () {
@@ -494,32 +447,24 @@
<polymer-element name="x-a" attributes="foo-bar">
</polymer-element>
'''.replaceAll(' ', ''),
- }, {
- 'a|lib/test.html.messages':
- 'warning: PolymerElement no longer recognizes attribute names with '
- 'dashes such as "foo-bar". Use "fooBar" or "foobar" instead (both '
- 'forms are equivalent in HTML). (lib/test.html 1 28)'
- });
+ }, [
+ 'warning: PolymerElement no longer recognizes attribute names with '
+ 'dashes such as "foo-bar". Use "fooBar" or "foobar" instead (both '
+ 'forms are equivalent in HTML). (lib/test.html 1 28)'
+ ]);
});
+
+ _testLinter("namespaced attributes don't cause an internal error", {
+ 'a|lib/test.html': '''<html><body>
+ <svg xmlns="http://www.w3.org/2000/svg" width="520" height="350">
+ </svg>
+ '''.replaceAll(' ', ''),
+ }, []);
}
-_testLinter(String name, Map inputFiles, Map outputMessages) {
- var linter = new Linter(new TransformOptions(), _testFormatter);
+_testLinter(String name, Map inputFiles, List outputMessages) {
+ var linter = new Linter(new TransformOptions());
var outputFiles = {};
inputFiles.forEach((k, v) => outputFiles[k] = v);
- outputMessages.forEach((k, v) => outputFiles[k] = v);
- var keys = inputFiles.keys.toSet();
- keys.retainAll(outputMessages.keys);
- expect(keys, isEmpty);
- testPhases(name, [[linter]], inputFiles, outputFiles);
-}
-
-
-_testFormatter(String kind, String message, Span span) {
- var formattedMessage = '$kind: $message';
- if (span != null) {
- formattedMessage = '$formattedMessage '
- '(${span.sourceUrl} ${span.start.line} ${span.start.column})';
- }
- return formattedMessage;
+ testPhases(name, [[linter]], inputFiles, outputFiles, outputMessages);
}
diff --git a/pkg/polymer/test/build/static_clean_test.dart b/pkg/polymer/test/build/static_clean_test.dart
new file mode 100644
index 0000000..410fc51
--- /dev/null
+++ b/pkg/polymer/test/build/static_clean_test.dart
@@ -0,0 +1,11 @@
+// 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 polymer.test.build.static_clean_test;
+
+import 'package:polymer/builder.dart';
+
+void main() {
+ // Check that builder.dart is statically clean. Nothing to do.
+}
diff --git a/pkg/sequence_zip/LICENSE b/pkg/sequence_zip/LICENSE
new file mode 100644
index 0000000..ee99930
--- /dev/null
+++ b/pkg/sequence_zip/LICENSE
@@ -0,0 +1,26 @@
+Copyright 2013, the Dart project authors. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google Inc. nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/pkg/sequence_zip/lib/iterable_zip.dart b/pkg/sequence_zip/lib/iterable_zip.dart
index f21da73..dd4e5cb 100644
--- a/pkg/sequence_zip/lib/iterable_zip.dart
+++ b/pkg/sequence_zip/lib/iterable_zip.dart
@@ -2,61 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-/**
- * Help for combining multiple Iterables into a single Iterable.
- *
- * This API is also available as part of the
- * [sequence_zip](#sequence_zip) library.
- */
+/** Please use `package:collection/iterable_zip.dart` instead. */
+@deprecated
library iterable_zip;
-import "dart:collection";
-
-/**
- * Iterable that iterates over lists of values from other iterables.
- *
- * When [iterator] is read, an [Iterator] is created for each [Iterable] in
- * the [Iterable] passed to the constructor.
- *
- * As long as all these iterators have a next value, those next values are
- * combined into a single list, which becomes the next value of this
- * [Iterable]'s [Iterator]. As soon as any of the iterators run out,
- * the zipped iterator also stops.
- */
-class IterableZip extends IterableBase<List> {
- final Iterable<Iterable> _iterables;
- IterableZip(Iterable<Iterable> iterables)
- : this._iterables = iterables;
-
- /**
- * Returns an iterator that combines values of the iterables' iterators
- * as long as they all have values.
- */
- Iterator<List> get iterator {
- List iterators = _iterables.map((x) => x.iterator).toList(growable: false);
- // TODO(lrn): Return an empty iterator directly if iterators is empty?
- return new _IteratorZip(iterators);
- }
-}
-
-class _IteratorZip implements Iterator<List> {
- final List<Iterator> _iterators;
- List _current;
- _IteratorZip(List iterators) : _iterators = iterators;
- bool moveNext() {
- if (_iterators.isEmpty) return false;
- for (int i = 0; i < _iterators.length; i++) {
- if (!_iterators[i].moveNext()) {
- _current = null;
- return false;
- }
- }
- _current = new List(_iterators.length);
- for (int i = 0; i < _iterators.length; i++) {
- _current[i] = _iterators[i].current;
- }
- return true;
- }
-
- List get current => _current;
-}
+export "package:collection/iterable_zip.dart";
diff --git a/pkg/sequence_zip/lib/sequence_zip.dart b/pkg/sequence_zip/lib/sequence_zip.dart
index 2f0d7e6..8824e46 100644
--- a/pkg/sequence_zip/lib/sequence_zip.dart
+++ b/pkg/sequence_zip/lib/sequence_zip.dart
@@ -3,14 +3,10 @@
// BSD-style license that can be found in the LICENSE file.
/**
- * Utilities for combining multiple streams or Iterables
- * into a single stream or Iterable, respectively.
- *
- * This library defines no new APIs.
- * It's a convenience library for using the APIs in the
- * [iterable_zip](#iterable_zip) and
- * [stream_zip](#stream_zip) libraries.
+ * Please use the libraries `package:collection/iterable_zip.dart` for iterable zipping
+ * or `package:async/stream_zip.dart` for stream zipping.
*/
+@deprecated
library sequence_zip;
export "iterable_zip.dart";
diff --git a/pkg/sequence_zip/lib/stream_zip.dart b/pkg/sequence_zip/lib/stream_zip.dart
index b09cfdb..78b7a3a 100644
--- a/pkg/sequence_zip/lib/stream_zip.dart
+++ b/pkg/sequence_zip/lib/stream_zip.dart
@@ -2,121 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-/**
- * Help for combining multiple streams into a single stream.
- *
- * This API is also available as part of the
- * [sequence_zip](#sequence_zip) library.
- */
+/** Please use `package:async/stream_zip.dart` instead. */
+@deprecated
library stream_zip;
-import "dart:async";
-
-/**
- * A stream that combines the values of other streams.
- */
-class StreamZip extends Stream<List> {
- final Iterable<Stream> _streams;
- StreamZip(Iterable<Stream> streams) : _streams = streams;
-
- StreamSubscription<List> listen(void onData(List data), {
- Function onError,
- void onDone(),
- bool cancelOnError}) {
- cancelOnError = identical(true, cancelOnError);
- List<StreamSubscription> subscriptions = <StreamSubscription>[];
- StreamController controller;
- List current;
- int dataCount = 0;
-
- /// Called for each data from a subscription in [subscriptions].
- void handleData(int index, data) {
- current[index] = data;
- dataCount++;
- if (dataCount == subscriptions.length) {
- List data = current;
- current = new List(subscriptions.length);
- dataCount = 0;
- for (int i = 0; i < subscriptions.length; i++) {
- if (i != index) subscriptions[i].resume();
- }
- controller.add(data);
- } else {
- subscriptions[index].pause();
- }
- }
-
- /// Called for each error from a subscription in [subscriptions].
- /// Except if [cancelOnError] is true, in which case the function below
- /// is used instead.
- void handleError(Object error, StackTrace stackTrace) {
- controller.addError(error, stackTrace);
- }
-
- /// Called when a subscription has an error and [cancelOnError] is true.
- ///
- /// Prematurely cancels all subscriptions since we know that we won't
- /// be needing any more values.
- void handleErrorCancel(Object error, StackTrace stackTrace) {
- for (int i = 0; i < subscriptions.length; i++) {
- subscriptions[i].cancel();
- }
- controller.addError(error, stackTrace);
- }
-
- void handleDone() {
- for (int i = 0; i < subscriptions.length; i++) {
- subscriptions[i].cancel();
- }
- controller.close();
- }
-
- try {
- for (Stream stream in _streams) {
- int index = subscriptions.length;
- subscriptions.add(stream.listen(
- (data) { handleData(index, data); },
- onError: cancelOnError ? handleError : handleErrorCancel,
- onDone: handleDone,
- cancelOnError: cancelOnError));
- }
- } catch (e) {
- for (int i = subscriptions.length - 1; i >= 0; i--) {
- subscriptions[i].cancel();
- }
- rethrow;
- }
-
- current = new List(subscriptions.length);
-
- controller = new StreamController<List>(
- onPause: () {
- for (int i = 0; i < subscriptions.length; i++) {
- // This may pause some subscriptions more than once.
- // These will not be resumed by onResume below, but must wait for the
- // next round.
- subscriptions[i].pause();
- }
- },
- onResume: () {
- for (int i = 0; i < subscriptions.length; i++) {
- subscriptions[i].resume();
- }
- },
- onCancel: () {
- for (int i = 0; i < subscriptions.length; i++) {
- // Canceling more than once is safe.
- subscriptions[i].cancel();
- }
- }
- );
-
- if (subscriptions.isEmpty) {
- controller.close();
- }
- return controller.stream.listen(onData,
- onError: onError,
- onDone: onDone,
- cancelOnError: cancelOnError);
- }
-}
+export "package:async/stream_zip.dart";
\ No newline at end of file
diff --git a/pkg/sequence_zip/pubspec.yaml b/pkg/sequence_zip/pubspec.yaml
index fa4d22c..961e43a 100644
--- a/pkg/sequence_zip/pubspec.yaml
+++ b/pkg/sequence_zip/pubspec.yaml
@@ -1,12 +1,14 @@
name: sequence_zip
-version: 0.9.0
-author: "Dart Team <misc@dartlang.org>"
+version: 0.9.1
+author: Dart Team <misc@dartlang.org>
homepage: http://www.dartlang.org
description: >
"Zip" functionality on iterables and streams.
- Combines multiple iterables into a single iterable of tuples of values,
- and similar for Streams.
-dev_dependencies:
- unittest: ">=0.9.0 <0.10.0"
+ This package has been discontinued.
+ The zip functionality for iterables is in `package:collection/iterable_zip.dart`
+ and the zip functionality for streams is in `package:async/stream_zip.dart`.
+dependencies:
+ collection: "0.9.0"
+ async: "0.9.0"
environment:
sdk: ">=0.8.10+6 <2.0.0"
diff --git a/pkg/serialization/LICENSE b/pkg/serialization/LICENSE
new file mode 100644
index 0000000..ee99930
--- /dev/null
+++ b/pkg/serialization/LICENSE
@@ -0,0 +1,26 @@
+Copyright 2013, the Dart project authors. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google Inc. nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/pkg/serialization/README.md b/pkg/serialization/README.md
new file mode 100644
index 0000000..d35ebc8
--- /dev/null
+++ b/pkg/serialization/README.md
@@ -0,0 +1,20 @@
+Serialization
+=============
+
+A general-purpose serialization facility for Dart Objects.
+
+This provides the ability to save and restore objects to pluggable
+Formats using pluggable Rules.
+These rules can use mirrors or be hard-coded. The main principle
+is using only public APIs on the serialized objects, so changes to the
+internal representation do not break previous serializations. It also handles
+cycles, different representations, filling in known objects on the
+receiving side, and other issues. It is not as much intended for
+APIs using JSON to pass acyclic structures without class information,
+and is fairly heavweight and expensive for doing that compared to simpler
+approaches.
+
+For more detailed descriptions and examples of use, see the comment on
+the [serialization][serialization] library.
+
+[serialization]: https://api.dartlang.org/docs/channels/stable/latest/serialization.html
diff --git a/pkg/serialization/pubspec.yaml b/pkg/serialization/pubspec.yaml
index 3a5ea8a..2a8d9b2 100644
--- a/pkg/serialization/pubspec.yaml
+++ b/pkg/serialization/pubspec.yaml
@@ -1,5 +1,5 @@
name: serialization
-version: 0.9.0
+version: 0.9.1
author: "Dart Team <misc@dartlang.org>"
homepage: http://www.dartlang.org
documentation: http://api.dartlang.org/docs/pkg/serialization
@@ -8,4 +8,4 @@
dev_dependencies:
unittest: ">=0.9.0 <0.10.0"
environment:
- sdk: ">=0.8.10+6 <2.0.0"
+ sdk: ">=1.0.0 <2.0.0"
diff --git a/pkg/stack_trace/lib/src/chain.dart b/pkg/stack_trace/lib/src/chain.dart
index f6e2f3f..4055bc8 100644
--- a/pkg/stack_trace/lib/src/chain.dart
+++ b/pkg/stack_trace/lib/src/chain.dart
@@ -157,10 +157,19 @@
/// This calls [Trace.terse] on every trace in [traces], and discards any
/// trace that contain only internal frames.
Chain get terse {
- return new Chain(traces.map((trace) => trace.terse).where((trace) {
+ var terseTraces = traces.map((trace) => trace.terse);
+ var nonEmptyTraces = terseTraces.where((trace) {
// Ignore traces that contain only internal processing.
return trace.frames.length > 1;
- }));
+ });
+
+ // If all the traces contain only internal processing, preserve the last
+ // (top-most) one so that the chain isn't empty.
+ if (nonEmptyTraces.isEmpty && terseTraces.isNotEmpty) {
+ return new Chain([terseTraces.last]);
+ }
+
+ return new Chain(nonEmptyTraces);
}
/// Converts [this] to a [Trace].
diff --git a/pkg/stack_trace/test/chain_test.dart b/pkg/stack_trace/test/chain_test.dart
index 4d31acb..9c16690 100644
--- a/pkg/stack_trace/test/chain_test.dart
+++ b/pkg/stack_trace/test/chain_test.dart
@@ -386,6 +386,21 @@
'$userSlashCode 10:11 Foo.bar\n'
'dart:core Bar.baz\n'));
});
+
+ test("doesn't return in an empty chain", () {
+ var chain = new Chain([
+ new Trace.parse(
+ 'dart:core 10:11 Foo.bar\n'
+ 'package:stack_trace/stack_trace.dart 10:11 Bar.baz\n'
+ 'dart:core 10:11 Zip.zap'),
+ new Trace.parse(
+ 'dart:core 10:11 A.b\n'
+ 'package:stack_trace/stack_trace.dart 10:11 C.d\n'
+ 'dart:core 10:11 E.f')
+ ]);
+
+ expect(chain.terse.toString(), equals('dart:core E.f\n'));
+ });
});
test('Chain.toTrace eliminates asynchronous gaps', () {
diff --git a/pkg/typed_data/LICENSE b/pkg/typed_data/LICENSE
new file mode 100644
index 0000000..ee99930
--- /dev/null
+++ b/pkg/typed_data/LICENSE
@@ -0,0 +1,26 @@
+Copyright 2013, the Dart project authors. All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+ * Neither the name of Google Inc. nor the names of its
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/pkg/typed_data/README.md b/pkg/typed_data/README.md
new file mode 100644
index 0000000..e1e7db5
--- /dev/null
+++ b/pkg/typed_data/README.md
@@ -0,0 +1,15 @@
+Helper libraries for working with typed data lists.
+
+The `typed_data` package contains utility functions and classes that makes working with typed data lists easier.
+
+## Using
+
+The `typed_data` package can be imported as
+
+ import 'package:typed_data/typed_data.dart';
+
+## Typed buffers: Growable typed data lists
+
+Typed buffers are contains growable lists backed by typed arrays.
+These are similar to the growable lists returned by `new List()`,
+but stores typed data like a typed data list.
\ No newline at end of file
diff --git a/pkg/typed_data/lib/typed_buffers.dart b/pkg/typed_data/lib/typed_buffers.dart
new file mode 100644
index 0000000..b880338
--- /dev/null
+++ b/pkg/typed_data/lib/typed_buffers.dart
@@ -0,0 +1,235 @@
+// 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.
+
+/**
+ * Growable typed-data lists.
+ *
+ * These lists works just as a typed-data list, except that they are growable.
+ * They use an underlying buffer, and when that buffer becomes too small, it
+ * is replaced by a new buffer.
+ *
+ * That means that using the [TypedDataView.buffer] getter is not guaranteed
+ * to return the same result each time it is used, and that the buffer may
+ * be larger than what the list is using.
+ */
+library dart.pkg.typed_data.typed_buffers;
+
+import "dart:collection" show ListBase;
+import "dart:typed_data";
+
+abstract class _TypedDataBuffer<E> extends ListBase<E> {
+ static const int INITIAL_LENGTH = 8;
+
+ /// This is a Uint8List for Uint8Buffer. It's both a List<E> and a TypedData,
+ /// which we don't have a type for here.
+ var _buffer;
+ /// The length of the list being built.
+ int _length;
+
+ _TypedDataBuffer(List<E> buffer)
+ : this._buffer = buffer, this._length = buffer.length;
+
+ int get length => _length;
+ E operator[](int index) {
+ if (index >= length) throw new RangeError.range(index, 0, length - 1);
+ return _buffer[index];
+ }
+
+ void operator[]=(int index, E value) {
+ if (index >= length) throw new RangeError.range(index, 0, length - 1);
+ _buffer[index] = value;
+ }
+
+ void set length(int newLength) {
+ if (newLength < _length) {
+ E defaultValue = _defaultValue;
+ for (int i = newLength; i < _length; i++) {
+ _buffer[i] = defaultValue;
+ }
+ } else if (newLength > _buffer.length) {
+ List<E> newBuffer;
+ if (_buffer.length == 0) {
+ newBuffer = _createBuffer(newLength);
+ } else {
+ newBuffer = _createBiggerBuffer(newLength);
+ }
+ newBuffer.setRange(0, _length, _buffer);
+ _buffer = newBuffer;
+ }
+ _length = newLength;
+ }
+
+ void _add(E value) {
+ if (_length == _buffer.length) _grow();
+ _buffer[_length++] = value;
+ }
+
+ // We override the default implementation of `add` and `addAll` because
+ // they grow by setting the length in increments of one. We want to grow
+ // by doubling capacity in most cases.
+ void add(E value) { _add(value); }
+
+ void addAll(Iterable<E> values) {
+ for (E value in values) _add(value);
+ }
+
+ void insert(int index, E element) {
+ if (index < 0 || index > _length) {
+ throw new RangeError.range(index, 0, _length);
+ }
+ if (_length < _buffer.length) {
+ _buffer.setRange(index + 1, _length + 1, _buffer, index);
+ _buffer[index] = element;
+ _length++;
+ return;
+ }
+ List<E> newBuffer = _createBiggerBuffer(null);
+ newBuffer.setRange(0, index, _buffer);
+ newBuffer.setRange(index + 1, _length + 1, _buffer, index);
+ newBuffer[index] = element;
+ _length++;
+ _buffer = newBuffer;
+ }
+
+ /**
+ * Create a bigger buffer.
+ *
+ * This method determines how much bigger a bigger buffer should
+ * be. If [requiredLength] is not null, it will be at least that
+ * size. It will always have at least have double the capacity of
+ * the current buffer.
+ */
+ List<E> _createBiggerBuffer(int requiredLength) {
+ int newLength = _buffer.length * 2;
+ if (requiredLength != null && newLength < requiredLength) {
+ newLength = requiredLength;
+ } else if (newLength < INITIAL_LENGTH) {
+ newLength = INITIAL_LENGTH;
+ }
+ return _createBuffer(newLength);
+ }
+
+ void _grow() {
+ _buffer = _createBiggerBuffer(null)..setRange(0, _length, _buffer);
+ }
+
+ void setRange(int start, int end, Iterable<E> source, [int skipCount = 0]) {
+ if (end > _length) throw new RangeError.range(end, 0, _length);
+ if (source is _TypedDataBuffer<E>) {
+ _buffer.setRange(start, end, source._buffer, skipCount);
+ } else {
+ _buffer.setRange(start, end, source, skipCount);
+ }
+ }
+
+ // TypedData.
+
+ int get elementSizeInBytes => _buffer.elementSizeInBytes;
+
+ int get lengthInBytes => _length * _buffer.elementSizeInBytes;
+
+ int get offsetInBytes => _buffer.offsetInBytes;
+
+ /**
+ * Returns the underlying [ByteBuffer].
+ *
+ * The returned buffer may be replaced by operations that change the [length]
+ * of this list.
+ *
+ * The buffer may be larger than [lengthInBytes] bytes, but never smaller.
+ */
+ ByteBuffer get buffer => _buffer.buffer;
+
+ // Specialization for the specific type.
+
+ // Return zero for integers, 0.0 for floats, etc.
+ // Used to fill buffer when changing length.
+ E get _defaultValue;
+
+ // Create a new typed list to use as buffer.
+ List<E> _createBuffer(int size);
+}
+
+abstract class _IntBuffer extends _TypedDataBuffer<int> {
+ _IntBuffer(buffer): super(buffer);
+ int get _defaultValue => 0;
+}
+
+abstract class _FloatBuffer extends _TypedDataBuffer<double> {
+ _FloatBuffer(buffer): super(buffer);
+ double get _defaultValue => 0.0;
+}
+
+class Uint8Buffer extends _IntBuffer {
+ Uint8Buffer([int initialLength = 0]) : super(new Uint8List(initialLength));
+ Uint8List _createBuffer(int size) => new Uint8List(size);
+}
+
+class Int8Buffer extends _IntBuffer {
+ Int8Buffer([int initialLength = 0]) : super(new Int8List(initialLength));
+ Int8List _createBuffer(int size) => new Int8List(size);
+}
+
+class Uint8ClampedBuffer extends _IntBuffer {
+ Uint8ClampedBuffer([int initialLength = 0])
+ : super(new Uint8ClampedList(initialLength));
+ Uint8ClampedList _createBuffer(int size) => new Uint8ClampedList(size);
+}
+
+class Uint16Buffer extends _IntBuffer {
+ Uint16Buffer([int initialLength = 0]) : super(new Uint16List(initialLength));
+ Uint16List _createBuffer(int size) => new Uint16List(size);
+}
+
+class Int16Buffer extends _IntBuffer {
+ Int16Buffer([int initialLength = 0]) : super(new Int16List(initialLength));
+ Int16List _createBuffer(int size) => new Int16List(size);
+}
+
+class Uint32Buffer extends _IntBuffer {
+ Uint32Buffer([int initialLength = 0]) : super(new Uint32List(initialLength));
+ Uint32List _createBuffer(int size) => new Uint32List(size);
+}
+
+class Int32Buffer extends _IntBuffer {
+ Int32Buffer([int initialLength = 0]) : super(new Int32List(initialLength));
+ Int32List _createBuffer(int size) => new Int32List(size);
+}
+
+class Uint64Buffer extends _IntBuffer {
+ Uint64Buffer([int initialLength = 0]) : super(new Uint64List(initialLength));
+ Uint64List _createBuffer(int size) => new Uint64List(size);
+}
+
+class Int64Buffer extends _IntBuffer {
+ Int64Buffer([int initialLength = 0]) : super(new Int64List(initialLength));
+ Int64List _createBuffer(int size) => new Int64List(size);
+}
+
+class Float32Buffer extends _FloatBuffer {
+ Float32Buffer([int initialLength = 0])
+ : super(new Float32List(initialLength));
+ Float32List _createBuffer(int size) => new Float32List(size);
+}
+
+class Float64Buffer extends _FloatBuffer {
+ Float64Buffer([int initialLength = 0])
+ : super(new Float64List(initialLength));
+ Float64List _createBuffer(int size) => new Float64List(size);
+}
+
+class Int32x4Buffer extends _TypedDataBuffer<Int32x4> {
+ static Int32x4 _zero = new Int32x4(0, 0, 0, 0);
+ Int32x4Buffer([int initialLength = 0])
+ : super(new Int32x4List(initialLength));
+ Int32x4 get _defaultValue => _zero;
+ Int32x4List _createBuffer(int size) => new Int32x4List(size);
+}
+
+class Float32x4Buffer extends _TypedDataBuffer<Float32x4> {
+ Float32x4Buffer([int initialLength = 0])
+ : super(new Float32x4List(initialLength));
+ Float32x4 get _defaultValue => new Float32x4.zero();
+ Float32x4List _createBuffer(int size) => new Float32x4List(size);
+}
diff --git a/pkg/typed_data/lib/typed_data.dart b/pkg/typed_data/lib/typed_data.dart
new file mode 100644
index 0000000..b6619ab
--- /dev/null
+++ b/pkg/typed_data/lib/typed_data.dart
@@ -0,0 +1,10 @@
+// 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.
+
+/**
+ * Utilities and functionality related to the "dart:typed_data" library.
+ */
+library dart.pkg.typed_data;
+
+export "package:typed_data/typed_buffers.dart";
diff --git a/pkg/typed_data/pubspec.yaml b/pkg/typed_data/pubspec.yaml
new file mode 100644
index 0000000..af2e72a
--- /dev/null
+++ b/pkg/typed_data/pubspec.yaml
@@ -0,0 +1,9 @@
+name: typed_data
+version: 0.9.0
+author: Dart Team <misc@dartlang.org>
+description: Utility functions and classes related to the 'dart:typed_data' library.
+homepage: http://www.dartlang.org
+dev_dependencies:
+ unittest: ">=0.9.0 <0.10.0"
+environment:
+ sdk: ">=1.0.0 <2.0.0"
diff --git a/pkg/collection_helpers/test/typed_buffers_test.dart b/pkg/typed_data/test/typed_buffers_test.dart
similarity index 99%
rename from pkg/collection_helpers/test/typed_buffers_test.dart
rename to pkg/typed_data/test/typed_buffers_test.dart
index d8ba5d0..1cb37b0 100644
--- a/pkg/collection_helpers/test/typed_buffers_test.dart
+++ b/pkg/typed_data/test/typed_buffers_test.dart
@@ -4,7 +4,7 @@
// Tests typed-data buffer classes.
-import "package:collection_helpers/all.dart";
+import "package:typed_data/typed_buffers.dart";
import "package:unittest/unittest.dart";
import "dart:typed_data";
diff --git a/pkg/unittest/lib/compact_vm_config.dart b/pkg/unittest/lib/compact_vm_config.dart
index 69560ac..c531d80 100644
--- a/pkg/unittest/lib/compact_vm_config.dart
+++ b/pkg/unittest/lib/compact_vm_config.dart
@@ -67,6 +67,20 @@
}
}
+ void onTestResultChanged(TestCase test) {
+ _pass--;
+ _fail++;
+ _progressLine(_start, _pass, _fail, test.description);
+ print('');
+ if (test.message != '') {
+ print(indent(test.message));
+ }
+
+ if (test.stackTrace != null) {
+ print(indent(test.stackTrace.toString()));
+ }
+ }
+
void onDone(bool success) {
// Override and don't call the superclass onDone() to avoid printing the
// "unittest-suite-..." boilerplate.
diff --git a/pkg/unittest/lib/src/iterable_matchers.dart b/pkg/unittest/lib/src/iterable_matchers.dart
index ab7827f..2189286 100644
--- a/pkg/unittest/lib/src/iterable_matchers.dart
+++ b/pkg/unittest/lib/src/iterable_matchers.dart
@@ -108,69 +108,27 @@
}
}
}
+
/**
* Returns a matcher which matches [Iterable]s that have the same
* length and the same elements as [expected], but not necessarily in
* the same order. Note that this is O(n^2) so should only be used on
* small objects.
*/
-Matcher unorderedEquals(Iterable expected) =>
- new _UnorderedEquals(expected);
+Matcher unorderedEquals(Iterable expected) => new _UnorderedEquals(expected);
-class _UnorderedEquals extends Matcher {
- Iterable _expected;
+class _UnorderedEquals extends _UnorderedMatches {
+ final List _expectedValues;
- _UnorderedEquals(Iterable this._expected);
-
- String _test(item) {
- if (item is !Iterable) {
- return 'not iterable';
- }
- // Check the lengths are the same.
- var expectedLength = _expected.length;
- var actualLength = item.length;
- if (expectedLength > actualLength) {
- return 'has too few elements (${actualLength} < ${expectedLength})';
- } else if (expectedLength < actualLength) {
- return 'has too many elements (${actualLength} > ${expectedLength})';
- }
- List<bool> matched = new List<bool>(actualLength);
- for (var i = 0; i < actualLength; i++) {
- matched[i] = false;
- }
- var expectedPosition = 0;
- for (var expectedElement in _expected) {
- var actualPosition = 0;
- var gotMatch = false;
- for (var actualElement in item) {
- if (!matched[actualPosition]) {
- if (expectedElement == actualElement) {
- matched[actualPosition] = gotMatch = true;
- break;
- }
- }
- ++actualPosition;
- }
- if (!gotMatch) {
- Description reason = new StringDescription();
- reason.add('has no match for element ').
- addDescriptionOf(expectedElement).
- add(' at index ${expectedPosition}');
- return reason.toString();
- }
- ++expectedPosition;
- }
- return null;
- }
-
- bool matches(item, Map mismatchState) => (_test(item) == null);
+ _UnorderedEquals(Iterable expected)
+ : super(expected.map(equals)),
+ _expectedValues = expected.toList();
Description describe(Description description) =>
- description.add('equals ').addDescriptionOf(_expected).add(' unordered');
-
- Description describeMismatch(item, Description mismatchDescription,
- Map matchState, bool verbose) =>
- mismatchDescription.add(_test(item));
+ description
+ .add('equals ')
+ .addDescriptionOf(_expectedValues)
+ .add(' unordered');
}
/**
@@ -193,6 +151,73 @@
}
/**
+ * Returns a matcher which matches [Iterable]s whose elements match the matchers
+ * in [expected], but not necessarily in the same order.
+ *
+ * Note that this is `O(n^2)` and so should only be used on small objects.
+ */
+Matcher unorderedMatches(Iterable expected) =>
+ new _UnorderedMatches(expected);
+
+class _UnorderedMatches extends Matcher {
+ final List<Matcher> _expected;
+
+ _UnorderedMatches(Iterable expected)
+ : _expected = expected.map(wrapMatcher).toList();
+
+ String _test(item) {
+ if (item is !Iterable) return 'not iterable';
+ item = item.toList();
+
+ // Check the lengths are the same.
+ if (_expected.length > item.length) {
+ return 'has too few elements (${item.length} < ${_expected.length})';
+ } else if (_expected.length < item.length) {
+ return 'has too many elements (${item.length} > ${_expected.length})';
+ }
+
+ var matched = new List<bool>.filled(item.length, false);
+ var expectedPosition = 0;
+ for (var expectedMatcher in _expected) {
+ var actualPosition = 0;
+ var gotMatch = false;
+ for (var actualElement in item) {
+ if (!matched[actualPosition]) {
+ if (expectedMatcher.matches(actualElement, {})) {
+ matched[actualPosition] = gotMatch = true;
+ break;
+ }
+ }
+ ++actualPosition;
+ }
+
+ if (!gotMatch) {
+ return new StringDescription()
+ .add('has no match for ')
+ .addDescriptionOf(expectedMatcher)
+ .add(' at index ${expectedPosition}')
+ .toString();
+ }
+
+ ++expectedPosition;
+ }
+ return null;
+ }
+
+ bool matches(item, Map mismatchState) => _test(item) == null;
+
+ Description describe(Description description) =>
+ description
+ .add('matches ')
+ .addAll('[', ', ', ']', _expected)
+ .add(' unordered');
+
+ Description describeMismatch(item, Description mismatchDescription,
+ Map matchState, bool verbose) =>
+ mismatchDescription.add(_test(item));
+}
+
+/**
* A pairwise matcher for iterable. You can pass an arbitrary [comparator]
* function that takes an expected and actual argument which will be applied
* to each pair in order. [description] should be a meaningful name for
diff --git a/pkg/unittest/pubspec.yaml b/pkg/unittest/pubspec.yaml
index dd67528..f1c1d4a 100644
--- a/pkg/unittest/pubspec.yaml
+++ b/pkg/unittest/pubspec.yaml
@@ -1,5 +1,5 @@
name: unittest
-version: 0.9.1
+version: 0.9.2+1
author: Dart Team <misc@dartlang.org>
description: A library for writing dart unit tests.
homepage: http://www.dartlang.org
diff --git a/pkg/unittest/test/matchers_test.dart b/pkg/unittest/test/matchers_test.dart
index 1ec1e92..9f8e121 100644
--- a/pkg/unittest/test/matchers_test.dart
+++ b/pkg/unittest/test/matchers_test.dart
@@ -481,7 +481,30 @@
shouldFail(d, unorderedEquals([3, 1]),
"Expected: equals [3, 1] unordered "
"Actual: [1, 2] "
- "Which: has no match for element <3> at index 0");
+ "Which: has no match for <3> at index 0");
+ });
+
+ test('unorderedMatchess', () {
+ var d = [1, 2];
+ shouldPass(d, unorderedMatches([2, 1]));
+ shouldPass(d, unorderedMatches([greaterThan(1), greaterThan(0)]));
+ shouldFail(d, unorderedMatches([greaterThan(0)]),
+ "Expected: matches [a value greater than <0>] unordered "
+ "Actual: [1, 2] "
+ "Which: has too many elements (2 > 1)");
+ shouldFail(d, unorderedMatches([3, 2, 1]),
+ "Expected: matches [<3>, <2>, <1>] unordered "
+ "Actual: [1, 2] "
+ "Which: has too few elements (2 < 3)");
+ shouldFail(d, unorderedMatches([3, 1]),
+ "Expected: matches [<3>, <1>] unordered "
+ "Actual: [1, 2] "
+ "Which: has no match for <3> at index 0");
+ shouldFail(d, unorderedMatches([greaterThan(3), greaterThan(0)]),
+ "Expected: matches [a value greater than <3>, a value greater than "
+ "<0>] unordered "
+ "Actual: [1, 2] "
+ "Which: has no match for a value greater than <3> at index 0");
});
test('pairwise compare', () {
diff --git a/pkg/unmodifiable_collection/lib/unmodifiable_collection.dart b/pkg/unmodifiable_collection/lib/unmodifiable_collection.dart
index 17e24e5..428bb7d 100644
--- a/pkg/unmodifiable_collection/lib/unmodifiable_collection.dart
+++ b/pkg/unmodifiable_collection/lib/unmodifiable_collection.dart
@@ -5,18 +5,18 @@
/**
* This library used to introduce unmodifiable wrappers for collections.
*
- * This functionality has been moved to the `collection_helpers` library.
+ * This functionality has been moved to the `collection` library.
*
* Please replace the import of this library with:
*
- * import "package:collection_helpers/wrappers.dart";
+ * import "package:collection/wrappers.dart";
*
* and change dependencies to match.
*/
@deprecated
library unmodifiable_collection;
-export "package:collection_helpers/wrappers.dart"
+export "package:collection/wrappers.dart"
show UnmodifiableListView,
UnmodifiableSetView,
UnmodifiableMapView,
diff --git a/pkg/unmodifiable_collection/pubspec.yaml b/pkg/unmodifiable_collection/pubspec.yaml
index b4ee459..2e59d7a 100644
--- a/pkg/unmodifiable_collection/pubspec.yaml
+++ b/pkg/unmodifiable_collection/pubspec.yaml
@@ -1,12 +1,12 @@
name: unmodifiable_collection
-version: 0.9.1
+version: 0.9.2
author: "Dart Team <misc@dartlang.org>"
homepage: http://www.dartlang.org
documentation: http://api.dartlang.org/docs/pkg/unmodifiable_collection
description: >
- Discontinued library. Use package:collection_helpers/wrappers.dart instead.
+ Discontinued library. Use package:collection/wrappers.dart instead.
dependencies:
- collection_helpers: ">=0.9.0 <0.10.0"
+ collection: ">=0.9.0 <0.10.0"
environment:
sdk: ">=0.8.10+6 <2.0.0"
diff --git a/runtime/bin/builtin.h b/runtime/bin/builtin.h
index 90a121e..a4d8a13 100644
--- a/runtime/bin/builtin.h
+++ b/runtime/bin/builtin.h
@@ -54,7 +54,8 @@
// Native method support.
static Dart_NativeFunction NativeLookup(Dart_Handle name,
- int argument_count);
+ int argument_count,
+ bool* auto_setup_scope);
static const char* builtin_source_paths_[];
static const char* io_source_paths_[];
diff --git a/runtime/bin/builtin_gen_snapshot.cc b/runtime/bin/builtin_gen_snapshot.cc
index 9a89adb..965a862 100644
--- a/runtime/bin/builtin_gen_snapshot.cc
+++ b/runtime/bin/builtin_gen_snapshot.cc
@@ -29,11 +29,14 @@
Dart_NativeFunction Builtin::NativeLookup(Dart_Handle name,
- int argument_count) {
+ int argument_count,
+ bool* auto_setup_scope) {
const char* function_name = NULL;
Dart_Handle result = Dart_StringToCString(name, &function_name);
DART_CHECK_VALID(result);
ASSERT(function_name != NULL);
+ ASSERT(auto_setup_scope != NULL);
+ *auto_setup_scope = true;
int num_entries = sizeof(BuiltinEntries) / sizeof(struct NativeEntries);
for (int i = 0; i < num_entries; i++) {
struct NativeEntries* entry = &(BuiltinEntries[i]);
diff --git a/runtime/bin/builtin_natives.cc b/runtime/bin/builtin_natives.cc
index ca3d8a3..5681c0a 100644
--- a/runtime/bin/builtin_natives.cc
+++ b/runtime/bin/builtin_natives.cc
@@ -54,6 +54,7 @@
V(File_Delete, 1) \
V(File_DeleteLink, 1) \
V(File_Rename, 2) \
+ V(File_Copy, 2) \
V(File_RenameLink, 2) \
V(File_ResolveSymbolicLinks, 1) \
V(File_OpenStdio, 1) \
@@ -84,11 +85,14 @@
* Looks up native functions in both libdart_builtin and libdart_io.
*/
Dart_NativeFunction Builtin::NativeLookup(Dart_Handle name,
- int argument_count) {
+ int argument_count,
+ bool* auto_setup_scope) {
const char* function_name = NULL;
Dart_Handle result = Dart_StringToCString(name, &function_name);
DART_CHECK_VALID(result);
ASSERT(function_name != NULL);
+ ASSERT(auto_setup_scope != NULL);
+ *auto_setup_scope = true;
int num_entries = sizeof(BuiltinEntries) / sizeof(struct NativeEntries);
for (int i = 0; i < num_entries; i++) {
struct NativeEntries* entry = &(BuiltinEntries[i]);
@@ -97,7 +101,7 @@
return reinterpret_cast<Dart_NativeFunction>(entry->function_);
}
}
- return IONativeLookup(name, argument_count);
+ return IONativeLookup(name, argument_count, auto_setup_scope);
}
diff --git a/runtime/bin/dbg_message.cc b/runtime/bin/dbg_message.cc
index 5912c31..55f2db4 100644
--- a/runtime/bin/dbg_message.cc
+++ b/runtime/bin/dbg_message.cc
@@ -1017,27 +1017,54 @@
}
-void DbgMsgQueue::HandleMessages() {
- bool resume_requested = false;
+void DbgMsgQueue::Notify() {
MonitorLocker ml(&msg_queue_lock_);
- is_running_ = false;
- while (!resume_requested) {
- while (msglist_head_ == NULL) {
- ASSERT(msglist_tail_ == NULL);
- dart::Monitor::WaitResult res = ml.Wait(); // Wait for debugger commands.
- ASSERT(res == dart::Monitor::kNotified);
- }
- while (msglist_head_ != NULL && !resume_requested) {
- ASSERT(msglist_tail_ != NULL);
- DbgMessage* msg = msglist_head_;
- msglist_head_ = msglist_head_->next();
- resume_requested = msg->HandleMessage();
- delete msg;
- }
+ ml.Notify();
+}
+
+
+bool DbgMsgQueue::HandlePendingMessages() {
+ // Handle all available debug messages, up to a resume request.
+ bool resume_requested = false;
+ while (msglist_head_ != NULL && !resume_requested) {
+ ASSERT(msglist_tail_ != NULL);
+ DbgMessage* msg = msglist_head_;
+ msglist_head_ = msglist_head_->next();
if (msglist_head_ == NULL) {
msglist_tail_ = NULL;
}
+ resume_requested = msg->HandleMessage();
+ delete msg;
}
+ return resume_requested;
+}
+
+
+void DbgMsgQueue::MessageLoop() {
+ MonitorLocker ml(&msg_queue_lock_);
+ is_running_ = false;
+
+ // Request notification on isolate messages. This allows us to
+ // respond to vm service messages while at breakpoint.
+ Dart_SetMessageNotifyCallback(DbgMsgQueueList::NotifyIsolate);
+
+ while (true) {
+ // Handle all available vm service messages, up to a resume
+ // request.
+ if (Dart_HandleServiceMessages()) {
+ break;
+ }
+
+ // Handle all available debug messages, up to a resume request.
+ if (HandlePendingMessages()) {
+ break;
+ }
+
+ // Wait for more debug or vm service messages.
+ dart::Monitor::WaitResult res = ml.Wait();
+ ASSERT(res == dart::Monitor::kNotified);
+ }
+ Dart_SetMessageNotifyCallback(NULL);
is_interrupted_ = false;
is_running_ = true;
}
@@ -1177,6 +1204,16 @@
}
+void DbgMsgQueueList::NotifyIsolate(Dart_Isolate isolate) {
+ MutexLocker ml(msg_queue_list_lock_);
+ Dart_IsolateId isolate_id = Dart_GetIsolateId(isolate);
+ DbgMsgQueue* queue = DbgMsgQueueList::GetIsolateMsgQueueLocked(isolate_id);
+ if (queue != NULL) {
+ queue->Notify();
+ }
+}
+
+
bool DbgMsgQueueList::InterruptIsolate(Dart_IsolateId isolate_id) {
MutexLocker ml(msg_queue_list_lock_);
DbgMsgQueue* queue = DbgMsgQueueList::GetIsolateMsgQueueLocked(isolate_id);
@@ -1293,7 +1330,7 @@
ASSERT(msg_queue != NULL);
msg_queue->SendQueuedMsgs();
msg_queue->SendBreakpointEvent(bp_id, loc);
- msg_queue->HandleMessages();
+ msg_queue->MessageLoop();
Dart_ExitScope();
}
@@ -1307,7 +1344,7 @@
ASSERT(msg_queue != NULL);
msg_queue->SendQueuedMsgs();
msg_queue->SendExceptionEvent(exception, stack_trace);
- msg_queue->HandleMessages();
+ msg_queue->MessageLoop();
Dart_ExitScope();
}
@@ -1325,7 +1362,7 @@
msg_queue->SendQueuedMsgs();
msg_queue->SendIsolateEvent(isolate_id, kind);
if (kind == kInterrupted) {
- msg_queue->HandleMessages();
+ msg_queue->MessageLoop();
} else {
ASSERT(kind == kShutdown);
RemoveIsolateMsgQueue(isolate_id);
diff --git a/runtime/bin/dbg_message.h b/runtime/bin/dbg_message.h
index 79551ee..23c08fc 100644
--- a/runtime/bin/dbg_message.h
+++ b/runtime/bin/dbg_message.h
@@ -161,8 +161,16 @@
const char* end,
int debug_fd);
- // Handle all debug command messages in the queue.
- void HandleMessages();
+ // Notify an isolate of a pending vmservice message.
+ void Notify();
+
+ // Run a message loop which handles messages as they arrive until
+ // normal program execution resumes.
+ void MessageLoop();
+
+ // Handle any pending debug command messages in the queue. Return
+ // value indicates whether a resume has been requested.
+ bool HandlePendingMessages();
// Interrupt Isolate.
void InterruptIsolate();
@@ -225,6 +233,9 @@
const char* end,
int debug_fd);
+ // Notify an isolate of a pending vmservice message.
+ static void NotifyIsolate(Dart_Isolate isolate);
+
// Interrupt isolate.
static bool InterruptIsolate(Dart_IsolateId isolate_id);
diff --git a/runtime/bin/eventhandler_linux.cc b/runtime/bin/eventhandler_linux.cc
index 335238c..0db1f53 100644
--- a/runtime/bin/eventhandler_linux.cc
+++ b/runtime/bin/eventhandler_linux.cc
@@ -134,8 +134,7 @@
if (status == -1) {
FATAL("Failed adding interrupt fd to epoll instance");
}
- timer_fd_ = TEMP_FAILURE_RETRY(timerfd_create(CLOCK_REALTIME,
- TFD_NONBLOCK | TFD_CLOEXEC));
+ timer_fd_ = TEMP_FAILURE_RETRY(timerfd_create(CLOCK_REALTIME, TFD_CLOEXEC));
if (epoll_fd_ == -1) {
FATAL("Failed creating timerfd file descriptor");
}
@@ -147,7 +146,8 @@
timer_fd_,
&event));
if (status == -1) {
- FATAL("Failed adding timerfd fd to epoll instance");
+ FATAL2(
+ "Failed adding timerfd fd(%i) to epoll instance: %i", timer_fd_, errno);
}
}
diff --git a/runtime/bin/eventhandler_win.cc b/runtime/bin/eventhandler_win.cc
index 7b5d66a..b6ac1ce 100644
--- a/runtime/bin/eventhandler_win.cc
+++ b/runtime/bin/eventhandler_win.cc
@@ -429,7 +429,6 @@
bool ListenSocket::IssueAccept() {
ScopedLock lock(this);
-
// For AcceptEx there needs to be buffer storage for address
// information for two addresses (local and remote address). The
// AcceptEx documentation says: "This value must be at least 16
@@ -452,9 +451,10 @@
buffer->GetCleanOverlapped());
if (!ok) {
if (WSAGetLastError() != WSA_IO_PENDING) {
- Log::PrintErr("AcceptEx failed: %d\n", WSAGetLastError());
+ int error = WSAGetLastError();
closesocket(buffer->client());
OverlappedBuffer::DisposeBuffer(buffer);
+ WSASetLastError(error);
return false;
}
}
@@ -972,7 +972,11 @@
}
// Always keep 5 outstanding accepts going, to enhance performance.
while (listen_socket->pending_accept_count() < 5) {
- listen_socket->IssueAccept();
+ bool accept_success = listen_socket->IssueAccept();
+ if (!accept_success) {
+ HandleError(listen_socket);
+ break;
+ }
}
}
diff --git a/runtime/bin/file.cc b/runtime/bin/file.cc
index f0205fb..7f40f96 100644
--- a/runtime/bin/file.cc
+++ b/runtime/bin/file.cc
@@ -262,7 +262,6 @@
// Write the data out into the file.
int64_t bytes_written = file->Write(reinterpret_cast<void*>(buffer), length);
-
// Release the direct pointer acquired above.
result = Dart_TypedDataReleaseData(buffer_obj);
if (Dart_IsError(result)) Dart_PropagateError(result);
@@ -503,6 +502,22 @@
}
+void FUNCTION_NAME(File_Copy)(Dart_NativeArguments args) {
+ const char* old_path =
+ DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0));
+ const char* new_path =
+ DartUtils::GetStringValue(Dart_GetNativeArgument(args, 1));
+ bool result = File::Copy(old_path, new_path);
+ if (result) {
+ Dart_SetReturnValue(args, Dart_NewBoolean(result));
+ } else {
+ Dart_Handle err = DartUtils::NewDartOSError();
+ if (Dart_IsError(err)) Dart_PropagateError(err);
+ Dart_SetReturnValue(args, err);
+ }
+}
+
+
void FUNCTION_NAME(File_ResolveSymbolicLinks)(Dart_NativeArguments args) {
const char* str =
DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0));
@@ -706,6 +721,20 @@
}
+CObject* File::CopyRequest(const CObjectArray& request) {
+ if (request.Length() == 2 &&
+ request[0]->IsString() &&
+ request[1]->IsString()) {
+ CObjectString old_path(request[0]);
+ CObjectString new_path(request[1]);
+ bool completed = File::Copy(old_path.CString(), new_path.CString());
+ if (completed) return CObject::True();
+ return CObject::NewOSError();
+ }
+ return CObject::IllegalArgumentError();
+}
+
+
CObject* File::ResolveSymbolicLinksRequest(const CObjectArray& request) {
if (request.Length() == 1 && request[0]->IsString()) {
CObjectString filename(request[0]);
diff --git a/runtime/bin/file.h b/runtime/bin/file.h
index 1f3eb11..ec1bac8 100644
--- a/runtime/bin/file.h
+++ b/runtime/bin/file.h
@@ -126,6 +126,7 @@
static bool DeleteLink(const char* path);
static bool Rename(const char* old_path, const char* new_path);
static bool RenameLink(const char* old_path, const char* new_path);
+ static bool Copy(const char* old_path, const char* new_path);
static off64_t LengthFromPath(const char* path);
static void Stat(const char* path, int64_t* data);
static time_t LastModified(const char* path);
@@ -144,6 +145,7 @@
static CObject* CreateRequest(const CObjectArray& request);
static CObject* DeleteRequest(const CObjectArray& request);
static CObject* RenameRequest(const CObjectArray& request);
+ static CObject* CopyRequest(const CObjectArray& request);
static CObject* OpenRequest(const CObjectArray& request);
static CObject* ResolveSymbolicLinksRequest(const CObjectArray& request);
static CObject* CloseRequest(const CObjectArray& request);
diff --git a/runtime/bin/file_android.cc b/runtime/bin/file_android.cc
index 917e83e..3851c32 100644
--- a/runtime/bin/file_android.cc
+++ b/runtime/bin/file_android.cc
@@ -11,11 +11,13 @@
#include <fcntl.h> // NOLINT
#include <sys/stat.h> // NOLINT
#include <sys/types.h> // NOLINT
+#include <sys/sendfile.h> // NOLINT
#include <unistd.h> // NOLINT
#include <libgen.h> // NOLINT
#include "bin/builtin.h"
#include "bin/log.h"
+#include "bin/signal_blocker.h"
namespace dart {
@@ -46,7 +48,7 @@
void File::Close() {
ASSERT(handle_->fd() >= 0);
- int err = TEMP_FAILURE_RETRY(close(handle_->fd()));
+ int err = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(handle_->fd()));
if (err != 0) {
const int kBufferSize = 1024;
char error_message[kBufferSize];
@@ -64,13 +66,15 @@
int64_t File::Read(void* buffer, int64_t num_bytes) {
ASSERT(handle_->fd() >= 0);
- return TEMP_FAILURE_RETRY(read(handle_->fd(), buffer, num_bytes));
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(read(handle_->fd(), buffer,
+ num_bytes));
}
int64_t File::Write(const void* buffer, int64_t num_bytes) {
ASSERT(handle_->fd() >= 0);
- return TEMP_FAILURE_RETRY(write(handle_->fd(), buffer, num_bytes));
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(write(handle_->fd(), buffer,
+ num_bytes));
}
@@ -88,20 +92,21 @@
bool File::Truncate(off64_t length) {
ASSERT(handle_->fd() >= 0);
- return TEMP_FAILURE_RETRY(ftruncate(handle_->fd(), length) != -1);
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
+ ftruncate(handle_->fd(), length) != -1);
}
bool File::Flush() {
ASSERT(handle_->fd() >= 0);
- return TEMP_FAILURE_RETRY(fsync(handle_->fd()) != -1);
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(fsync(handle_->fd()) != -1);
}
off64_t File::Length() {
ASSERT(handle_->fd() >= 0);
struct stat st;
- if (TEMP_FAILURE_RETRY(fstat(handle_->fd(), &st)) == 0) {
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(fstat(handle_->fd(), &st)) == 0) {
return st.st_size;
}
return -1;
@@ -111,7 +116,7 @@
File* File::Open(const char* name, FileOpenMode mode) {
// Report errors for non-regular files.
struct stat st;
- if (TEMP_FAILURE_RETRY(stat(name, &st)) == 0) {
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(stat(name, &st)) == 0) {
if (!S_ISREG(st.st_mode)) {
errno = (S_ISDIR(st.st_mode)) ? EISDIR : ENOENT;
return NULL;
@@ -125,7 +130,7 @@
flags = flags | O_TRUNC;
}
flags |= O_CLOEXEC;
- int fd = TEMP_FAILURE_RETRY(open(name, flags, 0666));
+ int fd = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(open(name, flags, 0666));
if (fd < 0) {
return NULL;
}
@@ -147,7 +152,7 @@
bool File::Exists(const char* name) {
struct stat st;
- if (TEMP_FAILURE_RETRY(stat(name, &st)) == 0) {
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(stat(name, &st)) == 0) {
return S_ISREG(st.st_mode);
} else {
return false;
@@ -156,7 +161,9 @@
bool File::Create(const char* name) {
- int fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CREAT | O_CLOEXEC, 0666));
+ int fd = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(open(name,
+ O_RDONLY | O_CREAT | O_CLOEXEC,
+ 0666));
if (fd < 0) {
return false;
}
@@ -165,7 +172,7 @@
bool File::CreateLink(const char* name, const char* target) {
- int status = TEMP_FAILURE_RETRY(symlink(target, name));
+ int status = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(symlink(target, name));
return (status == 0);
}
@@ -173,7 +180,7 @@
bool File::Delete(const char* name) {
File::Type type = File::GetType(name, true);
if (type == kIsFile) {
- return TEMP_FAILURE_RETRY(unlink(name)) == 0;
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(unlink(name)) == 0;
} else if (type == kIsDirectory) {
errno = EISDIR;
} else {
@@ -186,7 +193,7 @@
bool File::DeleteLink(const char* name) {
File::Type type = File::GetType(name, false);
if (type == kIsLink) {
- return TEMP_FAILURE_RETRY(unlink(name)) == 0;
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(unlink(name)) == 0;
}
errno = EINVAL;
return false;
@@ -196,7 +203,7 @@
bool File::Rename(const char* old_path, const char* new_path) {
File::Type type = File::GetType(old_path, true);
if (type == kIsFile) {
- return TEMP_FAILURE_RETRY(rename(old_path, new_path)) == 0;
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(rename(old_path, new_path)) == 0;
} else if (type == kIsDirectory) {
errno = EISDIR;
} else {
@@ -209,7 +216,7 @@
bool File::RenameLink(const char* old_path, const char* new_path) {
File::Type type = File::GetType(old_path, false);
if (type == kIsLink) {
- return TEMP_FAILURE_RETRY(rename(old_path, new_path)) == 0;
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(rename(old_path, new_path)) == 0;
} else if (type == kIsDirectory) {
errno = EISDIR;
} else {
@@ -219,9 +226,68 @@
}
+bool File::Copy(const char* old_path, const char* new_path) {
+ File::Type type = File::GetType(old_path, true);
+ if (type == kIsFile) {
+ struct stat st;
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(stat(old_path, &st)) != 0) {
+ return false;
+ }
+ int old_fd = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(open(old_path,
+ O_RDONLY | O_CLOEXEC));
+ if (old_fd < 0) {
+ return false;
+ }
+ int new_fd = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
+ open(new_path, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, st.st_mode));
+ if (new_fd < 0) {
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(old_fd));
+ return false;
+ }
+ off_t offset = 0;
+ int result = 1;
+ while (result > 0) {
+ // Loop to ensure we copy everything, and not only up to 2GB.
+ result = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
+ sendfile(new_fd, old_fd, &offset, kMaxUint32));
+ }
+ // From sendfile man pages:
+ // Applications may wish to fall back to read(2)/write(2) in the case
+ // where sendfile() fails with EINVAL or ENOSYS.
+ if (result < 0 && (errno == EINVAL || errno == ENOSYS)) {
+ const intptr_t kBufferSize = 8 * KB;
+ uint8_t buffer[kBufferSize];
+ while ((result = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
+ read(old_fd, buffer, kBufferSize))) > 0) {
+ int wrote = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(write(new_fd, buffer,
+ result));
+ if (wrote != result) {
+ result = -1;
+ break;
+ }
+ }
+ }
+ if (result < 0) {
+ int e = errno;
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(old_fd));
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(new_fd));
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(unlink(new_path));
+ errno = e;
+ return false;
+ }
+ return true;
+ } else if (type == kIsDirectory) {
+ errno = EISDIR;
+ } else {
+ errno = ENOENT;
+ }
+ return false;
+}
+
+
off64_t File::LengthFromPath(const char* name) {
struct stat st;
- if (TEMP_FAILURE_RETRY(stat(name, &st)) == 0) {
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(stat(name, &st)) == 0) {
return st.st_size;
}
return -1;
@@ -230,7 +296,7 @@
void File::Stat(const char* name, int64_t* data) {
struct stat st;
- if (TEMP_FAILURE_RETRY(stat(name, &st)) == 0) {
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(stat(name, &st)) == 0) {
if (S_ISREG(st.st_mode)) {
data[kType] = kIsFile;
} else if (S_ISDIR(st.st_mode)) {
@@ -253,7 +319,7 @@
time_t File::LastModified(const char* name) {
struct stat st;
- if (TEMP_FAILURE_RETRY(stat(name, &st)) == 0) {
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(stat(name, &st)) == 0) {
return st.st_mtime;
}
return -1;
@@ -335,9 +401,11 @@
struct stat entry_info;
int stat_success;
if (follow_links) {
- stat_success = TEMP_FAILURE_RETRY(stat(pathname, &entry_info));
+ stat_success = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(stat(pathname,
+ &entry_info));
} else {
- stat_success = TEMP_FAILURE_RETRY(lstat(pathname, &entry_info));
+ stat_success = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(lstat(pathname,
+ &entry_info));
}
if (stat_success == -1) return File::kDoesNotExist;
if (S_ISDIR(entry_info.st_mode)) return File::kIsDirectory;
@@ -350,8 +418,8 @@
File::Identical File::AreIdentical(const char* file_1, const char* file_2) {
struct stat file_1_info;
struct stat file_2_info;
- if (TEMP_FAILURE_RETRY(lstat(file_1, &file_1_info)) == -1 ||
- TEMP_FAILURE_RETRY(lstat(file_2, &file_2_info)) == -1) {
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(lstat(file_1, &file_1_info)) == -1 ||
+ TEMP_FAILURE_RETRY_BLOCK_SIGNALS(lstat(file_2, &file_2_info)) == -1) {
return File::kError;
}
return (file_1_info.st_ino == file_2_info.st_ino &&
diff --git a/runtime/bin/file_linux.cc b/runtime/bin/file_linux.cc
index f5db4e5..b4c2b31 100644
--- a/runtime/bin/file_linux.cc
+++ b/runtime/bin/file_linux.cc
@@ -11,11 +11,13 @@
#include <fcntl.h> // NOLINT
#include <sys/stat.h> // NOLINT
#include <sys/types.h> // NOLINT
+#include <sys/sendfile.h> // NOLINT
#include <unistd.h> // NOLINT
#include <libgen.h> // NOLINT
#include "bin/builtin.h"
#include "bin/log.h"
+#include "bin/signal_blocker.h"
namespace dart {
@@ -46,7 +48,7 @@
void File::Close() {
ASSERT(handle_->fd() >= 0);
- int err = TEMP_FAILURE_RETRY(close(handle_->fd()));
+ int err = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(handle_->fd()));
if (err != 0) {
const int kBufferSize = 1024;
char error_buf[kBufferSize];
@@ -63,13 +65,15 @@
int64_t File::Read(void* buffer, int64_t num_bytes) {
ASSERT(handle_->fd() >= 0);
- return TEMP_FAILURE_RETRY(read(handle_->fd(), buffer, num_bytes));
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(read(handle_->fd(), buffer,
+ num_bytes));
}
int64_t File::Write(const void* buffer, int64_t num_bytes) {
ASSERT(handle_->fd() >= 0);
- return TEMP_FAILURE_RETRY(write(handle_->fd(), buffer, num_bytes));
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(write(handle_->fd(), buffer,
+ num_bytes));
}
@@ -87,20 +91,21 @@
bool File::Truncate(off64_t length) {
ASSERT(handle_->fd() >= 0);
- return TEMP_FAILURE_RETRY(ftruncate64(handle_->fd(), length) != -1);
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
+ ftruncate64(handle_->fd(), length) != -1);
}
bool File::Flush() {
ASSERT(handle_->fd() >= 0);
- return TEMP_FAILURE_RETRY(fsync(handle_->fd()) != -1);
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(fsync(handle_->fd()) != -1);
}
off64_t File::Length() {
ASSERT(handle_->fd() >= 0);
struct stat64 st;
- if (TEMP_FAILURE_RETRY(fstat64(handle_->fd(), &st)) == 0) {
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(fstat64(handle_->fd(), &st)) == 0) {
return st.st_size;
}
return -1;
@@ -110,7 +115,7 @@
File* File::Open(const char* name, FileOpenMode mode) {
// Report errors for non-regular files.
struct stat64 st;
- if (TEMP_FAILURE_RETRY(stat64(name, &st)) == 0) {
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(stat64(name, &st)) == 0) {
// Only accept regular files and character devices.
if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode)) {
errno = (S_ISDIR(st.st_mode)) ? EISDIR : ENOENT;
@@ -125,7 +130,7 @@
flags = flags | O_TRUNC;
}
flags |= O_CLOEXEC;
- int fd = TEMP_FAILURE_RETRY(open64(name, flags, 0666));
+ int fd = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(open64(name, flags, 0666));
if (fd < 0) {
return NULL;
}
@@ -147,7 +152,7 @@
bool File::Exists(const char* name) {
struct stat64 st;
- if (TEMP_FAILURE_RETRY(stat64(name, &st)) == 0) {
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(stat64(name, &st)) == 0) {
return S_ISREG(st.st_mode);
} else {
return false;
@@ -156,7 +161,7 @@
bool File::Create(const char* name) {
- int fd = TEMP_FAILURE_RETRY(
+ int fd = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
open64(name, O_RDONLY | O_CREAT | O_CLOEXEC, 0666));
if (fd < 0) {
return false;
@@ -166,7 +171,7 @@
bool File::CreateLink(const char* name, const char* target) {
- int status = TEMP_FAILURE_RETRY(symlink(target, name));
+ int status = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(symlink(target, name));
return (status == 0);
}
@@ -174,7 +179,7 @@
bool File::Delete(const char* name) {
File::Type type = File::GetType(name, true);
if (type == kIsFile) {
- return TEMP_FAILURE_RETRY(unlink(name)) == 0;
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(unlink(name)) == 0;
} else if (type == kIsDirectory) {
errno = EISDIR;
} else {
@@ -187,7 +192,7 @@
bool File::DeleteLink(const char* name) {
File::Type type = File::GetType(name, false);
if (type == kIsLink) {
- return TEMP_FAILURE_RETRY(unlink(name)) == 0;
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(unlink(name)) == 0;
}
errno = EINVAL;
return false;
@@ -197,7 +202,7 @@
bool File::Rename(const char* old_path, const char* new_path) {
File::Type type = File::GetType(old_path, true);
if (type == kIsFile) {
- return TEMP_FAILURE_RETRY(rename(old_path, new_path)) == 0;
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(rename(old_path, new_path)) == 0;
} else if (type == kIsDirectory) {
errno = EISDIR;
} else {
@@ -210,7 +215,7 @@
bool File::RenameLink(const char* old_path, const char* new_path) {
File::Type type = File::GetType(old_path, false);
if (type == kIsLink) {
- return TEMP_FAILURE_RETRY(rename(old_path, new_path)) == 0;
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(rename(old_path, new_path)) == 0;
} else if (type == kIsDirectory) {
errno = EISDIR;
} else {
@@ -220,9 +225,68 @@
}
+bool File::Copy(const char* old_path, const char* new_path) {
+ File::Type type = File::GetType(old_path, true);
+ if (type == kIsFile) {
+ struct stat64 st;
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(stat64(old_path, &st)) != 0) {
+ return false;
+ }
+ int old_fd = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(open64(old_path,
+ O_RDONLY | O_CLOEXEC));
+ if (old_fd < 0) {
+ return false;
+ }
+ int new_fd = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
+ open64(new_path, O_WRONLY | O_TRUNC | O_CREAT | O_CLOEXEC, st.st_mode));
+ if (new_fd < 0) {
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(old_fd));
+ return false;
+ }
+ off64_t offset = 0;
+ int result = 1;
+ while (result > 0) {
+ // Loop to ensure we copy everything, and not only up to 2GB.
+ result = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
+ sendfile64(new_fd, old_fd, &offset, kMaxUint32));
+ }
+ // From sendfile man pages:
+ // Applications may wish to fall back to read(2)/write(2) in the case
+ // where sendfile() fails with EINVAL or ENOSYS.
+ if (result < 0 && (errno == EINVAL || errno == ENOSYS)) {
+ const intptr_t kBufferSize = 8 * KB;
+ uint8_t buffer[kBufferSize];
+ while ((result = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
+ read(old_fd, buffer, kBufferSize))) > 0) {
+ int wrote = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(write(new_fd, buffer,
+ result));
+ if (wrote != result) {
+ result = -1;
+ break;
+ }
+ }
+ }
+ if (result < 0) {
+ int e = errno;
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(old_fd));
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(new_fd));
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(unlink(new_path));
+ errno = e;
+ return false;
+ }
+ return true;
+ } else if (type == kIsDirectory) {
+ errno = EISDIR;
+ } else {
+ errno = ENOENT;
+ }
+ return false;
+}
+
+
off64_t File::LengthFromPath(const char* name) {
struct stat64 st;
- if (TEMP_FAILURE_RETRY(stat64(name, &st)) == 0) {
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(stat64(name, &st)) == 0) {
return st.st_size;
}
return -1;
@@ -231,7 +295,7 @@
void File::Stat(const char* name, int64_t* data) {
struct stat64 st;
- if (TEMP_FAILURE_RETRY(stat64(name, &st)) == 0) {
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(stat64(name, &st)) == 0) {
if (S_ISREG(st.st_mode)) {
data[kType] = kIsFile;
} else if (S_ISDIR(st.st_mode)) {
@@ -254,7 +318,7 @@
time_t File::LastModified(const char* name) {
struct stat64 st;
- if (TEMP_FAILURE_RETRY(stat64(name, &st)) == 0) {
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(stat64(name, &st)) == 0) {
return st.st_mtime;
}
return -1;
@@ -329,9 +393,11 @@
struct stat64 entry_info;
int stat_success;
if (follow_links) {
- stat_success = TEMP_FAILURE_RETRY(stat64(pathname, &entry_info));
+ stat_success = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(stat64(pathname,
+ &entry_info));
} else {
- stat_success = TEMP_FAILURE_RETRY(lstat64(pathname, &entry_info));
+ stat_success = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(lstat64(pathname,
+ &entry_info));
}
if (stat_success == -1) return File::kDoesNotExist;
if (S_ISDIR(entry_info.st_mode)) return File::kIsDirectory;
@@ -344,8 +410,8 @@
File::Identical File::AreIdentical(const char* file_1, const char* file_2) {
struct stat64 file_1_info;
struct stat64 file_2_info;
- if (TEMP_FAILURE_RETRY(lstat64(file_1, &file_1_info)) == -1 ||
- TEMP_FAILURE_RETRY(lstat64(file_2, &file_2_info)) == -1) {
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(lstat64(file_1, &file_1_info)) == -1 ||
+ TEMP_FAILURE_RETRY_BLOCK_SIGNALS(lstat64(file_2, &file_2_info)) == -1) {
return File::kError;
}
return (file_1_info.st_ino == file_2_info.st_ino &&
diff --git a/runtime/bin/file_macos.cc b/runtime/bin/file_macos.cc
index 46c77cb..d750af8 100644
--- a/runtime/bin/file_macos.cc
+++ b/runtime/bin/file_macos.cc
@@ -9,6 +9,7 @@
#include <errno.h> // NOLINT
#include <fcntl.h> // NOLINT
+#include <copyfile.h> // NOLINT
#include <sys/stat.h> // NOLINT
#include <unistd.h> // NOLINT
#include <libgen.h> // NOLINT
@@ -17,7 +18,7 @@
#include "bin/builtin.h"
#include "bin/fdutils.h"
#include "bin/log.h"
-
+#include "bin/signal_blocker.h"
namespace dart {
namespace bin {
@@ -47,7 +48,7 @@
void File::Close() {
ASSERT(handle_->fd() >= 0);
- int err = TEMP_FAILURE_RETRY(close(handle_->fd()));
+ int err = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(handle_->fd()));
if (err != 0) {
const int kBufferSize = 1024;
char error_message[kBufferSize];
@@ -65,13 +66,15 @@
int64_t File::Read(void* buffer, int64_t num_bytes) {
ASSERT(handle_->fd() >= 0);
- return TEMP_FAILURE_RETRY(read(handle_->fd(), buffer, num_bytes));
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(read(handle_->fd(), buffer,
+ num_bytes));
}
int64_t File::Write(const void* buffer, int64_t num_bytes) {
ASSERT(handle_->fd() >= 0);
- return TEMP_FAILURE_RETRY(write(handle_->fd(), buffer, num_bytes));
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(write(handle_->fd(), buffer,
+ num_bytes));
}
@@ -89,20 +92,21 @@
bool File::Truncate(off64_t length) {
ASSERT(handle_->fd() >= 0);
- return TEMP_FAILURE_RETRY(ftruncate(handle_->fd(), length) != -1);
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
+ ftruncate(handle_->fd(), length) != -1);
}
bool File::Flush() {
ASSERT(handle_->fd() >= 0);
- return TEMP_FAILURE_RETRY(fsync(handle_->fd()) != -1);
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(fsync(handle_->fd()) != -1);
}
off64_t File::Length() {
ASSERT(handle_->fd() >= 0);
struct stat st;
- if (TEMP_FAILURE_RETRY(fstat(handle_->fd(), &st)) == 0) {
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(fstat(handle_->fd(), &st)) == 0) {
return st.st_size;
}
return -1;
@@ -112,7 +116,7 @@
File* File::Open(const char* name, FileOpenMode mode) {
// Report errors for non-regular files.
struct stat st;
- if (TEMP_FAILURE_RETRY(stat(name, &st)) == 0) {
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(stat(name, &st)) == 0) {
// Only accept regular files and character devices.
if (!S_ISREG(st.st_mode) && !S_ISCHR(st.st_mode)) {
errno = (S_ISDIR(st.st_mode)) ? EISDIR : ENOENT;
@@ -126,7 +130,7 @@
if ((mode & kTruncate) != 0) {
flags = flags | O_TRUNC;
}
- int fd = TEMP_FAILURE_RETRY(open(name, flags, 0666));
+ int fd = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(open(name, flags, 0666));
if (fd < 0) {
return NULL;
}
@@ -149,7 +153,7 @@
bool File::Exists(const char* name) {
struct stat st;
- if (TEMP_FAILURE_RETRY(stat(name, &st)) == 0) {
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(stat(name, &st)) == 0) {
return S_ISREG(st.st_mode);
} else {
return false;
@@ -158,7 +162,8 @@
bool File::Create(const char* name) {
- int fd = TEMP_FAILURE_RETRY(open(name, O_RDONLY | O_CREAT, 0666));
+ int fd = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(open(name, O_RDONLY | O_CREAT,
+ 0666));
if (fd < 0) {
return false;
}
@@ -167,7 +172,7 @@
bool File::CreateLink(const char* name, const char* target) {
- int status = TEMP_FAILURE_RETRY(symlink(target, name));
+ int status = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(symlink(target, name));
return (status == 0);
}
@@ -175,7 +180,7 @@
bool File::Delete(const char* name) {
File::Type type = File::GetType(name, true);
if (type == kIsFile) {
- return TEMP_FAILURE_RETRY(unlink(name)) == 0;
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(unlink(name)) == 0;
} else if (type == kIsDirectory) {
errno = EISDIR;
} else {
@@ -188,7 +193,7 @@
bool File::DeleteLink(const char* name) {
File::Type type = File::GetType(name, false);
if (type == kIsLink) {
- return TEMP_FAILURE_RETRY(unlink(name)) == 0;
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(unlink(name)) == 0;
}
errno = EINVAL;
return false;
@@ -198,7 +203,7 @@
bool File::Rename(const char* old_path, const char* new_path) {
File::Type type = File::GetType(old_path, true);
if (type == kIsFile) {
- return TEMP_FAILURE_RETRY(rename(old_path, new_path)) == 0;
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(rename(old_path, new_path)) == 0;
} else if (type == kIsDirectory) {
errno = EISDIR;
} else {
@@ -211,7 +216,7 @@
bool File::RenameLink(const char* old_path, const char* new_path) {
File::Type type = File::GetType(old_path, false);
if (type == kIsLink) {
- return TEMP_FAILURE_RETRY(rename(old_path, new_path)) == 0;
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(rename(old_path, new_path)) == 0;
} else if (type == kIsDirectory) {
errno = EISDIR;
} else {
@@ -221,9 +226,22 @@
}
+bool File::Copy(const char* old_path, const char* new_path) {
+ File::Type type = File::GetType(old_path, true);
+ if (type == kIsFile) {
+ return copyfile(old_path, new_path, NULL, COPYFILE_ALL) == 0;
+ } else if (type == kIsDirectory) {
+ errno = EISDIR;
+ } else {
+ errno = ENOENT;
+ }
+ return false;
+}
+
+
off64_t File::LengthFromPath(const char* name) {
struct stat st;
- if (TEMP_FAILURE_RETRY(stat(name, &st)) == 0) {
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(stat(name, &st)) == 0) {
return st.st_size;
}
return -1;
@@ -232,7 +250,7 @@
void File::Stat(const char* name, int64_t* data) {
struct stat st;
- if (TEMP_FAILURE_RETRY(stat(name, &st)) == 0) {
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(stat(name, &st)) == 0) {
if (S_ISREG(st.st_mode)) {
data[kType] = kIsFile;
} else if (S_ISDIR(st.st_mode)) {
@@ -255,7 +273,7 @@
time_t File::LastModified(const char* name) {
struct stat st;
- if (TEMP_FAILURE_RETRY(stat(name, &st)) == 0) {
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(stat(name, &st)) == 0) {
return st.st_mtime;
}
return -1;
@@ -336,9 +354,11 @@
struct stat entry_info;
int stat_success;
if (follow_links) {
- stat_success = TEMP_FAILURE_RETRY(stat(pathname, &entry_info));
+ stat_success = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(stat(pathname,
+ &entry_info));
} else {
- stat_success = TEMP_FAILURE_RETRY(lstat(pathname, &entry_info));
+ stat_success = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(lstat(pathname,
+ &entry_info));
}
if (stat_success == -1) return File::kDoesNotExist;
if (S_ISDIR(entry_info.st_mode)) return File::kIsDirectory;
@@ -351,8 +371,8 @@
File::Identical File::AreIdentical(const char* file_1, const char* file_2) {
struct stat file_1_info;
struct stat file_2_info;
- if (TEMP_FAILURE_RETRY(lstat(file_1, &file_1_info)) == -1 ||
- TEMP_FAILURE_RETRY(lstat(file_2, &file_2_info)) == -1) {
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(lstat(file_1, &file_1_info)) == -1 ||
+ TEMP_FAILURE_RETRY_BLOCK_SIGNALS(lstat(file_2, &file_2_info)) == -1) {
return File::kError;
}
return (file_1_info.st_ino == file_2_info.st_ino &&
diff --git a/runtime/bin/file_patch.dart b/runtime/bin/file_patch.dart
index 68612a5..4ded719 100644
--- a/runtime/bin/file_patch.dart
+++ b/runtime/bin/file_patch.dart
@@ -14,6 +14,7 @@
native "File_Rename";
/* patch */ static _renameLink(String oldPath, String newPath)
native "File_RenameLink";
+ /* patch */ static _copy(String oldPath, String newPath) native "File_Copy";
/* patch */ static _lengthFromPath(String path) native "File_LengthFromPath";
/* patch */ static _lastModified(String path) native "File_LastModified";
/* patch */ static _open(String path, int mode) native "File_Open";
diff --git a/runtime/bin/file_win.cc b/runtime/bin/file_win.cc
index 4c3c853..1be41cb 100644
--- a/runtime/bin/file_win.cc
+++ b/runtime/bin/file_win.cc
@@ -322,6 +322,27 @@
}
+bool File::Copy(const char* old_path, const char* new_path) {
+ File::Type type = GetType(old_path, false);
+ if (type == kIsFile) {
+ const wchar_t* system_old_path = StringUtils::Utf8ToWide(old_path);
+ const wchar_t* system_new_path = StringUtils::Utf8ToWide(new_path);
+ bool success = CopyFileExW(system_old_path,
+ system_new_path,
+ NULL,
+ NULL,
+ NULL,
+ 0) != 0;
+ free(const_cast<wchar_t*>(system_old_path));
+ free(const_cast<wchar_t*>(system_new_path));
+ return success;
+ } else {
+ SetLastError(ERROR_FILE_NOT_FOUND);
+ }
+ return false;
+}
+
+
off64_t File::LengthFromPath(const char* name) {
struct __stat64 st;
const wchar_t* system_name = StringUtils::Utf8ToWide(name);
diff --git a/runtime/bin/io_impl_sources.gypi b/runtime/bin/io_impl_sources.gypi
index d026609..a720c7f 100644
--- a/runtime/bin/io_impl_sources.gypi
+++ b/runtime/bin/io_impl_sources.gypi
@@ -50,12 +50,12 @@
'socket_linux.cc',
'socket_macos.cc',
'socket_win.cc',
- 'stdin.cc',
- 'stdin.h',
- 'stdin_android.cc',
- 'stdin_linux.cc',
- 'stdin_macos.cc',
- 'stdin_win.cc',
+ 'stdio.cc',
+ 'stdio.h',
+ 'stdio_android.cc',
+ 'stdio_linux.cc',
+ 'stdio_macos.cc',
+ 'stdio_win.cc',
],
'conditions': [
['dart_io_support==1', {
diff --git a/runtime/bin/io_natives.cc b/runtime/bin/io_natives.cc
index 480ce68..6a860b7 100644
--- a/runtime/bin/io_natives.cc
+++ b/runtime/bin/io_natives.cc
@@ -27,8 +27,7 @@
V(Filter_End, 1) \
V(Filter_Process, 4) \
V(Filter_Processed, 3) \
- V(InternetAddress_Fixed, 1) \
- V(InternetAddress_Parse, 2) \
+ V(InternetAddress_Parse, 1) \
V(IOService_NewServicePort, 0) \
V(Platform_NumberOfProcessors, 0) \
V(Platform_OperatingSystem, 0) \
@@ -46,6 +45,8 @@
V(Process_Exit, 1) \
V(Process_Sleep, 1) \
V(Process_Pid, 1) \
+ V(Process_SetSignalHandler, 1) \
+ V(Process_ClearSignalHandler, 1) \
V(SecureSocket_Connect, 9) \
V(SecureSocket_Destroy, 1) \
V(SecureSocket_Handshake, 1) \
@@ -80,6 +81,7 @@
V(Stdin_SetEchoMode, 1) \
V(Stdin_GetLineMode, 0) \
V(Stdin_SetLineMode, 1) \
+ V(Stdout_GetTerminalSize, 0) \
V(StringToSystemEncoding, 1) \
V(SystemEncodingToString, 1)
@@ -96,11 +98,14 @@
Dart_NativeFunction IONativeLookup(Dart_Handle name,
- int argument_count) {
+ int argument_count,
+ bool* auto_setup_scope) {
const char* function_name = NULL;
Dart_Handle result = Dart_StringToCString(name, &function_name);
DART_CHECK_VALID(result);
ASSERT(function_name != NULL);
+ ASSERT(auto_setup_scope != NULL);
+ *auto_setup_scope = true;
int num_entries = sizeof(IOEntries) / sizeof(struct NativeEntries);
for (int i = 0; i < num_entries; i++) {
struct NativeEntries* entry = &(IOEntries[i]);
diff --git a/runtime/bin/io_natives.h b/runtime/bin/io_natives.h
index dac7fce..7039234 100644
--- a/runtime/bin/io_natives.h
+++ b/runtime/bin/io_natives.h
@@ -12,7 +12,8 @@
namespace bin {
Dart_NativeFunction IONativeLookup(Dart_Handle name,
- int argument_count);
+ int argument_count,
+ bool* auto_setup_scope);
} // namespace bin
} // namespace dart
diff --git a/runtime/bin/io_service.h b/runtime/bin/io_service.h
index d9e8c45..af829eb 100644
--- a/runtime/bin/io_service.h
+++ b/runtime/bin/io_service.h
@@ -18,40 +18,41 @@
V(File, Create, 1) \
V(File, Delete, 2) \
V(File, Rename, 3) \
- V(File, Open, 4) \
- V(File, ResolveSymbolicLinks, 5) \
- V(File, Close, 6) \
- V(File, Position, 7) \
- V(File, SetPosition, 8) \
- V(File, Truncate, 9) \
- V(File, Length, 10) \
- V(File, LengthFromPath, 11) \
- V(File, LastModified, 12) \
- V(File, Flush, 13) \
- V(File, ReadByte, 14) \
- V(File, WriteByte, 15) \
- V(File, Read, 16) \
- V(File, ReadInto, 17) \
- V(File, WriteFrom, 18) \
- V(File, CreateLink, 19) \
- V(File, DeleteLink, 20) \
- V(File, RenameLink, 21) \
- V(File, LinkTarget, 22) \
- V(File, Type, 23) \
- V(File, Identical, 24) \
- V(File, Stat, 25) \
- V(Socket, Lookup, 26) \
- V(Socket, ListInterfaces, 27) \
- V(Socket, ReverseLookup, 28) \
- V(Directory, Create, 29) \
- V(Directory, Delete, 30) \
- V(Directory, Exists, 31) \
- V(Directory, CreateTemp, 32) \
- V(Directory, ListStart, 33) \
- V(Directory, ListNext, 34) \
- V(Directory, ListStop, 35) \
- V(Directory, Rename, 36) \
- V(SSLFilter, ProcessFilter, 37)
+ V(File, Copy, 4) \
+ V(File, Open, 5) \
+ V(File, ResolveSymbolicLinks, 6) \
+ V(File, Close, 7) \
+ V(File, Position, 8) \
+ V(File, SetPosition, 9) \
+ V(File, Truncate, 10) \
+ V(File, Length, 11) \
+ V(File, LengthFromPath, 12) \
+ V(File, LastModified, 13) \
+ V(File, Flush, 14) \
+ V(File, ReadByte, 15) \
+ V(File, WriteByte, 16) \
+ V(File, Read, 17) \
+ V(File, ReadInto, 18) \
+ V(File, WriteFrom, 19) \
+ V(File, CreateLink, 20) \
+ V(File, DeleteLink, 21) \
+ V(File, RenameLink, 22) \
+ V(File, LinkTarget, 23) \
+ V(File, Type, 24) \
+ V(File, Identical, 25) \
+ V(File, Stat, 26) \
+ V(Socket, Lookup, 27) \
+ V(Socket, ListInterfaces, 28) \
+ V(Socket, ReverseLookup, 29) \
+ V(Directory, Create, 30) \
+ V(Directory, Delete, 31) \
+ V(Directory, Exists, 32) \
+ V(Directory, CreateTemp, 33) \
+ V(Directory, ListStart, 34) \
+ V(Directory, ListNext, 35) \
+ V(Directory, ListStop, 36) \
+ V(Directory, Rename, 37) \
+ V(SSLFilter, ProcessFilter, 38)
#define DECLARE_REQUEST(type, method, id) \
k##type##method##Request = id,
diff --git a/runtime/bin/process.cc b/runtime/bin/process.cc
index d7dd894..ebafedd 100644
--- a/runtime/bin/process.cc
+++ b/runtime/bin/process.cc
@@ -10,7 +10,6 @@
#include "include/dart_api.h"
-
namespace dart {
namespace bin {
@@ -208,7 +207,8 @@
int64_t status = 0;
// Ignore result if passing invalid argument and just exit 0.
DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 0), &status);
- // Be sure to do platform-specific cleanups.
+ Dart_ExitIsolate();
+ Dart_Cleanup();
Platform::Cleanup();
exit(static_cast<int>(status));
}
@@ -243,6 +243,23 @@
}
+void FUNCTION_NAME(Process_SetSignalHandler)(Dart_NativeArguments args) {
+ intptr_t signal = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 0));
+ intptr_t id = Process::SetSignalHandler(signal);
+ if (id == -1) {
+ Dart_SetReturnValue(args, DartUtils::NewDartOSError());
+ } else {
+ Dart_SetReturnValue(args, Dart_NewInteger(id));
+ }
+}
+
+
+void FUNCTION_NAME(Process_ClearSignalHandler)(Dart_NativeArguments args) {
+ intptr_t signal = DartUtils::GetIntptrValue(Dart_GetNativeArgument(args, 0));
+ Process::ClearSignalHandler(signal);
+}
+
+
Dart_Handle Process::GetProcessIdNativeField(Dart_Handle process,
intptr_t* pid) {
return Dart_GetNativeInstanceField(process, kProcessIdNativeField, pid);
diff --git a/runtime/bin/process.h b/runtime/bin/process.h
index 02a9ecc..adda36a 100644
--- a/runtime/bin/process.h
+++ b/runtime/bin/process.h
@@ -41,6 +41,41 @@
};
+// To be kept in sync with ProcessSignal consts in sdk/lib/io/process.dart
+// Note that this map is as on Linux.
+enum ProcessSignals {
+ kSighup = 1,
+ kSigint = 2,
+ kSigquit = 3,
+ kSigill = 4,
+ kSigtrap = 5,
+ kSigabrt = 6,
+ kSigbus = 7,
+ kSigfpe = 8,
+ kSigkill = 9,
+ kSigusr1 = 10,
+ kSigsegv = 11,
+ kSigusr2 = 12,
+ kSigpipe = 13,
+ kSigalrm = 14,
+ kSigterm = 15,
+ kSigchld = 17,
+ kSigcont = 18,
+ kSigstop = 19,
+ kSigtstp = 20,
+ kSigttin = 21,
+ kSigttou = 22,
+ kSigurg = 23,
+ kSigxcpu = 24,
+ kSigxfsz = 25,
+ kSigvtalrm = 26,
+ kSigprof = 27,
+ kSigwinch = 28,
+ kSigpoll = 29,
+ kSigsys = 31
+};
+
+
class Process {
public:
// Start a new process providing access to stdin, stdout, stderr and
@@ -84,6 +119,9 @@
static intptr_t CurrentProcessId();
+ static intptr_t SetSignalHandler(intptr_t signal);
+ static void ClearSignalHandler(intptr_t signal);
+
static Dart_Handle GetProcessIdNativeField(Dart_Handle process,
intptr_t* pid);
static Dart_Handle SetProcessIdNativeField(Dart_Handle process,
@@ -98,6 +136,46 @@
};
+class SignalInfo {
+ public:
+ SignalInfo(int fd, int signal, SignalInfo* prev = NULL)
+ : fd_(fd),
+ signal_(signal),
+ // SignalInfo is expected to be created when in a isolate.
+ port_(Dart_GetMainPortId()),
+ next_(NULL),
+ prev_(prev) {
+ if (prev_ != NULL) {
+ prev_->next_ = this;
+ }
+ }
+
+ ~SignalInfo();
+
+ void Unlink() {
+ if (prev_ != NULL) {
+ prev_->next_ = next_;
+ }
+ if (next_ != NULL) {
+ next_->prev_ = prev_;
+ }
+ }
+
+ int fd() const { return fd_; }
+ int signal() const { return signal_; }
+ Dart_Port port() const { return port_; }
+ SignalInfo* next() const { return next_; }
+
+ private:
+ int fd_;
+ int signal_;
+ // The port_ is used to identify what isolate the signal-info belongs to.
+ Dart_Port port_;
+ SignalInfo* next_;
+ SignalInfo* prev_;
+};
+
+
// Utility class for collecting the output when running a process
// synchronously by using Process::Wait. This class is sub-classed in
// the platform specific files to implement reading into the buffers
diff --git a/runtime/bin/process_android.cc b/runtime/bin/process_android.cc
index 378b9ba..2567cbe 100644
--- a/runtime/bin/process_android.cc
+++ b/runtime/bin/process_android.cc
@@ -18,6 +18,7 @@
#include "bin/fdutils.h"
#include "bin/log.h"
+#include "bin/signal_blocker.h"
#include "bin/thread.h"
@@ -631,6 +632,115 @@
return static_cast<intptr_t>(getpid());
}
+
+static Mutex* signal_mutex = new Mutex();
+static SignalInfo* signal_handlers = NULL;
+static const int kSignalsCount = 5;
+static const int kSignals[kSignalsCount] = {
+ SIGINT,
+ SIGWINCH,
+ SIGTERM,
+ SIGUSR1,
+ SIGUSR2
+};
+
+
+SignalInfo::~SignalInfo() {
+ VOID_TEMP_FAILURE_RETRY(close(fd_));
+}
+
+
+static void SignalHandler(int signal) {
+ MutexLocker lock(signal_mutex);
+ const SignalInfo* handler = signal_handlers;
+ while (handler != NULL) {
+ if (handler->signal() == signal) {
+ int value = 0;
+ VOID_TEMP_FAILURE_RETRY(write(handler->fd(), &value, 1));
+ }
+ handler = handler->next();
+ }
+}
+
+
+intptr_t Process::SetSignalHandler(intptr_t signal) {
+ bool found = false;
+ for (int i = 0; i < kSignalsCount; i++) {
+ if (kSignals[i] == signal) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) return -1;
+ int fds[2];
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(pipe(fds)) != 0) {
+ return -1;
+ }
+ if (!FDUtils::SetNonBlocking(fds[0])) {
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fds[0]));
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fds[1]));
+ return -1;
+ }
+ ThreadSignalBlocker blocker(kSignalsCount, kSignals);
+ MutexLocker lock(signal_mutex);
+ SignalInfo* handler = signal_handlers;
+ bool listen = true;
+ while (handler != NULL) {
+ if (handler->signal() == signal) {
+ listen = false;
+ break;
+ }
+ handler = handler->next();
+ }
+ if (listen) {
+ struct sigaction act;
+ bzero(&act, sizeof(act));
+ act.sa_handler = SignalHandler;
+ int status = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
+ sigaction(signal, &act, NULL));
+ if (status < 0) {
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fds[0]));
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fds[1]));
+ return -1;
+ }
+ }
+ if (signal_handlers == NULL) {
+ signal_handlers = new SignalInfo(fds[1], signal);
+ } else {
+ new SignalInfo(fds[1], signal, signal_handlers);
+ }
+ return fds[0];
+}
+
+
+void Process::ClearSignalHandler(intptr_t signal) {
+ ThreadSignalBlocker blocker(kSignalsCount, kSignals);
+ MutexLocker lock(signal_mutex);
+ SignalInfo* handler = signal_handlers;
+ bool unlisten = true;
+ while (handler != NULL) {
+ bool remove = false;
+ if (handler->signal() == signal) {
+ if (handler->port() == Dart_GetMainPortId()) {
+ if (signal_handlers == handler) signal_handlers = handler->next();
+ handler->Unlink();
+ remove = true;
+ } else {
+ unlisten = false;
+ }
+ }
+ SignalInfo* next = handler->next();
+ if (remove) delete handler;
+ handler = next;
+ }
+ if (unlisten) {
+ struct sigaction act;
+ bzero(&act, sizeof(act));
+ act.sa_handler = SIG_DFL;
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(sigaction(signal, &act, NULL));
+ }
+}
+
} // namespace bin
} // namespace dart
diff --git a/runtime/bin/process_linux.cc b/runtime/bin/process_linux.cc
index 95d11cd..7479064 100644
--- a/runtime/bin/process_linux.cc
+++ b/runtime/bin/process_linux.cc
@@ -18,6 +18,7 @@
#include "bin/fdutils.h"
#include "bin/log.h"
+#include "bin/signal_blocker.h"
#include "bin/thread.h"
@@ -630,6 +631,115 @@
return static_cast<intptr_t>(getpid());
}
+
+static Mutex* signal_mutex = new Mutex();
+static SignalInfo* signal_handlers = NULL;
+static const int kSignalsCount = 5;
+static const int kSignals[kSignalsCount] = {
+ SIGINT,
+ SIGWINCH,
+ SIGTERM,
+ SIGUSR1,
+ SIGUSR2
+};
+
+
+SignalInfo::~SignalInfo() {
+ VOID_TEMP_FAILURE_RETRY(close(fd_));
+}
+
+
+static void SignalHandler(int signal) {
+ MutexLocker lock(signal_mutex);
+ const SignalInfo* handler = signal_handlers;
+ while (handler != NULL) {
+ if (handler->signal() == signal) {
+ int value = 0;
+ VOID_TEMP_FAILURE_RETRY(write(handler->fd(), &value, 1));
+ }
+ handler = handler->next();
+ }
+}
+
+
+intptr_t Process::SetSignalHandler(intptr_t signal) {
+ bool found = false;
+ for (int i = 0; i < kSignalsCount; i++) {
+ if (kSignals[i] == signal) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) return -1;
+ int fds[2];
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(pipe(fds)) != 0) {
+ return -1;
+ }
+ if (!FDUtils::SetNonBlocking(fds[0])) {
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fds[0]));
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fds[1]));
+ return -1;
+ }
+ ThreadSignalBlocker blocker(kSignalsCount, kSignals);
+ MutexLocker lock(signal_mutex);
+ SignalInfo* handler = signal_handlers;
+ bool listen = true;
+ while (handler != NULL) {
+ if (handler->signal() == signal) {
+ listen = false;
+ break;
+ }
+ handler = handler->next();
+ }
+ if (listen) {
+ struct sigaction act;
+ bzero(&act, sizeof(act));
+ act.sa_handler = SignalHandler;
+ int status = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
+ sigaction(signal, &act, NULL));
+ if (status < 0) {
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fds[0]));
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fds[1]));
+ return -1;
+ }
+ }
+ if (signal_handlers == NULL) {
+ signal_handlers = new SignalInfo(fds[1], signal);
+ } else {
+ new SignalInfo(fds[1], signal, signal_handlers);
+ }
+ return fds[0];
+}
+
+
+void Process::ClearSignalHandler(intptr_t signal) {
+ ThreadSignalBlocker blocker(kSignalsCount, kSignals);
+ MutexLocker lock(signal_mutex);
+ SignalInfo* handler = signal_handlers;
+ bool unlisten = true;
+ while (handler != NULL) {
+ bool remove = false;
+ if (handler->signal() == signal) {
+ if (handler->port() == Dart_GetMainPortId()) {
+ if (signal_handlers == handler) signal_handlers = handler->next();
+ handler->Unlink();
+ remove = true;
+ } else {
+ unlisten = false;
+ }
+ }
+ SignalInfo* next = handler->next();
+ if (remove) delete handler;
+ handler = next;
+ }
+ if (unlisten) {
+ struct sigaction act;
+ bzero(&act, sizeof(act));
+ act.sa_handler = SIG_DFL;
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(sigaction(signal, &act, NULL));
+ }
+}
+
} // namespace bin
} // namespace dart
diff --git a/runtime/bin/process_macos.cc b/runtime/bin/process_macos.cc
index edb222a..ae0f37e 100644
--- a/runtime/bin/process_macos.cc
+++ b/runtime/bin/process_macos.cc
@@ -18,6 +18,7 @@
#include "bin/fdutils.h"
#include "bin/log.h"
+#include "bin/signal_blocker.h"
#include "bin/thread.h"
extern char **environ;
@@ -622,8 +623,44 @@
}
+static int SignalMap(intptr_t id) {
+ switch (static_cast<ProcessSignals>(id)) {
+ case kSighup: return SIGHUP;
+ case kSigint: return SIGINT;
+ case kSigquit: return SIGQUIT;
+ case kSigill: return SIGILL;
+ case kSigtrap: return SIGTRAP;
+ case kSigabrt: return SIGABRT;
+ case kSigbus: return SIGBUS;
+ case kSigfpe: return SIGFPE;
+ case kSigkill: return SIGKILL;
+ case kSigusr1: return SIGUSR1;
+ case kSigsegv: return SIGSEGV;
+ case kSigusr2: return SIGUSR2;
+ case kSigpipe: return SIGPIPE;
+ case kSigalrm: return SIGALRM;
+ case kSigterm: return SIGTERM;
+ case kSigchld: return SIGCHLD;
+ case kSigcont: return SIGCONT;
+ case kSigstop: return SIGSTOP;
+ case kSigtstp: return SIGTSTP;
+ case kSigttin: return SIGTTIN;
+ case kSigttou: return SIGTTOU;
+ case kSigurg: return SIGURG;
+ case kSigxcpu: return SIGXCPU;
+ case kSigxfsz: return SIGXFSZ;
+ case kSigvtalrm: return SIGVTALRM;
+ case kSigprof: return SIGPROF;
+ case kSigwinch: return SIGWINCH;
+ case kSigpoll: return -1;
+ case kSigsys: return SIGSYS;
+ }
+ return -1;
+}
+
+
bool Process::Kill(intptr_t id, int signal) {
- return (TEMP_FAILURE_RETRY(kill(id, signal)) != -1);
+ return (TEMP_FAILURE_RETRY(kill(id, SignalMap(signal))) != -1);
}
@@ -636,6 +673,119 @@
return static_cast<intptr_t>(getpid());
}
+
+static Mutex* signal_mutex = new Mutex();
+static SignalInfo* signal_handlers = NULL;
+static const int kSignalsCount = 5;
+static const int kSignals[kSignalsCount] = {
+ SIGINT,
+ SIGWINCH,
+ SIGTERM,
+ SIGUSR1,
+ SIGUSR2
+};
+
+
+SignalInfo::~SignalInfo() {
+ VOID_TEMP_FAILURE_RETRY(close(fd_));
+}
+
+
+static void SignalHandler(int signal) {
+ MutexLocker lock(signal_mutex);
+ const SignalInfo* handler = signal_handlers;
+ while (handler != NULL) {
+ if (handler->signal() == signal) {
+ int value = 0;
+ VOID_TEMP_FAILURE_RETRY(write(handler->fd(), &value, 1));
+ }
+ handler = handler->next();
+ }
+}
+
+
+intptr_t Process::SetSignalHandler(intptr_t signal) {
+ signal = SignalMap(signal);
+ if (signal == -1) return -1;
+ bool found = false;
+ for (int i = 0; i < kSignalsCount; i++) {
+ if (kSignals[i] == signal) {
+ found = true;
+ break;
+ }
+ }
+ if (!found) return -1;
+ int fds[2];
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(pipe(fds)) != 0) {
+ return -1;
+ }
+ if (!FDUtils::SetNonBlocking(fds[0])) {
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fds[0]));
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fds[1]));
+ return -1;
+ }
+ ThreadSignalBlocker blocker(kSignalsCount, kSignals);
+ MutexLocker lock(signal_mutex);
+ SignalInfo* handler = signal_handlers;
+ bool listen = true;
+ while (handler != NULL) {
+ if (handler->signal() == signal) {
+ listen = false;
+ break;
+ }
+ handler = handler->next();
+ }
+ if (listen) {
+ struct sigaction act;
+ bzero(&act, sizeof(act));
+ act.sa_handler = SignalHandler;
+ int status = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
+ sigaction(signal, &act, NULL));
+ if (status < 0) {
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fds[0]));
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fds[1]));
+ return -1;
+ }
+ }
+ if (signal_handlers == NULL) {
+ signal_handlers = new SignalInfo(fds[1], signal);
+ } else {
+ new SignalInfo(fds[1], signal, signal_handlers);
+ }
+ return fds[0];
+}
+
+
+void Process::ClearSignalHandler(intptr_t signal) {
+ signal = SignalMap(signal);
+ if (signal == -1) return;
+ ThreadSignalBlocker blocker(kSignalsCount, kSignals);
+ MutexLocker lock(signal_mutex);
+ SignalInfo* handler = signal_handlers;
+ bool unlisten = true;
+ while (handler != NULL) {
+ bool remove = false;
+ if (handler->signal() == signal) {
+ if (handler->port() == Dart_GetMainPortId()) {
+ if (signal_handlers == handler) signal_handlers = handler->next();
+ handler->Unlink();
+ remove = true;
+ } else {
+ unlisten = false;
+ }
+ }
+ SignalInfo* next = handler->next();
+ if (remove) delete handler;
+ handler = next;
+ }
+ if (unlisten) {
+ struct sigaction act;
+ bzero(&act, sizeof(act));
+ act.sa_handler = SIG_DFL;
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(sigaction(signal, &act, NULL));
+ }
+}
+
} // namespace bin
} // namespace dart
diff --git a/runtime/bin/process_patch.dart b/runtime/bin/process_patch.dart
index e0e8fc6..b83ec1b 100644
--- a/runtime/bin/process_patch.dart
+++ b/runtime/bin/process_patch.dart
@@ -71,12 +71,77 @@
}
+List<_SignalController> _signalControllers = new List(32);
+
+
+class _SignalController {
+ final ProcessSignal signal;
+
+ StreamController _controller;
+ var _id;
+
+ _SignalController(this.signal) {
+ _controller = new StreamController.broadcast(
+ onListen: _listen,
+ onCancel: _cancel);
+ }
+
+ Stream<ProcessSignal> get stream => _controller.stream;
+
+ void _listen() {
+ var id = _setSignalHandler(signal._signalNumber);
+ if (id is! int) {
+ _controller.addError(
+ new SignalException("Failed to listen for $signal", id));
+ return;
+ }
+ _id = id;
+ var socket = new _RawSocket(new _NativeSocket.watch(id));
+ socket.listen((event) {
+ if (event == RawSocketEvent.READ) {
+ var bytes = socket.read();
+ for (int i = 0; i < bytes.length; i++) {
+ _controller.add(signal);
+ }
+ }
+ });
+ }
+
+ void _cancel() {
+ if (_id != null) {
+ _clearSignalHandler(signal._signalNumber);
+ _id = null;
+ }
+ }
+
+ /* patch */ static int _setSignalHandler(int signal)
+ native "Process_SetSignalHandler";
+ /* patch */ static int _clearSignalHandler(int signal)
+ native "Process_ClearSignalHandler";
+}
+
+
patch class _ProcessUtils {
/* patch */ static void _exit(int status) native "Process_Exit";
/* patch */ static void _setExitCode(int status)
native "Process_SetExitCode";
/* patch */ static void _sleep(int millis) native "Process_Sleep";
/* patch */ static int _pid(Process process) native "Process_Pid";
+ /* patch */ static Stream<ProcessSignal> _watchSignal(ProcessSignal signal) {
+ if (signal != ProcessSignal.SIGHUP &&
+ signal != ProcessSignal.SIGINT &&
+ (Platform.isWindows ||
+ (signal != ProcessSignal.SIGUSR1 &&
+ signal != ProcessSignal.SIGUSR2 &&
+ signal != ProcessSignal.SIGWINCH))) {
+ throw new SignalException(
+ "Listening for signal $signal is not supported");
+ }
+ if (_signalControllers[signal._signalNumber] == null) {
+ _signalControllers[signal._signalNumber] = new _SignalController(signal);
+ }
+ return _signalControllers[signal._signalNumber].stream;
+ }
}
diff --git a/runtime/bin/process_win.cc b/runtime/bin/process_win.cc
index 00514c7..3875b4f 100644
--- a/runtime/bin/process_win.cc
+++ b/runtime/bin/process_win.cc
@@ -11,6 +11,7 @@
#include "bin/process.h"
#include "bin/eventhandler.h"
#include "bin/log.h"
+#include "bin/socket.h"
#include "bin/thread.h"
#include "bin/utils.h"
#include "bin/utils_win.h"
@@ -350,6 +351,33 @@
}
+const int kMaxPipeNameSize = 80;
+template<int Count>
+static int GenerateNames(wchar_t pipe_names[Count][kMaxPipeNameSize]) {
+ UUID uuid;
+ RPC_STATUS status = UuidCreateSequential(&uuid);
+ if (status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY) {
+ return status;
+ }
+ RPC_WSTR uuid_string;
+ status = UuidToStringW(&uuid, &uuid_string);
+ if (status != RPC_S_OK) {
+ return status;
+ }
+ for (int i = 0; i < Count; i++) {
+ static const wchar_t* prefix = L"\\\\.\\Pipe\\dart";
+ _snwprintf(pipe_names[i],
+ kMaxPipeNameSize,
+ L"%s_%s_%d", prefix, uuid_string, i + 1);
+ }
+ status = RpcStringFreeW(&uuid_string);
+ if (status != RPC_S_OK) {
+ return status;
+ }
+ return 0;
+}
+
+
int Process::Start(const char* path,
char* arguments[],
intptr_t arguments_length,
@@ -368,34 +396,13 @@
HANDLE exit_handles[2] = { INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE };
// Generate unique pipe names for the four named pipes needed.
- static const int kMaxPipeNameSize = 80;
wchar_t pipe_names[4][kMaxPipeNameSize];
- UUID uuid;
- RPC_STATUS status = UuidCreateSequential(&uuid);
- if (status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY) {
+ int status = GenerateNames<4>(pipe_names);
+ if (status != 0) {
SetOsErrorMessage(os_error_message);
Log::PrintErr("UuidCreateSequential failed %d\n", status);
return status;
}
- RPC_WSTR uuid_string;
- status = UuidToStringW(&uuid, &uuid_string);
- if (status != RPC_S_OK) {
- SetOsErrorMessage(os_error_message);
- Log::PrintErr("UuidToString failed %d\n", status);
- return status;
- }
- for (int i = 0; i < 4; i++) {
- static const wchar_t* prefix = L"\\\\.\\Pipe\\dart";
- _snwprintf(pipe_names[i],
- kMaxPipeNameSize,
- L"%s_%s_%d", prefix, uuid_string, i + 1);
- }
- status = RpcStringFreeW(&uuid_string);
- if (status != RPC_S_OK) {
- SetOsErrorMessage(os_error_message);
- Log::PrintErr("RpcStringFree failed %d\n", status);
- return status;
- }
if (!CreateProcessPipe(stdin_handles, pipe_names[0], kInheritRead)) {
int error_code = SetOsErrorMessage(os_error_message);
@@ -849,6 +856,102 @@
return static_cast<intptr_t>(GetCurrentProcessId());
}
+
+static SignalInfo* signal_handlers = NULL;
+static Mutex* signal_mutex = new Mutex();
+
+
+SignalInfo::~SignalInfo() {
+ reinterpret_cast<FileHandle*>(fd_)->Close();
+}
+
+
+BOOL WINAPI SignalHandler(DWORD signal) {
+ MutexLocker lock(signal_mutex);
+ const SignalInfo* handler = signal_handlers;
+ bool handled = false;
+ while (handler != NULL) {
+ if (handler->signal() == signal) {
+ int value = 0;
+ Socket::Write(handler->fd(), &value, 1);
+ handled = true;
+ }
+ handler = handler->next();
+ }
+ return handled;
+}
+
+
+intptr_t GetWinSignal(intptr_t signal) {
+ switch (signal) {
+ case kSighup: return CTRL_CLOSE_EVENT;
+ case kSigint: return CTRL_C_EVENT;
+ default:
+ return -1;
+ }
+}
+
+
+intptr_t Process::SetSignalHandler(intptr_t signal) {
+ signal = GetWinSignal(signal);
+ if (signal == -1) return -1;
+
+ // Generate a unique pipe name for the named pipe.
+ wchar_t pipe_name[kMaxPipeNameSize];
+ int status = GenerateNames<1>(&pipe_name);
+ if (status != 0) return status;
+
+ HANDLE fds[2];
+ if (!CreateProcessPipe(fds, pipe_name, kInheritNone)) {
+ int error_code = GetLastError();
+ CloseProcessPipe(fds);
+ SetLastError(error_code);
+ return -1;
+ }
+ MutexLocker lock(signal_mutex);
+ FileHandle* write_handle = new FileHandle(fds[kWriteHandle]);
+ write_handle->EnsureInitialized(EventHandler::delegate());
+ intptr_t write_fd = reinterpret_cast<intptr_t>(write_handle);
+ if (signal_handlers == NULL) {
+ if (SetConsoleCtrlHandler(SignalHandler, true) == 0) {
+ int error_code = GetLastError();
+ delete write_handle;
+ CloseProcessPipe(fds);
+ SetLastError(error_code);
+ return -1;
+ }
+ signal_handlers = new SignalInfo(write_fd, signal);
+ } else {
+ new SignalInfo(write_fd, signal, signal_handlers);
+ }
+ return reinterpret_cast<intptr_t>(new FileHandle(fds[kReadHandle]));
+}
+
+
+void Process::ClearSignalHandler(intptr_t signal) {
+ signal = GetWinSignal(signal);
+ if (signal == -1) return;
+ MutexLocker lock(signal_mutex);
+ SignalInfo* handler = signal_handlers;
+ while (handler != NULL) {
+ if (handler->port() == Dart_GetMainPortId() &&
+ handler->signal() == signal) {
+ handler->Unlink();
+ break;
+ }
+ handler = handler->next();
+ }
+ if (handler != NULL) {
+ if (signal_handlers == handler) {
+ signal_handlers = handler->next();
+ }
+ if (signal_handlers == NULL) {
+ USE(SetConsoleCtrlHandler(SignalHandler, false));
+ }
+ }
+ delete handler;
+}
+
} // namespace bin
} // namespace dart
diff --git a/runtime/bin/resources_sources.gypi b/runtime/bin/resources_sources.gypi
index 941f67d..c5f7885 100644
--- a/runtime/bin/resources_sources.gypi
+++ b/runtime/bin/resources_sources.gypi
@@ -5,13 +5,14 @@
{
'sources': [
# VM Service backend sources
+ 'vmservice/client.dart',
'vmservice/constants.dart',
'vmservice/resources.dart',
'vmservice/running_isolate.dart',
'vmservice/running_isolates.dart',
'vmservice/server.dart',
- 'vmservice/service_request.dart',
- 'vmservice/service_request_router.dart',
+ 'vmservice/message.dart',
+ 'vmservice/message_router.dart',
'vmservice/vmservice.dart',
'vmservice/vmservice_io.dart',
# VM Service frontend sources
diff --git a/runtime/bin/secure_socket.cc b/runtime/bin/secure_socket.cc
index 6fa0a99..4bcaa73 100644
--- a/runtime/bin/secure_socket.cc
+++ b/runtime/bin/secure_socket.cc
@@ -126,16 +126,7 @@
ThrowIfError(Dart_StringToCString(host_name_object, &host_name));
RawAddr raw_addr;
- Dart_TypedData_Type type;
- uint8_t* buffer = NULL;
- intptr_t len;
- ThrowIfError(Dart_TypedDataAcquireData(host_sockaddr_storage_object,
- &type,
- reinterpret_cast<void**>(&buffer),
- &len));
- ASSERT(static_cast<size_t>(len) <= sizeof(raw_addr));
- memmove(&raw_addr, buffer, len);
- Dart_TypedDataReleaseData(host_sockaddr_storage_object);
+ SocketAddress::GetSockAddr(host_sockaddr_storage_object, &raw_addr);
int64_t port;
if (!DartUtils::GetInt64Value(port_object, &port)) {
diff --git a/runtime/bin/signal_blocker.h b/runtime/bin/signal_blocker.h
new file mode 100644
index 0000000..1ab816c
--- /dev/null
+++ b/runtime/bin/signal_blocker.h
@@ -0,0 +1,71 @@
+// 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.
+
+#ifndef BIN_SIGNAL_BLOCKER_H_
+#define BIN_SIGNAL_BLOCKER_H_
+
+#include "platform/globals.h"
+
+#if defined(TARGET_OS_WINDOWS)
+#error Do not include this file on Windows.
+#endif
+
+#include <signal.h> // NOLINT
+
+#include "platform/thread.h"
+
+namespace dart {
+namespace bin {
+
+class ThreadSignalBlocker {
+ public:
+ explicit ThreadSignalBlocker(int sig) {
+ sigset_t signal_mask;
+ sigemptyset(&signal_mask);
+ sigaddset(&signal_mask, sig);
+ // Add sig to signal mask.
+ int r = pthread_sigmask(SIG_BLOCK, &signal_mask, &old);
+ USE(r);
+ ASSERT(r == 0);
+ }
+
+ ThreadSignalBlocker(int sigs_count, const int sigs[]) {
+ sigset_t signal_mask;
+ sigemptyset(&signal_mask);
+ for (int i = 0; i < sigs_count; i++) {
+ sigaddset(&signal_mask, sigs[i]);
+ }
+ // Add sig to signal mask.
+ int r = pthread_sigmask(SIG_BLOCK, &signal_mask, &old);
+ USE(r);
+ ASSERT(r == 0);
+ }
+
+ ~ThreadSignalBlocker() {
+ // Restore signal mask.
+ int r = pthread_sigmask(SIG_SETMASK, &old, NULL);
+ USE(r);
+ ASSERT(r == 0);
+ }
+
+ private:
+ sigset_t old;
+};
+
+
+#define TEMP_FAILURE_RETRY_BLOCK_SIGNALS(expression) \
+ ({ ThreadSignalBlocker tsb(SIGPROF); \
+ int64_t __result; \
+ do { \
+ __result = static_cast<int64_t>(expression); \
+ } while (__result == -1L && errno == EINTR); \
+ __result; })
+
+#define VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(expression) \
+ (static_cast<void>(TEMP_FAILURE_RETRY_BLOCK_SIGNALS(expression)))
+
+} // namespace bin
+} // namespace dart
+
+#endif // BIN_SIGNAL_BLOCKER_H_
diff --git a/runtime/bin/socket.cc b/runtime/bin/socket.cc
index 2d1b8bc..42fe373 100644
--- a/runtime/bin/socket.cc
+++ b/runtime/bin/socket.cc
@@ -15,7 +15,6 @@
#include "include/dart_api.h"
-
namespace dart {
namespace bin {
@@ -27,75 +26,20 @@
int Socket::service_ports_index_ = 0;
-static void GetSockAddr(Dart_Handle obj, RawAddr* addr) {
- Dart_TypedData_Type data_type;
- uint8_t* data = NULL;
- intptr_t len;
- Dart_Handle result = Dart_TypedDataAcquireData(
- obj, &data_type, reinterpret_cast<void**>(&data), &len);
- if (Dart_IsError(result)) Dart_PropagateError(result);
- if (data_type != Dart_TypedData_kUint8) {
- Dart_PropagateError(Dart_NewApiError("Unexpected type for socket address"));
- }
- memmove(reinterpret_cast<void *>(addr), data, len);
- Dart_TypedDataReleaseData(obj);
-}
-
-
-void FUNCTION_NAME(InternetAddress_Fixed)(Dart_NativeArguments args) {
- int64_t id = 0;
- bool ok = DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 0), &id);
- ASSERT(ok);
- USE(ok);
- RawAddr raw;
- memset(&raw, 0, sizeof(raw));
- switch (id) {
- case SocketAddress::ADDRESS_LOOPBACK_IP_V4: {
- raw.in.sin_family = AF_INET;
- raw.in.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
- break;
- }
- case SocketAddress::ADDRESS_LOOPBACK_IP_V6: {
- raw.in6.sin6_family = AF_INET6;
- raw.in6.sin6_addr = in6addr_loopback;
- break;
- }
- case SocketAddress::ADDRESS_ANY_IP_V4: {
- raw.in.sin_family = AF_INET;
- raw.in.sin_addr.s_addr = INADDR_ANY;
- break;
- }
- case SocketAddress::ADDRESS_ANY_IP_V6: {
- raw.in6.sin6_family = AF_INET6;
- raw.in6.sin6_addr = in6addr_any;
- break;
- }
- default:
- Dart_Handle error = DartUtils::NewDartArgumentError("");
- if (Dart_IsError(error)) Dart_PropagateError(error);
- Dart_ThrowException(error);
- }
- Dart_SetReturnValue(args, SocketAddress::ToTypedData(&raw));
-}
-
-
void FUNCTION_NAME(InternetAddress_Parse)(Dart_NativeArguments args) {
- int64_t type = 0;
- bool ok = DartUtils::GetInt64Value(Dart_GetNativeArgument(args, 0), &type);
- ASSERT(ok);
- USE(ok);
const char* address =
- DartUtils::GetStringValue(Dart_GetNativeArgument(args, 1));
+ DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0));
ASSERT(address != NULL);
RawAddr raw;
memset(&raw, 0, sizeof(raw));
+ int type = strchr(address, ':') == NULL ? SocketAddress::TYPE_IPV4
+ : SocketAddress::TYPE_IPV6;
if (type == SocketAddress::TYPE_IPV4) {
raw.addr.sa_family = AF_INET;
} else {
- ASSERT(type == SocketAddress::TYPE_IPV6);
raw.addr.sa_family = AF_INET6;
}
- ok = Socket::ParseAddress(type, address, &raw);
+ bool ok = Socket::ParseAddress(type, address, &raw);
if (!ok) {
Dart_SetReturnValue(args, Dart_Null());
} else {
@@ -106,7 +50,7 @@
void FUNCTION_NAME(Socket_CreateConnect)(Dart_NativeArguments args) {
RawAddr addr;
- GetSockAddr(Dart_GetNativeArgument(args, 1), &addr);
+ SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 1), &addr);
Dart_Handle port_arg = Dart_GetNativeArgument(args, 2);
int64_t port = DartUtils::GetInt64ValueCheckRange(port_arg, 0, 65535);
intptr_t socket = Socket::CreateConnect(addr, port);
@@ -122,7 +66,7 @@
void FUNCTION_NAME(Socket_CreateBindDatagram)(Dart_NativeArguments args) {
RawAddr addr;
- GetSockAddr(Dart_GetNativeArgument(args, 1), &addr);
+ SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 1), &addr);
Dart_Handle port_arg = Dart_GetNativeArgument(args, 2);
int64_t port = DartUtils::GetInt64ValueCheckRange(port_arg, 0, 65535);
bool reuse_addr = DartUtils::GetBooleanValue(Dart_GetNativeArgument(args, 3));
@@ -246,20 +190,14 @@
Socket::FormatNumericAddress(&addr, numeric_address, INET6_ADDRSTRLEN);
// Create a Datagram object with the data and sender address and port.
- const int kNumArgs = 5;
+ const int kNumArgs = 4;
Dart_Handle dart_args[kNumArgs];
dart_args[0] = data;
- dart_args[1] = Dart_NewBoolean(addr.addr.sa_family == AF_INET6);
- dart_args[2] = Dart_NewStringFromCString(numeric_address);
- if (Dart_IsError(dart_args[2])) Dart_PropagateError(dart_args[2]);
- int len = SocketAddress::GetAddrLength(&addr);
- dart_args[3] = Dart_NewTypedData(Dart_TypedData_kUint8, len);
+ dart_args[1] = Dart_NewStringFromCString(numeric_address);
+ if (Dart_IsError(dart_args[1])) Dart_PropagateError(dart_args[1]);
+ dart_args[2] = SocketAddress::ToTypedData(&addr);
+ dart_args[3] = Dart_NewInteger(port);
if (Dart_IsError(dart_args[3])) Dart_PropagateError(dart_args[3]);
- Dart_Handle err = Dart_ListSetAsBytes(
- dart_args[3], 0, reinterpret_cast<uint8_t *>(&addr), len);
- if (Dart_IsError(err)) Dart_PropagateError(err);
- dart_args[4] = Dart_NewInteger(port);
- if (Dart_IsError(dart_args[4])) Dart_PropagateError(dart_args[4]);
// TODO(sgjesse): Cache the _makeDatagram function somewhere.
Dart_Handle io_lib =
Dart_LookupLibrary(DartUtils::NewString("dart:io"));
@@ -319,7 +257,7 @@
Dart_Handle address_obj = Dart_GetNativeArgument(args, 4);
ASSERT(Dart_IsList(address_obj));
RawAddr addr;
- GetSockAddr(address_obj, &addr);
+ SocketAddress::GetSockAddr(address_obj, &addr);
int64_t port = DartUtils::GetInt64ValueCheckRange(
Dart_GetNativeArgument(args, 5),
0,
@@ -428,7 +366,7 @@
void FUNCTION_NAME(ServerSocket_CreateBindListen)(Dart_NativeArguments args) {
RawAddr addr;
- GetSockAddr(Dart_GetNativeArgument(args, 1), &addr);
+ SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 1), &addr);
int64_t port = DartUtils::GetInt64ValueCheckRange(
Dart_GetNativeArgument(args, 2),
0,
@@ -497,13 +435,9 @@
entry->SetAt(1, as_string);
RawAddr raw = addr->addr();
- CObjectUint8Array* data = new CObjectUint8Array(CObject::NewUint8Array(
- SocketAddress::GetAddrLength(&raw)));
- memmove(data->Buffer(),
- reinterpret_cast<void *>(&raw),
- SocketAddress::GetAddrLength(&raw));
-
+ CObjectUint8Array* data = SocketAddress::ToCObject(&raw);
entry->SetAt(2, data);
+
array->SetAt(i + 1, entry);
}
result = array;
@@ -523,9 +457,21 @@
request[0]->IsTypedData()) {
CObjectUint8Array addr_object(request[0]);
RawAddr addr;
- memmove(reinterpret_cast<void *>(&addr),
- addr_object.Buffer(),
- addr_object.Length());
+ int len = addr_object.Length();
+ memset(reinterpret_cast<void*>(&addr), 0, sizeof(RawAddr));
+ if (len == sizeof(in_addr)) {
+ addr.in.sin_family = AF_INET;
+ memmove(reinterpret_cast<void*>(&addr.in.sin_addr),
+ addr_object.Buffer(),
+ len);
+ } else {
+ ASSERT(len == sizeof(in6_addr));
+ addr.in6.sin6_family = AF_INET6;
+ memmove(reinterpret_cast<void*>(&addr.in6.sin6_addr),
+ addr_object.Buffer(),
+ len);
+ }
+
OSError* os_error = NULL;
const intptr_t kMaxHostLength = 1025;
char host[kMaxHostLength];
@@ -567,11 +513,7 @@
entry->SetAt(1, as_string);
RawAddr raw = addr->addr();
- CObjectUint8Array* data = new CObjectUint8Array(CObject::NewUint8Array(
- SocketAddress::GetAddrLength(&raw)));
- memmove(data->Buffer(),
- reinterpret_cast<void *>(&raw),
- SocketAddress::GetAddrLength(&raw));
+ CObjectUint8Array* data = SocketAddress::ToCObject(&raw);
entry->SetAt(2, data);
CObjectString* interface_name = new CObjectString(CObject::NewString(
@@ -702,10 +644,10 @@
intptr_t socket =
Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
RawAddr addr;
- GetSockAddr(Dart_GetNativeArgument(args, 1), &addr);
+ SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 1), &addr);
RawAddr interface;
if (Dart_GetNativeArgument(args, 2) != Dart_Null()) {
- GetSockAddr(Dart_GetNativeArgument(args, 2), &interface);
+ SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 2), &interface);
}
int interfaceIndex =
DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 3));
@@ -721,10 +663,10 @@
intptr_t socket =
Socket::GetSocketIdNativeField(Dart_GetNativeArgument(args, 0));
RawAddr addr;
- GetSockAddr(Dart_GetNativeArgument(args, 1), &addr);
+ SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 1), &addr);
RawAddr interface;
if (Dart_GetNativeArgument(args, 2) != Dart_Null()) {
- GetSockAddr(Dart_GetNativeArgument(args, 2), &interface);
+ SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 2), &interface);
}
int interfaceIndex =
DartUtils::GetIntegerValue(Dart_GetNativeArgument(args, 3));
diff --git a/runtime/bin/socket.h b/runtime/bin/socket.h
index 0c009b0..b27a9c5 100644
--- a/runtime/bin/socket.h
+++ b/runtime/bin/socket.h
@@ -70,6 +70,36 @@
sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in);
}
+ static intptr_t GetInAddrLength(const RawAddr* addr) {
+ ASSERT(addr->ss.ss_family == AF_INET || addr->ss.ss_family == AF_INET6);
+ return addr->ss.ss_family == AF_INET6 ?
+ sizeof(struct in6_addr) : sizeof(struct in_addr);
+ }
+
+ static void GetSockAddr(Dart_Handle obj, RawAddr* addr) {
+ Dart_TypedData_Type data_type;
+ uint8_t* data = NULL;
+ intptr_t len;
+ Dart_Handle result = Dart_TypedDataAcquireData(
+ obj, &data_type, reinterpret_cast<void**>(&data), &len);
+ if (Dart_IsError(result)) Dart_PropagateError(result);
+ if (data_type != Dart_TypedData_kUint8 ||
+ (len != sizeof(in_addr) && len != sizeof(in6_addr))) {
+ Dart_PropagateError(
+ Dart_NewApiError("Unexpected type for socket address"));
+ }
+ memset(reinterpret_cast<void*>(addr), 0, sizeof(RawAddr));
+ if (len == sizeof(in_addr)) {
+ addr->in.sin_family = AF_INET;
+ memmove(reinterpret_cast<void *>(&addr->in.sin_addr), data, len);
+ } else {
+ ASSERT(len == sizeof(in6_addr));
+ addr->in6.sin6_family = AF_INET6;
+ memmove(reinterpret_cast<void*>(&addr->in6.sin6_addr), data, len);
+ }
+ Dart_TypedDataReleaseData(obj);
+ }
+
static int16_t FromType(int type) {
if (type == TYPE_ANY) return AF_UNSPEC;
if (type == TYPE_IPV4) return AF_INET;
@@ -85,7 +115,7 @@
}
}
- static intptr_t GetAddrPort(RawAddr* addr) {
+ static intptr_t GetAddrPort(const RawAddr* addr) {
if (addr->ss.ss_family == AF_INET) {
return ntohs(addr->in.sin_port);
} else {
@@ -93,14 +123,36 @@
}
}
- static Dart_Handle ToTypedData(RawAddr* addr) {
- int len = GetAddrLength(addr);
+ static Dart_Handle ToTypedData(RawAddr* raw) {
+ int len = GetInAddrLength(raw);
Dart_Handle result = Dart_NewTypedData(Dart_TypedData_kUint8, len);
if (Dart_IsError(result)) Dart_PropagateError(result);
- Dart_ListSetAsBytes(result, 0, reinterpret_cast<uint8_t *>(addr), len);
+ Dart_Handle err;
+ if (raw->addr.sa_family == AF_INET6) {
+ err = Dart_ListSetAsBytes(
+ result, 0, reinterpret_cast<uint8_t*>(&raw->in6.sin6_addr), len);
+ } else {
+ err = Dart_ListSetAsBytes(
+ result, 0, reinterpret_cast<uint8_t*>(&raw->in.sin_addr), len);
+ }
+ if (Dart_IsError(err)) Dart_PropagateError(err);
return result;
}
+ static CObjectUint8Array* ToCObject(RawAddr* raw) {
+ int in_addr_len = SocketAddress::GetInAddrLength(raw);
+ void* in_addr;
+ CObjectUint8Array* data =
+ new CObjectUint8Array(CObject::NewUint8Array(in_addr_len));
+ if (raw->addr.sa_family == AF_INET6) {
+ in_addr = reinterpret_cast<void*>(&raw->in6.sin6_addr);
+ } else {
+ in_addr = reinterpret_cast<void*>(&raw->in.sin_addr);
+ }
+ memmove(data->Buffer(), in_addr, in_addr_len);
+ return data;
+ }
+
private:
char as_string_[INET6_ADDRSTRLEN];
RawAddr addr_;
diff --git a/runtime/bin/socket_android.cc b/runtime/bin/socket_android.cc
index 72a03bd..0ab6af4 100644
--- a/runtime/bin/socket_android.cc
+++ b/runtime/bin/socket_android.cc
@@ -16,6 +16,7 @@
#include "bin/fdutils.h"
#include "bin/file.h"
#include "bin/log.h"
+#include "bin/signal_blocker.h"
#include "bin/socket.h"
@@ -35,7 +36,7 @@
bool Socket::FormatNumericAddress(RawAddr* addr, char* address, int len) {
socklen_t salen = SocketAddress::GetAddrLength(addr);
- if (TEMP_FAILURE_RETRY(getnameinfo(&addr->addr,
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(getnameinfo(&addr->addr,
salen,
address,
len,
@@ -56,8 +57,8 @@
intptr_t Socket::Create(RawAddr addr) {
intptr_t fd;
-
- fd = TEMP_FAILURE_RETRY(socket(addr.ss.ss_family, SOCK_STREAM, 0));
+ fd = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(socket(addr.ss.ss_family, SOCK_STREAM,
+ 0));
if (fd < 0) {
const int kBufferSize = 1024;
char error_message[kBufferSize];
@@ -73,14 +74,14 @@
intptr_t Socket::Connect(intptr_t fd, RawAddr addr, const intptr_t port) {
SocketAddress::SetAddrPort(&addr, port);
- intptr_t result = TEMP_FAILURE_RETRY(
+ intptr_t result = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
connect(fd,
&addr.addr,
SocketAddress::GetAddrLength(&addr)));
if (result == 0 || errno == EINPROGRESS) {
return fd;
}
- VOID_TEMP_FAILURE_RETRY(close(fd));
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fd));
return -1;
}
@@ -104,7 +105,8 @@
int Socket::Read(intptr_t fd, void* buffer, intptr_t num_bytes) {
ASSERT(fd >= 0);
- ssize_t read_bytes = TEMP_FAILURE_RETRY(read(fd, buffer, num_bytes));
+ ssize_t read_bytes = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(read(fd, buffer,
+ num_bytes));
ASSERT(EAGAIN == EWOULDBLOCK);
if (read_bytes == -1 && errno == EWOULDBLOCK) {
// If the read would block we need to retry and therefore return 0
@@ -120,7 +122,7 @@
ASSERT(fd >= 0);
socklen_t addr_len = sizeof(addr->ss);
ssize_t read_bytes =
- TEMP_FAILURE_RETRY(
+ TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
recvfrom(fd, buffer, num_bytes, 0, &addr->addr, &addr_len));
if (read_bytes == -1 && errno == EWOULDBLOCK) {
// If the read would block we need to retry and therefore return 0
@@ -133,7 +135,8 @@
int Socket::Write(intptr_t fd, const void* buffer, intptr_t num_bytes) {
ASSERT(fd >= 0);
- ssize_t written_bytes = TEMP_FAILURE_RETRY(write(fd, buffer, num_bytes));
+ ssize_t written_bytes = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(write(fd, buffer,
+ num_bytes));
ASSERT(EAGAIN == EWOULDBLOCK);
if (written_bytes == -1 && errno == EWOULDBLOCK) {
// If the would block we need to retry and therefore return 0 as
@@ -148,7 +151,7 @@
RawAddr addr) {
ASSERT(fd >= 0);
ssize_t written_bytes =
- TEMP_FAILURE_RETRY(
+ TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
sendto(fd, buffer, num_bytes, 0,
&addr.addr, SocketAddress::GetAddrLength(&addr)));
ASSERT(EAGAIN == EWOULDBLOCK);
@@ -165,7 +168,7 @@
ASSERT(fd >= 0);
RawAddr raw;
socklen_t size = sizeof(raw);
- if (TEMP_FAILURE_RETRY(
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
getsockname(fd,
&raw.addr,
&size))) {
@@ -183,7 +186,7 @@
ASSERT(fd >= 0);
RawAddr raw;
socklen_t size = sizeof(raw);
- if (TEMP_FAILURE_RETRY(
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
getpeername(fd,
&raw.addr,
&size))) {
@@ -268,7 +271,7 @@
intptr_t host_len,
OSError** os_error) {
ASSERT(host_len >= NI_MAXHOST);
- int status = TEMP_FAILURE_RETRY(getnameinfo(
+ int status = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(getnameinfo(
&addr.addr,
SocketAddress::GetAddrLength(&addr),
host,
@@ -303,7 +306,7 @@
RawAddr* addr, intptr_t port, bool reuseAddress) {
intptr_t fd;
- fd = TEMP_FAILURE_RETRY(
+ fd = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
socket(addr->addr.sa_family, SOCK_DGRAM, IPPROTO_UDP));
if (fd < 0) return -1;
@@ -311,16 +314,16 @@
if (reuseAddress) {
int optval = 1;
- VOID_TEMP_FAILURE_RETRY(
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)));
}
SocketAddress::SetAddrPort(addr, port);
- if (TEMP_FAILURE_RETRY(
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
bind(fd,
&addr->addr,
SocketAddress::GetAddrLength(addr))) < 0) {
- TEMP_FAILURE_RETRY(close(fd));
+ TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fd));
return -1;
}
@@ -344,27 +347,28 @@
bool v6_only) {
intptr_t fd;
- fd = TEMP_FAILURE_RETRY(socket(addr.ss.ss_family, SOCK_STREAM, 0));
+ fd = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(socket(addr.ss.ss_family, SOCK_STREAM,
+ 0));
if (fd < 0) return -1;
FDUtils::SetCloseOnExec(fd);
int optval = 1;
- TEMP_FAILURE_RETRY(
+ TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)));
if (addr.ss.ss_family == AF_INET6) {
optval = v6_only ? 1 : 0;
- TEMP_FAILURE_RETRY(
+ TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)));
}
SocketAddress::SetAddrPort(&addr, port);
- if (TEMP_FAILURE_RETRY(
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
bind(fd,
&addr.addr,
SocketAddress::GetAddrLength(&addr))) < 0) {
- VOID_TEMP_FAILURE_RETRY(close(fd));
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fd));
return -1;
}
@@ -374,13 +378,14 @@
// that we do not get the bad port number again.
intptr_t new_fd = CreateBindListen(addr, 0, backlog, v6_only);
int err = errno;
- VOID_TEMP_FAILURE_RETRY(close(fd));
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fd));
errno = err;
return new_fd;
}
- if (TEMP_FAILURE_RETRY(listen(fd, backlog > 0 ? backlog : SOMAXCONN)) != 0) {
- VOID_TEMP_FAILURE_RETRY(close(fd));
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
+ listen(fd, backlog > 0 ? backlog : SOMAXCONN)) != 0) {
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fd));
return -1;
}
@@ -403,7 +408,7 @@
intptr_t socket;
struct sockaddr clientaddr;
socklen_t addrlen = sizeof(clientaddr);
- socket = TEMP_FAILURE_RETRY(accept(fd, &clientaddr, &addrlen));
+ socket = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(accept(fd, &clientaddr, &addrlen));
if (socket == -1) {
if (IsTemporaryAcceptError(errno)) {
// We need to signal to the caller that this is actually not an
@@ -421,7 +426,7 @@
void Socket::Close(intptr_t fd) {
ASSERT(fd >= 0);
- int err = TEMP_FAILURE_RETRY(close(fd));
+ int err = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fd));
if (err != 0) {
const int kBufferSize = 1024;
char error_message[kBufferSize];
@@ -444,7 +449,7 @@
bool Socket::GetNoDelay(intptr_t fd, bool* enabled) {
int on;
socklen_t len = sizeof(on);
- int err = TEMP_FAILURE_RETRY(getsockopt(fd,
+ int err = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(getsockopt(fd,
IPPROTO_TCP,
TCP_NODELAY,
reinterpret_cast<void *>(&on),
@@ -458,7 +463,7 @@
bool Socket::SetNoDelay(intptr_t fd, bool enabled) {
int on = enabled ? 1 : 0;
- return TEMP_FAILURE_RETRY(setsockopt(fd,
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(setsockopt(fd,
IPPROTO_TCP,
TCP_NODELAY,
reinterpret_cast<char *>(&on),
@@ -472,7 +477,7 @@
int level = protocol == SocketAddress::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6;
int optname = protocol == SocketAddress::TYPE_IPV4
? IP_MULTICAST_LOOP : IPV6_MULTICAST_LOOP;
- if (TEMP_FAILURE_RETRY(getsockopt(fd,
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(getsockopt(fd,
level,
optname,
reinterpret_cast<char *>(&on),
@@ -489,7 +494,7 @@
int level = protocol == SocketAddress::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6;
int optname = protocol == SocketAddress::TYPE_IPV4
? IP_MULTICAST_LOOP : IPV6_MULTICAST_LOOP;
- return TEMP_FAILURE_RETRY(setsockopt(fd,
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(setsockopt(fd,
level,
optname,
reinterpret_cast<char *>(&on),
@@ -503,7 +508,7 @@
int level = protocol == SocketAddress::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6;
int optname = protocol == SocketAddress::TYPE_IPV4
? IP_MULTICAST_TTL : IPV6_MULTICAST_HOPS;
- if (TEMP_FAILURE_RETRY(getsockopt(fd,
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(getsockopt(fd,
level,
optname,
reinterpret_cast<char *>(&v),
@@ -520,7 +525,7 @@
int level = protocol == SocketAddress::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6;
int optname = protocol == SocketAddress::TYPE_IPV4
? IP_MULTICAST_TTL : IPV6_MULTICAST_HOPS;
- return TEMP_FAILURE_RETRY(setsockopt(fd,
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(setsockopt(fd,
level,
optname,
reinterpret_cast<char *>(&v),
@@ -531,7 +536,7 @@
bool Socket::GetBroadcast(intptr_t fd, bool* enabled) {
int on;
socklen_t len = sizeof(on);
- int err = TEMP_FAILURE_RETRY(getsockopt(fd,
+ int err = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(getsockopt(fd,
SOL_SOCKET,
SO_BROADCAST,
reinterpret_cast<char *>(&on),
@@ -545,7 +550,7 @@
bool Socket::SetBroadcast(intptr_t fd, bool enabled) {
int on = enabled ? 1 : 0;
- return TEMP_FAILURE_RETRY(setsockopt(fd,
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(setsockopt(fd,
SOL_SOCKET,
SO_BROADCAST,
reinterpret_cast<char *>(&on),
@@ -559,7 +564,7 @@
struct group_req mreq;
mreq.gr_interface = interfaceIndex;
memmove(&mreq.gr_group, &addr->ss, SocketAddress::GetAddrLength(addr));
- return TEMP_FAILURE_RETRY(setsockopt(
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(setsockopt(
fd, proto, MCAST_JOIN_GROUP, &mreq, sizeof(mreq))) == 0;
}
@@ -570,7 +575,7 @@
struct group_req mreq;
mreq.gr_interface = interfaceIndex;
memmove(&mreq.gr_group, &addr->ss, SocketAddress::GetAddrLength(addr));
- return TEMP_FAILURE_RETRY(setsockopt(
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(setsockopt(
fd, proto, MCAST_LEAVE_GROUP, &mreq, sizeof(mreq))) == 0;
}
diff --git a/runtime/bin/socket_linux.cc b/runtime/bin/socket_linux.cc
index 2c4a337..08d8fe1 100644
--- a/runtime/bin/socket_linux.cc
+++ b/runtime/bin/socket_linux.cc
@@ -18,6 +18,7 @@
#include "bin/fdutils.h"
#include "bin/file.h"
#include "bin/log.h"
+#include "bin/signal_blocker.h"
#include "bin/socket.h"
@@ -37,7 +38,7 @@
bool Socket::FormatNumericAddress(RawAddr* addr, char* address, int len) {
socklen_t salen = SocketAddress::GetAddrLength(addr);
- if (TEMP_FAILURE_RETRY(getnameinfo(&addr->addr,
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(getnameinfo(&addr->addr,
salen,
address,
len,
@@ -58,8 +59,8 @@
intptr_t Socket::Create(RawAddr addr) {
intptr_t fd;
-
- fd = TEMP_FAILURE_RETRY(socket(addr.ss.ss_family, SOCK_STREAM, 0));
+ fd = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(socket(addr.ss.ss_family, SOCK_STREAM,
+ 0));
if (fd < 0) {
const int kBufferSize = 1024;
char error_buf[kBufferSize];
@@ -75,14 +76,14 @@
intptr_t Socket::Connect(intptr_t fd, RawAddr addr, const intptr_t port) {
SocketAddress::SetAddrPort(&addr, port);
- intptr_t result = TEMP_FAILURE_RETRY(
+ intptr_t result = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
connect(fd,
&addr.addr,
SocketAddress::GetAddrLength(&addr)));
if (result == 0 || errno == EINPROGRESS) {
return fd;
}
- VOID_TEMP_FAILURE_RETRY(close(fd));
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fd));
return -1;
}
@@ -106,7 +107,8 @@
int Socket::Read(intptr_t fd, void* buffer, intptr_t num_bytes) {
ASSERT(fd >= 0);
- ssize_t read_bytes = TEMP_FAILURE_RETRY(read(fd, buffer, num_bytes));
+ ssize_t read_bytes = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(read(fd, buffer,
+ num_bytes));
ASSERT(EAGAIN == EWOULDBLOCK);
if (read_bytes == -1 && errno == EWOULDBLOCK) {
// If the read would block we need to retry and therefore return 0
@@ -122,7 +124,7 @@
ASSERT(fd >= 0);
socklen_t addr_len = sizeof(addr->ss);
ssize_t read_bytes =
- TEMP_FAILURE_RETRY(
+ TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
recvfrom(fd, buffer, num_bytes, 0, &addr->addr, &addr_len));
if (read_bytes == -1 && errno == EWOULDBLOCK) {
// If the read would block we need to retry and therefore return 0
@@ -135,7 +137,8 @@
int Socket::Write(intptr_t fd, const void* buffer, intptr_t num_bytes) {
ASSERT(fd >= 0);
- ssize_t written_bytes = TEMP_FAILURE_RETRY(write(fd, buffer, num_bytes));
+ ssize_t written_bytes = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(write(fd, buffer,
+ num_bytes));
ASSERT(EAGAIN == EWOULDBLOCK);
if (written_bytes == -1 && errno == EWOULDBLOCK) {
// If the would block we need to retry and therefore return 0 as
@@ -150,7 +153,7 @@
RawAddr addr) {
ASSERT(fd >= 0);
ssize_t written_bytes =
- TEMP_FAILURE_RETRY(
+ TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
sendto(fd, buffer, num_bytes, 0,
&addr.addr, SocketAddress::GetAddrLength(&addr)));
ASSERT(EAGAIN == EWOULDBLOCK);
@@ -167,7 +170,7 @@
ASSERT(fd >= 0);
RawAddr raw;
socklen_t size = sizeof(raw);
- if (TEMP_FAILURE_RETRY(
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
getsockname(fd,
&raw.addr,
&size))) {
@@ -185,7 +188,7 @@
ASSERT(fd >= 0);
RawAddr raw;
socklen_t size = sizeof(raw);
- if (TEMP_FAILURE_RETRY(
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
getpeername(fd,
&raw.addr,
&size))) {
@@ -269,7 +272,7 @@
intptr_t host_len,
OSError** os_error) {
ASSERT(host_len >= NI_MAXHOST);
- int status = TEMP_FAILURE_RETRY(getnameinfo(
+ int status = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(getnameinfo(
&addr.addr,
SocketAddress::GetAddrLength(&addr),
host,
@@ -304,7 +307,7 @@
RawAddr* addr, intptr_t port, bool reuseAddress) {
intptr_t fd;
- fd = TEMP_FAILURE_RETRY(
+ fd = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
socket(addr->addr.sa_family, SOCK_DGRAM, IPPROTO_UDP));
if (fd < 0) return -1;
@@ -312,16 +315,16 @@
if (reuseAddress) {
int optval = 1;
- VOID_TEMP_FAILURE_RETRY(
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)));
}
SocketAddress::SetAddrPort(addr, port);
- if (TEMP_FAILURE_RETRY(
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
bind(fd,
&addr->addr,
SocketAddress::GetAddrLength(addr))) < 0) {
- TEMP_FAILURE_RETRY(close(fd));
+ TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fd));
return -1;
}
@@ -387,27 +390,28 @@
bool v6_only) {
intptr_t fd;
- fd = TEMP_FAILURE_RETRY(socket(addr.ss.ss_family, SOCK_STREAM, 0));
+ fd = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(socket(addr.ss.ss_family, SOCK_STREAM,
+ 0));
if (fd < 0) return -1;
FDUtils::SetCloseOnExec(fd);
int optval = 1;
- TEMP_FAILURE_RETRY(
+ TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)));
if (addr.ss.ss_family == AF_INET6) {
optval = v6_only ? 1 : 0;
- TEMP_FAILURE_RETRY(
+ TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)));
}
SocketAddress::SetAddrPort(&addr, port);
- if (TEMP_FAILURE_RETRY(
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
bind(fd,
&addr.addr,
SocketAddress::GetAddrLength(&addr))) < 0) {
- VOID_TEMP_FAILURE_RETRY(close(fd));
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fd));
return -1;
}
@@ -417,13 +421,14 @@
// that we do not get the bad port number again.
intptr_t new_fd = CreateBindListen(addr, 0, backlog, v6_only);
int err = errno;
- VOID_TEMP_FAILURE_RETRY(close(fd));
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fd));
errno = err;
return new_fd;
}
- if (TEMP_FAILURE_RETRY(listen(fd, backlog > 0 ? backlog : SOMAXCONN)) != 0) {
- VOID_TEMP_FAILURE_RETRY(close(fd));
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
+ listen(fd, backlog > 0 ? backlog : SOMAXCONN)) != 0) {
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fd));
return -1;
}
@@ -446,7 +451,7 @@
intptr_t socket;
struct sockaddr clientaddr;
socklen_t addrlen = sizeof(clientaddr);
- socket = TEMP_FAILURE_RETRY(accept(fd, &clientaddr, &addrlen));
+ socket = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(accept(fd, &clientaddr, &addrlen));
if (socket == -1) {
if (IsTemporaryAcceptError(errno)) {
// We need to signal to the caller that this is actually not an
@@ -464,7 +469,7 @@
void Socket::Close(intptr_t fd) {
ASSERT(fd >= 0);
- int err = TEMP_FAILURE_RETRY(close(fd));
+ int err = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fd));
if (err != 0) {
const int kBufferSize = 1024;
char error_buf[kBufferSize];
@@ -486,7 +491,7 @@
bool Socket::GetNoDelay(intptr_t fd, bool* enabled) {
int on;
socklen_t len = sizeof(on);
- int err = TEMP_FAILURE_RETRY(getsockopt(fd,
+ int err = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(getsockopt(fd,
IPPROTO_TCP,
TCP_NODELAY,
reinterpret_cast<void *>(&on),
@@ -500,7 +505,7 @@
bool Socket::SetNoDelay(intptr_t fd, bool enabled) {
int on = enabled ? 1 : 0;
- return TEMP_FAILURE_RETRY(setsockopt(fd,
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(setsockopt(fd,
IPPROTO_TCP,
TCP_NODELAY,
reinterpret_cast<char *>(&on),
@@ -514,7 +519,7 @@
int level = protocol == SocketAddress::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6;
int optname = protocol == SocketAddress::TYPE_IPV4
? IP_MULTICAST_LOOP : IPV6_MULTICAST_LOOP;
- if (TEMP_FAILURE_RETRY(getsockopt(fd,
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(getsockopt(fd,
level,
optname,
reinterpret_cast<char *>(&on),
@@ -531,7 +536,7 @@
int level = protocol == SocketAddress::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6;
int optname = protocol == SocketAddress::TYPE_IPV4
? IP_MULTICAST_LOOP : IPV6_MULTICAST_LOOP;
- return TEMP_FAILURE_RETRY(setsockopt(fd,
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(setsockopt(fd,
level,
optname,
reinterpret_cast<char *>(&on),
@@ -545,7 +550,7 @@
int level = protocol == SocketAddress::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6;
int optname = protocol == SocketAddress::TYPE_IPV4
? IP_MULTICAST_TTL : IPV6_MULTICAST_HOPS;
- if (TEMP_FAILURE_RETRY(getsockopt(fd,
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(getsockopt(fd,
level,
optname,
reinterpret_cast<char *>(&v),
@@ -562,7 +567,7 @@
int level = protocol == SocketAddress::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6;
int optname = protocol == SocketAddress::TYPE_IPV4
? IP_MULTICAST_TTL : IPV6_MULTICAST_HOPS;
- return TEMP_FAILURE_RETRY(setsockopt(fd,
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(setsockopt(fd,
level,
optname,
reinterpret_cast<char *>(&v),
@@ -573,7 +578,7 @@
bool Socket::GetBroadcast(intptr_t fd, bool* enabled) {
int on;
socklen_t len = sizeof(on);
- int err = TEMP_FAILURE_RETRY(getsockopt(fd,
+ int err = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(getsockopt(fd,
SOL_SOCKET,
SO_BROADCAST,
reinterpret_cast<char *>(&on),
@@ -587,7 +592,7 @@
bool Socket::SetBroadcast(intptr_t fd, bool enabled) {
int on = enabled ? 1 : 0;
- return TEMP_FAILURE_RETRY(setsockopt(fd,
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(setsockopt(fd,
SOL_SOCKET,
SO_BROADCAST,
reinterpret_cast<char *>(&on),
@@ -601,7 +606,7 @@
struct group_req mreq;
mreq.gr_interface = interfaceIndex;
memmove(&mreq.gr_group, &addr->ss, SocketAddress::GetAddrLength(addr));
- return TEMP_FAILURE_RETRY(setsockopt(
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(setsockopt(
fd, proto, MCAST_JOIN_GROUP, &mreq, sizeof(mreq))) == 0;
}
@@ -612,7 +617,7 @@
struct group_req mreq;
mreq.gr_interface = interfaceIndex;
memmove(&mreq.gr_group, &addr->ss, SocketAddress::GetAddrLength(addr));
- return TEMP_FAILURE_RETRY(setsockopt(
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(setsockopt(
fd, proto, MCAST_LEAVE_GROUP, &mreq, sizeof(mreq))) == 0;
}
diff --git a/runtime/bin/socket_macos.cc b/runtime/bin/socket_macos.cc
index f626dff..815b0f7 100644
--- a/runtime/bin/socket_macos.cc
+++ b/runtime/bin/socket_macos.cc
@@ -18,6 +18,7 @@
#include "bin/fdutils.h"
#include "bin/file.h"
#include "bin/log.h"
+#include "bin/signal_blocker.h"
#include "bin/socket.h"
@@ -37,7 +38,7 @@
bool Socket::FormatNumericAddress(RawAddr* addr, char* address, int len) {
socklen_t salen = SocketAddress::GetAddrLength(addr);
- if (TEMP_FAILURE_RETRY(getnameinfo(&addr->addr,
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(getnameinfo(&addr->addr,
salen,
address,
len,
@@ -58,8 +59,8 @@
intptr_t Socket::Create(RawAddr addr) {
intptr_t fd;
-
- fd = TEMP_FAILURE_RETRY(socket(addr.ss.ss_family, SOCK_STREAM, 0));
+ fd = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(socket(addr.ss.ss_family, SOCK_STREAM,
+ 0));
if (fd < 0) {
const int kBufferSize = 1024;
char error_message[kBufferSize];
@@ -75,14 +76,14 @@
intptr_t Socket::Connect(intptr_t fd, RawAddr addr, const intptr_t port) {
SocketAddress::SetAddrPort(&addr, port);
- intptr_t result = TEMP_FAILURE_RETRY(
+ intptr_t result = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
connect(fd,
&addr.addr,
SocketAddress::GetAddrLength(&addr)));
if (result == 0 || errno == EINPROGRESS) {
return fd;
}
- VOID_TEMP_FAILURE_RETRY(close(fd));
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fd));
return -1;
}
@@ -106,7 +107,8 @@
int Socket::Read(intptr_t fd, void* buffer, intptr_t num_bytes) {
ASSERT(fd >= 0);
- ssize_t read_bytes = TEMP_FAILURE_RETRY(read(fd, buffer, num_bytes));
+ ssize_t read_bytes = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(read(fd, buffer,
+ num_bytes));
ASSERT(EAGAIN == EWOULDBLOCK);
if (read_bytes == -1 && errno == EWOULDBLOCK) {
// If the read would block we need to retry and therefore return 0
@@ -122,7 +124,7 @@
ASSERT(fd >= 0);
socklen_t addr_len = sizeof(addr->ss);
ssize_t read_bytes =
- TEMP_FAILURE_RETRY(
+ TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
recvfrom(fd, buffer, num_bytes, 0, &addr->addr, &addr_len));
if (read_bytes == -1 && errno == EWOULDBLOCK) {
// If the read would block we need to retry and therefore return 0
@@ -135,7 +137,8 @@
int Socket::Write(intptr_t fd, const void* buffer, intptr_t num_bytes) {
ASSERT(fd >= 0);
- ssize_t written_bytes = TEMP_FAILURE_RETRY(write(fd, buffer, num_bytes));
+ ssize_t written_bytes = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(write(fd, buffer,
+ num_bytes));
ASSERT(EAGAIN == EWOULDBLOCK);
if (written_bytes == -1 && errno == EWOULDBLOCK) {
// If the would block we need to retry and therefore return 0 as
@@ -150,7 +153,7 @@
RawAddr addr) {
ASSERT(fd >= 0);
ssize_t written_bytes =
- TEMP_FAILURE_RETRY(
+ TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
sendto(fd, buffer, num_bytes, 0,
&addr.addr, SocketAddress::GetAddrLength(&addr)));
ASSERT(EAGAIN == EWOULDBLOCK);
@@ -167,7 +170,7 @@
ASSERT(fd >= 0);
RawAddr raw;
socklen_t size = sizeof(raw);
- if (TEMP_FAILURE_RETRY(
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
getsockname(fd,
&raw.addr,
&size))) {
@@ -185,7 +188,7 @@
ASSERT(fd >= 0);
RawAddr raw;
socklen_t size = sizeof(raw);
- if (TEMP_FAILURE_RETRY(
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
getpeername(fd,
&raw.addr,
&size))) {
@@ -269,7 +272,7 @@
intptr_t host_len,
OSError** os_error) {
ASSERT(host_len >= NI_MAXHOST);
- int status = TEMP_FAILURE_RETRY(getnameinfo(
+ int status = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(getnameinfo(
&addr.addr,
SocketAddress::GetAddrLength(&addr),
host,
@@ -304,7 +307,7 @@
RawAddr* addr, intptr_t port, bool reuseAddress) {
intptr_t fd;
- fd = TEMP_FAILURE_RETRY(
+ fd = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
socket(addr->addr.sa_family, SOCK_DGRAM, IPPROTO_UDP));
if (fd < 0) return -1;
@@ -312,16 +315,16 @@
if (reuseAddress) {
int optval = 1;
- VOID_TEMP_FAILURE_RETRY(
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)));
}
SocketAddress::SetAddrPort(addr, port);
- if (TEMP_FAILURE_RETRY(
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
bind(fd,
&addr->addr,
SocketAddress::GetAddrLength(addr))) < 0) {
- VOID_TEMP_FAILURE_RETRY(close(fd));
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fd));
return -1;
}
@@ -387,27 +390,28 @@
bool v6_only) {
intptr_t fd;
- fd = TEMP_FAILURE_RETRY(socket(addr.ss.ss_family, SOCK_STREAM, 0));
+ fd = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(socket(addr.ss.ss_family, SOCK_STREAM,
+ 0));
if (fd < 0) return -1;
FDUtils::SetCloseOnExec(fd);
int optval = 1;
- VOID_TEMP_FAILURE_RETRY(
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)));
if (addr.ss.ss_family == AF_INET6) {
optval = v6_only ? 1 : 0;
- VOID_TEMP_FAILURE_RETRY(
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)));
}
SocketAddress::SetAddrPort(&addr, port);
- if (TEMP_FAILURE_RETRY(
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
bind(fd,
&addr.addr,
SocketAddress::GetAddrLength(&addr))) < 0) {
- VOID_TEMP_FAILURE_RETRY(close(fd));
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fd));
return -1;
}
@@ -417,13 +421,14 @@
// that we do not get the bad port number again.
intptr_t new_fd = CreateBindListen(addr, 0, backlog, v6_only);
int err = errno;
- VOID_TEMP_FAILURE_RETRY(close(fd));
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fd));
errno = err;
return new_fd;
}
- if (TEMP_FAILURE_RETRY(listen(fd, backlog > 0 ? backlog : SOMAXCONN)) != 0) {
- VOID_TEMP_FAILURE_RETRY(close(fd));
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
+ listen(fd, backlog > 0 ? backlog : SOMAXCONN)) != 0) {
+ VOID_TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fd));
return -1;
}
@@ -436,7 +441,7 @@
intptr_t socket;
struct sockaddr clientaddr;
socklen_t addrlen = sizeof(clientaddr);
- socket = TEMP_FAILURE_RETRY(accept(fd, &clientaddr, &addrlen));
+ socket = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(accept(fd, &clientaddr, &addrlen));
if (socket == -1) {
if (errno == EAGAIN) {
// We need to signal to the caller that this is actually not an
@@ -454,7 +459,7 @@
void Socket::Close(intptr_t fd) {
ASSERT(fd >= 0);
- int err = TEMP_FAILURE_RETRY(close(fd));
+ int err = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(close(fd));
if (err != 0) {
const int kBufferSize = 1024;
char error_message[kBufferSize];
@@ -477,7 +482,7 @@
bool Socket::GetNoDelay(intptr_t fd, bool* enabled) {
int on;
socklen_t len = sizeof(on);
- int err = TEMP_FAILURE_RETRY(getsockopt(fd,
+ int err = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(getsockopt(fd,
IPPROTO_TCP,
TCP_NODELAY,
reinterpret_cast<void *>(&on),
@@ -491,7 +496,7 @@
bool Socket::SetNoDelay(intptr_t fd, bool enabled) {
int on = enabled ? 1 : 0;
- return TEMP_FAILURE_RETRY(setsockopt(fd,
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(setsockopt(fd,
IPPROTO_TCP,
TCP_NODELAY,
reinterpret_cast<char *>(&on),
@@ -505,7 +510,7 @@
int level = protocol == SocketAddress::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6;
int optname = protocol == SocketAddress::TYPE_IPV4
? IP_MULTICAST_LOOP : IPV6_MULTICAST_LOOP;
- if (TEMP_FAILURE_RETRY(getsockopt(fd,
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(getsockopt(fd,
level,
optname,
reinterpret_cast<char *>(&on),
@@ -522,7 +527,7 @@
int level = protocol == SocketAddress::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6;
int optname = protocol == SocketAddress::TYPE_IPV4
? IP_MULTICAST_LOOP : IPV6_MULTICAST_LOOP;
- return TEMP_FAILURE_RETRY(setsockopt(fd,
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(setsockopt(fd,
level,
optname,
reinterpret_cast<char *>(&on),
@@ -536,7 +541,7 @@
int level = protocol == SocketAddress::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6;
int optname = protocol == SocketAddress::TYPE_IPV4
? IP_MULTICAST_TTL : IPV6_MULTICAST_HOPS;
- if (TEMP_FAILURE_RETRY(getsockopt(fd,
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(getsockopt(fd,
level,
optname,
reinterpret_cast<char *>(&v),
@@ -553,7 +558,7 @@
int level = protocol == SocketAddress::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6;
int optname = protocol == SocketAddress::TYPE_IPV4
? IP_MULTICAST_TTL : IPV6_MULTICAST_HOPS;
- return TEMP_FAILURE_RETRY(setsockopt(fd,
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(setsockopt(fd,
level,
optname,
reinterpret_cast<char *>(&v),
@@ -564,7 +569,7 @@
bool Socket::GetBroadcast(intptr_t fd, bool* enabled) {
int on;
socklen_t len = sizeof(on);
- int err = TEMP_FAILURE_RETRY(getsockopt(fd,
+ int err = TEMP_FAILURE_RETRY_BLOCK_SIGNALS(getsockopt(fd,
SOL_SOCKET,
SO_BROADCAST,
reinterpret_cast<char *>(&on),
@@ -578,7 +583,7 @@
bool Socket::SetBroadcast(intptr_t fd, bool enabled) {
int on = enabled ? 1 : 0;
- return TEMP_FAILURE_RETRY(setsockopt(fd,
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(setsockopt(fd,
SOL_SOCKET,
SO_BROADCAST,
reinterpret_cast<char *>(&on),
@@ -596,15 +601,15 @@
struct ip_mreq mreq;
memmove(&mreq.imr_multiaddr,
&addr->in.sin_addr,
- SocketAddress::GetAddrLength(addr));
+ SocketAddress::GetInAddrLength(addr));
memmove(&mreq.imr_interface,
&interface->in.sin_addr,
- SocketAddress::GetAddrLength(interface));
+ SocketAddress::GetInAddrLength(interface));
if (join) {
- return TEMP_FAILURE_RETRY(setsockopt(
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(setsockopt(
fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq))) == 0;
} else {
- return TEMP_FAILURE_RETRY(setsockopt(
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(setsockopt(
fd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &mreq, sizeof(mreq))) == 0;
}
} else {
@@ -612,43 +617,21 @@
struct ipv6_mreq mreq;
memmove(&mreq.ipv6mr_multiaddr,
&addr->in6.sin6_addr,
- SocketAddress::GetAddrLength(addr));
+ SocketAddress::GetInAddrLength(addr));
mreq.ipv6mr_interface = interfaceIndex;
if (join) {
- return TEMP_FAILURE_RETRY(setsockopt(
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(setsockopt(
fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq))) == 0;
} else {
- return TEMP_FAILURE_RETRY(setsockopt(
+ return TEMP_FAILURE_RETRY_BLOCK_SIGNALS(setsockopt(
fd, IPPROTO_IPV6, IPV6_LEAVE_GROUP, &mreq, sizeof(mreq))) == 0;
}
}
}
bool Socket::JoinMulticast(
- intptr_t fd, RawAddr* addr, RawAddr* interface, int interfaceIndex) {
- return JoinOrLeaveMulticast(fd, addr, interface, interfaceIndex, true);
- if (addr->addr.sa_family == AF_INET) {
- ASSERT(interface->addr.sa_family == AF_INET);
- struct ip_mreq mreq;
- memmove(&mreq.imr_multiaddr,
- &addr->in.sin_addr,
- SocketAddress::GetAddrLength(addr));
- memmove(&mreq.imr_interface,
- &interface->in.sin_addr,
- SocketAddress::GetAddrLength(interface));
- return TEMP_FAILURE_RETRY(setsockopt(
- fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &mreq, sizeof(mreq))) == 0;
- } else {
- ASSERT(addr->addr.sa_family == AF_INET6);
- ASSERT(interface->addr.sa_family == AF_INET6);
- struct ipv6_mreq mreq;
- memmove(&mreq.ipv6mr_multiaddr,
- &addr->in6.sin6_addr,
- SocketAddress::GetAddrLength(addr));
- mreq.ipv6mr_interface = interfaceIndex;
- return TEMP_FAILURE_RETRY(setsockopt(
- fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq))) == 0;
- }
+ intptr_t fd, RawAddr* addr, RawAddr* interface, int interfaceIndex) {
+ return JoinOrLeaveMulticast(fd, addr, interface, interfaceIndex, true);
}
diff --git a/runtime/bin/socket_patch.dart b/runtime/bin/socket_patch.dart
index a85320c..9076848 100644
--- a/runtime/bin/socket_patch.dart
+++ b/runtime/bin/socket_patch.dart
@@ -62,8 +62,7 @@
static const int _ADDRESS_LOOPBACK_IP_V6 = 1;
static const int _ADDRESS_ANY_IP_V4 = 2;
static const int _ADDRESS_ANY_IP_V6 = 3;
- static const int _IPV4_ADDR_OFFSET = 4;
- static const int _IPV6_ADDR_OFFSET = 8;
+ static const int _IPV4_ADDR_LENGTH = 4;
static const int _IPV6_ADDR_LENGTH = 16;
static _InternetAddress LOOPBACK_IP_V4 =
@@ -75,24 +74,26 @@
static _InternetAddress ANY_IP_V6 =
new _InternetAddress.fixed(_ADDRESS_ANY_IP_V6);
- final InternetAddressType type;
final String address;
final String _host;
- final Uint8List _sockaddr_storage;
+ final Uint8List _in_addr;
+
+ InternetAddressType get type =>
+ _in_addr.length == _IPV4_ADDR_LENGTH ? InternetAddressType.IP_V4
+ : InternetAddressType.IP_V6;
String get host => _host != null ? _host : address;
bool get isLoopback {
switch (type) {
case InternetAddressType.IP_V4:
- return _sockaddr_storage[_IPV4_ADDR_OFFSET] == 127;
+ return _in_addr[0] == 127;
case InternetAddressType.IP_V6:
for (int i = 0; i < _IPV6_ADDR_LENGTH - 1; i++) {
- if (_sockaddr_storage[_IPV6_ADDR_OFFSET + i] != 0) return false;
+ if (_in_addr[i] != 0) return false;
}
- int lastByteIndex = _IPV6_ADDR_OFFSET + _IPV6_ADDR_LENGTH - 1;
- return _sockaddr_storage[lastByteIndex] == 1;
+ return _in_addr[_IPV6_ADDR_LENGTH - 1] == 1;
}
}
@@ -100,13 +101,11 @@
switch (type) {
case InternetAddressType.IP_V4:
// Checking for 169.254.0.0/16.
- return _sockaddr_storage[_IPV4_ADDR_OFFSET] == 169 &&
- _sockaddr_storage[_IPV4_ADDR_OFFSET + 1] == 254;
+ return _in_addr[0] == 169 && _in_addr[1] == 254;
case InternetAddressType.IP_V6:
// Checking for fe80::/10.
- return _sockaddr_storage[_IPV6_ADDR_OFFSET] == 0xFE &&
- (_sockaddr_storage[_IPV6_ADDR_OFFSET + 1] & 0xB0) == 0x80;
+ return _in_addr[0] == 0xFE && (_in_addr[1] & 0xB0) == 0x80;
}
}
@@ -114,48 +113,48 @@
switch (type) {
case InternetAddressType.IP_V4:
// Checking for 224.0.0.0 through 239.255.255.255.
- return _sockaddr_storage[_IPV4_ADDR_OFFSET] >= 224 &&
- _sockaddr_storage[_IPV4_ADDR_OFFSET] < 240;
+ return _in_addr[0] >= 224 && _in_addr[0] < 240;
case InternetAddressType.IP_V6:
// Checking for ff00::/8.
- return _sockaddr_storage[_IPV6_ADDR_OFFSET] == 0xFF;
+ return _in_addr[0] == 0xFF;
}
}
Future<InternetAddress> reverse() => _NativeSocket.reverseLookup(this);
- _InternetAddress(InternetAddressType this.type,
- String this.address,
+ _InternetAddress(String this.address,
String this._host,
- List<int> this._sockaddr_storage);
+ List<int> this._in_addr);
factory _InternetAddress.parse(String address) {
- var type = address.indexOf(':') == -1
- ? InternetAddressType.IP_V4
- : InternetAddressType.IP_V6;
- var raw = _parse(type._value, address);
- if (raw == null) {
+ if (address is !String) {
throw new ArgumentError("Invalid internet address $address");
}
- return new _InternetAddress(type, address, null, raw);
+ var in_addr = _parse(address);
+ if (in_addr == null) {
+ throw new ArgumentError("Invalid internet address $address");
+ }
+ return new _InternetAddress(address, null, in_addr);
}
factory _InternetAddress.fixed(int id) {
- var sockaddr = _fixed(id);
switch (id) {
case _ADDRESS_LOOPBACK_IP_V4:
- return new _InternetAddress(
- InternetAddressType.IP_V4, "127.0.0.1", null, sockaddr);
+ var in_addr = new Uint8List(_IPV4_ADDR_LENGTH);
+ in_addr[0] = 127;
+ in_addr[_IPV4_ADDR_LENGTH - 1] = 1;
+ return new _InternetAddress("127.0.0.1", null, in_addr);
case _ADDRESS_LOOPBACK_IP_V6:
- return new _InternetAddress(
- InternetAddressType.IP_V6, "::1", null, sockaddr);
+ var in_addr = new Uint8List(_IPV6_ADDR_LENGTH);
+ in_addr[_IPV6_ADDR_LENGTH - 1] = 1;
+ return new _InternetAddress("::1", null, in_addr);
case _ADDRESS_ANY_IP_V4:
- return new _InternetAddress(
- InternetAddressType.IP_V4, "0.0.0.0", "0.0.0.0", sockaddr);
+ var in_addr = new Uint8List(_IPV4_ADDR_LENGTH);
+ return new _InternetAddress("0.0.0.0", "0.0.0.0", in_addr);
case _ADDRESS_ANY_IP_V6:
- return new _InternetAddress(
- InternetAddressType.IP_V6, "::", "::", sockaddr);
+ var in_addr = new Uint8List(_IPV6_ADDR_LENGTH);
+ return new _InternetAddress("::", "::", in_addr);
default:
assert(false);
throw new ArgumentError();
@@ -165,23 +164,23 @@
// Create a clone of this _InternetAddress replacing the host.
_InternetAddress _cloneWithNewHost(String host) {
return new _InternetAddress(
- type, address, host, new Uint8List.fromList(_sockaddr_storage));
+ address, host, new Uint8List.fromList(_in_addr));
}
bool operator ==(other) {
if (!(other is _InternetAddress)) return false;
if (other.type != type) return false;
bool equals = true;
- for (int i = 0; i < _sockaddr_storage.length && equals; i++) {
- equals = other._sockaddr_storage[i] == _sockaddr_storage[i];
+ for (int i = 0; i < _in_addr.length && equals; i++) {
+ equals = other._in_addr[i] == _in_addr[i];
}
return equals;
}
int get hashCode {
int result = 1;
- for (int i = 0; i < _sockaddr_storage.length; i++) {
- result = (result * 31 + _sockaddr_storage[i]) & 0x3FFFFFFF;
+ for (int i = 0; i < _in_addr.length; i++) {
+ result = (result * 31 + _in_addr[i]) & 0x3FFFFFFF;
}
return result;
}
@@ -190,9 +189,7 @@
return "InternetAddress('$address', ${type.name})";
}
- static Uint8List _fixed(int id) native "InternetAddress_Fixed";
- static Uint8List _parse(int type, String address)
- native "InternetAddress_Parse";
+ static Uint8List _parse(String address) native "InternetAddress_Parse";
}
class _NetworkInterface implements NetworkInterface {
@@ -284,14 +281,14 @@
} else {
return response.skip(1).map((result) {
var type = new InternetAddressType._from(result[0]);
- return new _InternetAddress(type, result[1], host, result[2]);
+ return new _InternetAddress(result[1], host, result[2]);
}).toList();
}
});
}
static Future<InternetAddress> reverseLookup(InternetAddress addr) {
- return _IOService.dispatch(_SOCKET_REVERSE_LOOKUP, [addr._sockaddr_storage])
+ return _IOService.dispatch(_SOCKET_REVERSE_LOOKUP, [addr._in_addr])
.then((response) {
if (isErrorResponse(response)) {
throw createError(response, "Failed reverse host lookup", addr);
@@ -315,8 +312,7 @@
var type = new InternetAddressType._from(result[0]);
var name = result[3];
var index = result[4];
- var address = new _InternetAddress(
- type, result[1], "", result[2]);
+ var address = new _InternetAddress(result[1], "", result[2]);
if (!includeLinkLocal && address.isLinkLocal) return map;
if (!includeLoopback && address.isLoopback) return map;
map.putIfAbsent(
@@ -345,7 +341,7 @@
var socket = new _NativeSocket.normal();
socket.address = address;
var result = socket.nativeCreateConnect(
- address._sockaddr_storage, port);
+ address._in_addr, port);
if (result is OSError) {
throw createError(result, "Connection failed", address, port);
} else {
@@ -387,7 +383,7 @@
.then((address) {
var socket = new _NativeSocket.listen();
socket.address = address;
- var result = socket.nativeCreateBindListen(address._sockaddr_storage,
+ var result = socket.nativeCreateBindListen(address._in_addr,
port,
backlog,
v6Only);
@@ -418,7 +414,7 @@
.then((address) {
var socket = new _NativeSocket.datagram(address);
var result = socket.nativeCreateBindDatagram(
- address._sockaddr_storage, port, reuseAddress);
+ address._in_addr, port, reuseAddress);
if (result is OSError) {
throw new SocketException("Failed to create datagram socket",
osError: result,
@@ -525,7 +521,7 @@
buffer, offset, bytes);
var result = nativeSendTo(
bufferAndStart.buffer, bufferAndStart.start, bytes,
- address._sockaddr_storage, port);
+ address._in_addr, port);
if (result is OSError) {
scheduleMicrotask(() => reportError(result, "Send failed"));
result = 0;
@@ -555,7 +551,7 @@
InternetAddress get remoteAddress {
var result = nativeGetRemotePeer()[0];
var type = new InternetAddressType._from(result[0]);
- return new _InternetAddress(type, result[1], null, result[2]);
+ return new _InternetAddress(result[1], null, result[2]);
}
// Multiplexes socket events to the socket handlers.
@@ -780,7 +776,7 @@
if (Platform.isMacOS && addr.type == InternetAddressType.IP_V4) {
if (interface != null) {
for (int i = 0; i < interface.addresses.length; i++) {
- if (addr.type == InternetAddressType.IP_V4) {
+ if (interface.addresses[i].type == InternetAddressType.IP_V4) {
return interface.addresses[i];
}
}
@@ -789,7 +785,7 @@
"The network interface does not have an address "
"of the same family as the multicast address");
} else {
- // Default to the ANY address if on iterface is specified.
+ // Default to the ANY address if no iterface is specified.
return InternetAddress.ANY_IP_V4;
}
} else {
@@ -801,8 +797,8 @@
var interfaceAddr = multicastAddress(addr, interface);
var interfaceIndex = interface == null ? 0 : interface.index;
var result = nativeJoinMulticast(
- addr._sockaddr_storage,
- interfaceAddr == null ? null : interfaceAddr._sockaddr_storage,
+ addr._in_addr,
+ interfaceAddr == null ? null : interfaceAddr._in_addr,
interfaceIndex);
if (result is OSError) throw result;
}
@@ -811,8 +807,8 @@
var interfaceAddr = multicastAddress(addr, interface);
var interfaceIndex = interface == null ? 0 : interface.index;
var result = nativeLeaveMulticast(
- addr._sockaddr_storage,
- interfaceAddr == null ? null : interfaceAddr._sockaddr_storage,
+ addr._in_addr,
+ interfaceAddr == null ? null : interfaceAddr._in_addr,
interfaceIndex);
if (result is OSError) throw result;
}
@@ -1551,14 +1547,11 @@
}
Datagram _makeDatagram(List<int> data,
- bool ipV6,
String address,
- List<int> sockaddr_storage,
+ List<int> in_addr,
int port) {
- var addressType =
- ipV6 ? InternetAddressType.IP_V6 : InternetAddressType.IP_V4;
return new Datagram(
data,
- new _InternetAddress(addressType, address, null, sockaddr_storage),
+ new _InternetAddress(address, null, in_addr),
port);
}
diff --git a/runtime/bin/stdin.cc b/runtime/bin/stdio.cc
similarity index 75%
rename from runtime/bin/stdin.cc
rename to runtime/bin/stdio.cc
index ef7904a..916a3b8 100644
--- a/runtime/bin/stdin.cc
+++ b/runtime/bin/stdio.cc
@@ -5,7 +5,7 @@
#include "bin/builtin.h"
#include "bin/dartutils.h"
#include "bin/utils.h"
-#include "bin/stdin.h"
+#include "bin/stdio.h"
#include "platform/globals.h"
#include "platform/thread.h"
@@ -43,5 +43,18 @@
Stdin::SetLineMode(enabled);
}
+
+void FUNCTION_NAME(Stdout_GetTerminalSize)(Dart_NativeArguments args) {
+ int size[2];
+ if (Stdout::GetTerminalSize(size)) {
+ Dart_Handle list = Dart_NewList(2);
+ Dart_ListSetAt(list, 0, Dart_NewInteger(size[0]));
+ Dart_ListSetAt(list, 1, Dart_NewInteger(size[1]));
+ Dart_SetReturnValue(args, list);
+ } else {
+ Dart_SetReturnValue(args, DartUtils::NewDartOSError());
+ }
+}
+
} // namespace bin
} // namespace dart
diff --git a/runtime/bin/stdin.h b/runtime/bin/stdio.h
similarity index 74%
rename from runtime/bin/stdin.h
rename to runtime/bin/stdio.h
index a0c6875..646629d 100644
--- a/runtime/bin/stdin.h
+++ b/runtime/bin/stdio.h
@@ -2,8 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-#ifndef BIN_STDIN_H_
-#define BIN_STDIN_H_
+#ifndef BIN_STDIO_H_
+#define BIN_STDIO_H_
#include "bin/builtin.h"
#include "bin/utils.h"
@@ -29,8 +29,18 @@
DISALLOW_IMPLICIT_CONSTRUCTORS(Stdin);
};
+
+class Stdout {
+ public:
+ static bool GetTerminalSize(int size[2]);
+
+ private:
+ DISALLOW_ALLOCATION();
+ DISALLOW_IMPLICIT_CONSTRUCTORS(Stdout);
+};
+
} // namespace bin
} // namespace dart
-#endif // BIN_STDIN_H_
+#endif // BIN_STDIO_H_
diff --git a/runtime/bin/stdin_android.cc b/runtime/bin/stdio_android.cc
similarity index 61%
rename from runtime/bin/stdin_android.cc
rename to runtime/bin/stdio_android.cc
index a1a4d63..b14dad8 100644
--- a/runtime/bin/stdin_android.cc
+++ b/runtime/bin/stdio_android.cc
@@ -5,61 +5,76 @@
#include "platform/globals.h"
#if defined(TARGET_OS_ANDROID)
+#include <errno.h> // NOLINT
+#include <sys/ioctl.h> // NOLINT
#include <termios.h> // NOLINT
-#include "bin/stdin.h"
+#include "bin/stdio.h"
#include "bin/fdutils.h"
+#include "bin/signal_blocker.h"
namespace dart {
namespace bin {
int Stdin::ReadByte() {
- FDUtils::SetBlocking(fileno(stdin));
+ FDUtils::SetBlocking(STDIN_FILENO);
int c = getchar();
if (c == EOF) {
c = -1;
}
- FDUtils::SetNonBlocking(fileno(stdin));
+ FDUtils::SetNonBlocking(STDIN_FILENO);
return c;
}
bool Stdin::GetEchoMode() {
struct termios term;
- tcgetattr(fileno(stdin), &term);
+ tcgetattr(STDIN_FILENO, &term);
return (term.c_lflag & ECHO) != 0;
}
void Stdin::SetEchoMode(bool enabled) {
struct termios term;
- tcgetattr(fileno(stdin), &term);
+ tcgetattr(STDIN_FILENO, &term);
if (enabled) {
term.c_lflag |= ECHO|ECHONL;
} else {
term.c_lflag &= ~(ECHO|ECHONL);
}
- tcsetattr(fileno(stdin), TCSANOW, &term);
+ tcsetattr(STDIN_FILENO, TCSANOW, &term);
}
bool Stdin::GetLineMode() {
struct termios term;
- tcgetattr(fileno(stdin), &term);
+ tcgetattr(STDIN_FILENO, &term);
return (term.c_lflag & ICANON) != 0;
}
void Stdin::SetLineMode(bool enabled) {
struct termios term;
- tcgetattr(fileno(stdin), &term);
+ tcgetattr(STDIN_FILENO, &term);
if (enabled) {
term.c_lflag |= ICANON;
} else {
term.c_lflag &= ~(ICANON);
}
- tcsetattr(fileno(stdin), TCSANOW, &term);
+ tcsetattr(STDIN_FILENO, TCSANOW, &term);
+}
+
+
+bool Stdout::GetTerminalSize(int size[2]) {
+ struct winsize w;
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
+ ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != 0)) {
+ return false;
+ }
+ size[0] = w.ws_col;
+ size[1] = w.ws_row;
+ return true;
}
} // namespace bin
diff --git a/runtime/bin/stdin_linux.cc b/runtime/bin/stdio_linux.cc
similarity index 61%
rename from runtime/bin/stdin_linux.cc
rename to runtime/bin/stdio_linux.cc
index c64610a..5d1739a 100644
--- a/runtime/bin/stdin_linux.cc
+++ b/runtime/bin/stdio_linux.cc
@@ -5,61 +5,76 @@
#include "platform/globals.h"
#if defined(TARGET_OS_LINUX)
+#include <errno.h> // NOLINT
+#include <sys/ioctl.h> // NOLINT
#include <termios.h> // NOLINT
-#include "bin/stdin.h"
+#include "bin/stdio.h"
#include "bin/fdutils.h"
+#include "bin/signal_blocker.h"
namespace dart {
namespace bin {
int Stdin::ReadByte() {
- FDUtils::SetBlocking(fileno(stdin));
+ FDUtils::SetBlocking(STDIN_FILENO);
int c = getchar();
if (c == EOF) {
c = -1;
}
- FDUtils::SetNonBlocking(fileno(stdin));
+ FDUtils::SetNonBlocking(STDIN_FILENO);
return c;
}
bool Stdin::GetEchoMode() {
struct termios term;
- tcgetattr(fileno(stdin), &term);
+ tcgetattr(STDIN_FILENO, &term);
return (term.c_lflag & ECHO) != 0;
}
void Stdin::SetEchoMode(bool enabled) {
struct termios term;
- tcgetattr(fileno(stdin), &term);
+ tcgetattr(STDIN_FILENO, &term);
if (enabled) {
term.c_lflag |= ECHO|ECHONL;
} else {
term.c_lflag &= ~(ECHO|ECHONL);
}
- tcsetattr(fileno(stdin), TCSANOW, &term);
+ tcsetattr(STDIN_FILENO, TCSANOW, &term);
}
bool Stdin::GetLineMode() {
struct termios term;
- tcgetattr(fileno(stdin), &term);
+ tcgetattr(STDIN_FILENO, &term);
return (term.c_lflag & ICANON) != 0;
}
void Stdin::SetLineMode(bool enabled) {
struct termios term;
- tcgetattr(fileno(stdin), &term);
+ tcgetattr(STDIN_FILENO, &term);
if (enabled) {
term.c_lflag |= ICANON;
} else {
term.c_lflag &= ~(ICANON);
}
- tcsetattr(fileno(stdin), TCSANOW, &term);
+ tcsetattr(STDIN_FILENO, TCSANOW, &term);
+}
+
+
+bool Stdout::GetTerminalSize(int size[2]) {
+ struct winsize w;
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
+ ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != 0)) {
+ return false;
+ }
+ size[0] = w.ws_col;
+ size[1] = w.ws_row;
+ return true;
}
} // namespace bin
diff --git a/runtime/bin/stdin_macos.cc b/runtime/bin/stdio_macos.cc
similarity index 61%
rename from runtime/bin/stdin_macos.cc
rename to runtime/bin/stdio_macos.cc
index a8afb77..623463a 100644
--- a/runtime/bin/stdin_macos.cc
+++ b/runtime/bin/stdio_macos.cc
@@ -5,65 +5,79 @@
#include "platform/globals.h"
#if defined(TARGET_OS_MACOS)
+#include <errno.h> // NOLINT
+#include <sys/ioctl.h> // NOLINT
#include <termios.h> // NOLINT
-#include "bin/stdin.h"
+#include "bin/stdio.h"
#include "bin/fdutils.h"
+#include "bin/signal_blocker.h"
namespace dart {
namespace bin {
int Stdin::ReadByte() {
- FDUtils::SetBlocking(fileno(stdin));
+ FDUtils::SetBlocking(STDIN_FILENO);
int c = getchar();
if (c == EOF) {
c = -1;
}
- FDUtils::SetNonBlocking(fileno(stdin));
+ FDUtils::SetNonBlocking(STDIN_FILENO);
return c;
}
bool Stdin::GetEchoMode() {
struct termios term;
- tcgetattr(fileno(stdin), &term);
+ tcgetattr(STDIN_FILENO, &term);
return (term.c_lflag & ECHO) != 0;
}
void Stdin::SetEchoMode(bool enabled) {
struct termios term;
- tcgetattr(fileno(stdin), &term);
+ tcgetattr(STDIN_FILENO, &term);
if (enabled) {
term.c_lflag |= ECHO|ECHONL;
} else {
term.c_lflag &= ~(ECHO|ECHONL);
}
- tcsetattr(fileno(stdin), TCSANOW, &term);
+ tcsetattr(STDIN_FILENO, TCSANOW, &term);
}
bool Stdin::GetLineMode() {
struct termios term;
- tcgetattr(fileno(stdin), &term);
+ tcgetattr(STDIN_FILENO, &term);
return (term.c_lflag & ICANON) != 0;
}
void Stdin::SetLineMode(bool enabled) {
struct termios term;
- tcgetattr(fileno(stdin), &term);
+ tcgetattr(STDIN_FILENO, &term);
if (enabled) {
term.c_lflag |= ICANON;
} else {
term.c_lflag &= ~(ICANON);
}
- tcsetattr(fileno(stdin), TCSANOW, &term);
+ tcsetattr(STDIN_FILENO, TCSANOW, &term);
+}
+
+
+bool Stdout::GetTerminalSize(int size[2]) {
+ struct winsize w;
+ if (TEMP_FAILURE_RETRY_BLOCK_SIGNALS(
+ ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) != 0)) {
+ return false;
+ }
+ size[0] = w.ws_col;
+ size[1] = w.ws_row;
+ return true;
}
} // namespace bin
} // namespace dart
#endif // defined(TARGET_OS_MACOS)
-
diff --git a/runtime/bin/stdio_patch.dart b/runtime/bin/stdio_patch.dart
index 5d5cdaf..2364281 100644
--- a/runtime/bin/stdio_patch.dart
+++ b/runtime/bin/stdio_patch.dart
@@ -16,15 +16,22 @@
}
}
- static IOSink _getStdioOutputStream(int fd) {
+ static _getStdioOutputStream(int fd) {
+ wrap(sink) {
+ if (fd == 1) {
+ return new Stdout._(sink);
+ } else {
+ return new _StdSink(sink);
+ }
+ }
assert(fd == 1 || fd == 2);
switch (_getStdioHandleType(fd)) {
case _STDIO_HANDLE_TYPE_TERMINAL:
case _STDIO_HANDLE_TYPE_PIPE:
case _STDIO_HANDLE_TYPE_SOCKET:
- return new _StdSink(new _Socket._writePipe(fd));
+ return wrap(new _Socket._writePipe(fd));
case _STDIO_HANDLE_TYPE_FILE:
- return new _StdSink(new IOSink(new _FileStreamConsumer.fromStdio(fd)));
+ return wrap(new IOSink(new _FileStreamConsumer.fromStdio(fd)));
default:
throw new FileSystemException("Unsupported stdin type");
}
@@ -54,6 +61,30 @@
static void set _lineMode(bool enabled) native "Stdin_SetLineMode";
}
+patch class Stdout {
+ /* patch */ bool get hasTerminal {
+ try {
+ _terminalSize;
+ return true;
+ } catch (_) {
+ return false;
+ }
+ }
+
+ /* patch */ int get terminalColumns => _terminalSize[0];
+ /* patch */ int get terminalLines => _terminalSize[1];
+
+ static List get _terminalSize {
+ var size = _getTerminalSize();
+ if (size is! List) {
+ throw new StdoutException("Could not get terminal size", size);
+ }
+ return size;
+ }
+
+ static _getTerminalSize() native "Stdout_GetTerminalSize";
+}
+
_getStdioHandle(_NativeSocket socket, int num) native "Socket_GetStdioHandle";
_getStdioHandleType(int num) native "File_GetStdioHandleType";
diff --git a/runtime/bin/stdin_win.cc b/runtime/bin/stdio_win.cc
similarity index 81%
rename from runtime/bin/stdin_win.cc
rename to runtime/bin/stdio_win.cc
index 44e517d..24ceb32 100644
--- a/runtime/bin/stdin_win.cc
+++ b/runtime/bin/stdio_win.cc
@@ -5,7 +5,7 @@
#include "platform/globals.h"
#if defined(TARGET_OS_WINDOWS)
-#include "bin/stdin.h"
+#include "bin/stdio.h"
namespace dart {
@@ -64,6 +64,16 @@
SetConsoleMode(h, mode);
}
+
+bool Stdout::GetTerminalSize(int size[2]) {
+ HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
+ CONSOLE_SCREEN_BUFFER_INFO info;
+ if (!GetConsoleScreenBufferInfo(h, &info)) return false;
+ size[0] = info.srWindow.Right - info.srWindow.Left + 1;
+ size[1] = info.srWindow.Bottom - info.srWindow.Top + 1;
+ return true;
+}
+
} // namespace bin
} // namespace dart
diff --git a/runtime/bin/test_extension.c b/runtime/bin/test_extension.c
index a08a5fe..82387a2 100644
--- a/runtime/bin/test_extension.c
+++ b/runtime/bin/test_extension.c
@@ -32,11 +32,17 @@
/* Native resolver for the extension library. */
-Dart_NativeFunction ResolveName(Dart_Handle name, int argc) {
+Dart_NativeFunction ResolveName(Dart_Handle name,
+ int argc,
+ bool* auto_setup_scope) {
/* assert(Dart_IsString(name)); */
const char* c_name;
Dart_Handle check_error;
+ if (auto_setup_scope == NULL) {
+ return NULL;
+ }
+ *auto_setup_scope = 1;
check_error = Dart_StringToCString(name, &c_name);
if (Dart_IsError(check_error)) {
Dart_PropagateError(check_error);
diff --git a/runtime/bin/utils_android.cc b/runtime/bin/utils_android.cc
index e88d248..615dae9 100644
--- a/runtime/bin/utils_android.cc
+++ b/runtime/bin/utils_android.cc
@@ -8,6 +8,7 @@
#include <errno.h> // NOLINT
#include <netdb.h> // NOLINT
#include <sys/time.h> // NOLINT
+#include <time.h> // NOLINT
#include "bin/utils.h"
#include "platform/assert.h"
@@ -98,7 +99,24 @@
}
void TimerUtils::Sleep(int64_t millis) {
- usleep(millis * 1000);
+ struct timespec req; // requested.
+ struct timespec rem; // remainder.
+ int64_t micros = millis * kMicrosecondsPerMillisecond;
+ int64_t seconds = micros / kMicrosecondsPerSecond;
+ micros = micros - seconds * kMicrosecondsPerSecond;
+ int64_t nanos = micros * kNanosecondsPerMicrosecond;
+ req.tv_sec = seconds;
+ req.tv_nsec = nanos;
+ while (true) {
+ int r = nanosleep(&req, &rem);
+ if (r == 0) {
+ break;
+ }
+ // We should only ever see an interrupt error.
+ ASSERT(errno == EINTR);
+ // Copy remainder into requested and repeat.
+ req = rem;
+ }
}
} // namespace bin
diff --git a/runtime/bin/utils_linux.cc b/runtime/bin/utils_linux.cc
index 4506f6f..ce35eb7 100644
--- a/runtime/bin/utils_linux.cc
+++ b/runtime/bin/utils_linux.cc
@@ -8,6 +8,7 @@
#include <errno.h> // NOLINT
#include <netdb.h> // NOLINT
#include <sys/time.h> // NOLINT
+#include <time.h> // NOLINT
#include "bin/utils.h"
#include "platform/assert.h"
@@ -96,16 +97,23 @@
}
void TimerUtils::Sleep(int64_t millis) {
- // We must loop here because SIGPROF will interrupt usleep.
- int64_t micros = millis * 1000;
- int64_t start = GetCurrentTimeMicros();
- while (micros > 0) {
- usleep(micros);
- int64_t now = GetCurrentTimeMicros();
- int64_t delta = now - start;
- ASSERT(delta >= 0);
- start = now;
- micros -= delta;
+ struct timespec req; // requested.
+ struct timespec rem; // remainder.
+ int64_t micros = millis * kMicrosecondsPerMillisecond;
+ int64_t seconds = micros / kMicrosecondsPerSecond;
+ micros = micros - seconds * kMicrosecondsPerSecond;
+ int64_t nanos = micros * kNanosecondsPerMicrosecond;
+ req.tv_sec = seconds;
+ req.tv_nsec = nanos;
+ while (true) {
+ int r = nanosleep(&req, &rem);
+ if (r == 0) {
+ break;
+ }
+ // We should only ever see an interrupt error.
+ ASSERT(errno == EINTR);
+ // Copy remainder into requested and repeat.
+ req = rem;
}
}
diff --git a/runtime/bin/utils_macos.cc b/runtime/bin/utils_macos.cc
index 1c83afd..460da35 100644
--- a/runtime/bin/utils_macos.cc
+++ b/runtime/bin/utils_macos.cc
@@ -8,6 +8,7 @@
#include <errno.h> // NOLINT
#include <netdb.h> // NOLINT
#include <sys/time.h> // NOLINT
+#include <time.h> // NOLINT
#include "bin/utils.h"
#include "platform/assert.h"
@@ -98,16 +99,23 @@
}
void TimerUtils::Sleep(int64_t millis) {
- // We must loop here because SIGPROF will interrupt usleep.
- int64_t micros = millis * 1000;
- int64_t start = GetCurrentTimeMicros();
- while (micros > 0) {
- usleep(micros);
- int64_t now = GetCurrentTimeMicros();
- int64_t delta = now - start;
- ASSERT(delta >= 0);
- start = now;
- micros -= delta;
+ struct timespec req; // requested.
+ struct timespec rem; // remainder.
+ int64_t micros = millis * kMicrosecondsPerMillisecond;
+ int64_t seconds = micros / kMicrosecondsPerSecond;
+ micros = micros - seconds * kMicrosecondsPerSecond;
+ int64_t nanos = micros * kNanosecondsPerMicrosecond;
+ req.tv_sec = seconds;
+ req.tv_nsec = nanos;
+ while (true) {
+ int r = nanosleep(&req, &rem);
+ if (r == 0) {
+ break;
+ }
+ // We should only ever see an interrupt error.
+ ASSERT(errno == EINTR);
+ // Copy remainder into requested and repeat.
+ req = rem;
}
}
diff --git a/runtime/bin/vmservice/client.dart b/runtime/bin/vmservice/client.dart
new file mode 100644
index 0000000..553fa1f
--- /dev/null
+++ b/runtime/bin/vmservice/client.dart
@@ -0,0 +1,43 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of vmservice;
+
+// A service client.
+abstract class Client {
+ /// Port that lives as long as the network client.
+ final RawReceivePort receivePort = new RawReceivePort();
+ final VMService service;
+
+ Client(this.service) {
+ receivePort.handler = (response) {
+ post(null, response);
+ };
+ service._addClient(this);
+ }
+
+ /// When implementing, call [close] when the network connection closes.
+ void close() {
+ receivePort.close();
+ service._removeClient(this);
+ }
+
+ /// Call to process a message. Response will be posted with 'seq'.
+ void onMessage(var seq, Message message) {
+ // Call post when the response arrives.
+ message.response.then((response) {
+ post(seq, response);
+ });
+ // Send message to service.
+ service.route(message);
+ }
+
+ /// When implementing, responsible for sending [response] to the client.
+ void post(var seq, String response);
+
+ dynamic toJson() {
+ return {
+ };
+ }
+}
diff --git a/runtime/bin/vmservice/client/deployed/web/index.html b/runtime/bin/vmservice/client/deployed/web/index.html
index a0437be..b226dd5 100644
--- a/runtime/bin/vmservice/client/deployed/web/index.html
+++ b/runtime/bin/vmservice/client/deployed/web/index.html
@@ -11,6 +11,24 @@
</head>
<body><polymer-element name="observatory-element">
+</polymer-element><polymer-element name="breakpoint-list" extends="observatory-element">
+ <template>
+ <template if="{{ msg['breakpoints'].isEmpty }}">
+ <div class="panel panel-warning">
+ <div class="panel-body">No breakpoints</div>
+ </div>
+ </template>
+ <template if="{{ msg['breakpoints'].isNotEmpty }}">
+ <ul class="list-group">
+ <template repeat="{{ bpt in msg['breakpoints'] }}">
+ <li class="list-group-item">
+ {{ bpt }}
+ </li>
+ </template>
+ </ul>
+ </template>
+ </template>
+
</polymer-element><polymer-element name="error-view" extends="observatory-element">
<template>
<div class="row">
@@ -297,6 +315,9 @@
<div class="col-md-1">
<a href="{{ app.locationManager.relativeLink(isolate, 'library') }}">Library</a>
</div>
+ <div class="col-md-1">
+ <a href="{{ app.locationManager.relativeLink(isolate, 'debug/breakpoints') }}">Breakpoints</a>
+ </div>
<div class="col-md-8"></div>
</div>
</template>
@@ -514,6 +535,9 @@
<template if="{{ messageType == 'StackTrace' }}">
<stack-trace app="{{ app }}" trace="{{ message }}"></stack-trace>
</template>
+ <template if="{{ messageType == 'BreakpointList' }}">
+ <breakpoint-list app="{{ app }}" msg="{{ message }}"></breakpoint-list>
+ </template>
<!-- If the message type is a RequestError -->
<template if="{{ messageType == 'RequestError' }}">
<error-view app="{{ app }}" error="{{ message['error'] }}"></error-view>
diff --git a/runtime/bin/vmservice/client/deployed/web/index.html_bootstrap.dart.js b/runtime/bin/vmservice/client/deployed/web/index.html_bootstrap.dart.js
index a67ecba..1dd1331 100644
--- a/runtime/bin/vmservice/client/deployed/web/index.html_bootstrap.dart.js
+++ b/runtime/bin/vmservice/client/deployed/web/index.html_bootstrap.dart.js
@@ -7782,7 +7782,7 @@
$$.Y7=[A,{"":"v;wc,nn,lv,Pp",
call$2:function(a,b){return this.nn.call(this.wc,this.lv,a,b)},
$is_bh:true}]
-$$.Dw=[T,{"":"v;wc,nn,lv,Pp",
+$$.PD=[T,{"":"v;wc,nn,lv,Pp",
call$3:function(a,b,c){return this.nn.call(this.wc,a,b,c)}}]
$$.zy=[H,{"":"Tp;call$2,$name",$is_bh:true}]
$$.Nb=[H,{"":"Tp;call$1,$name",$is_HB:true,$is_Dv:true}]
@@ -7805,7 +7805,7 @@
call$catchAll:function(){return{onError:null,radix:null}},
$is_HB:true,
$is_Dv:true}]
-;init.mangledNames={gB:"length",gDb:"_cachedDeclarations",gEI:"prefix",gF1:"isolate",gFF:"source",gFJ:"__$cls",gFT:"__$instruction",gFU:"_cachedMethodsMap",gG1:"message",gH8:"_fieldsDescriptor",gHt:"_fieldsMetadata",gKM:"$",gLA:"src",gLf:"__$field",gLy:"_cachedSetters",gM2:"_cachedVariables",gMj:"function",gNI:"instruction",gNl:"script",gO3:"url",gOk:"_cachedMetadata",gP:"value",gP2:"_collapsed",gPw:"__$isolate",gPy:"__$error",gQG:"app",gRu:"cls",gT1:"_cachedGetters",gTn:"json",gTx:"_jsConstructorOrInterceptor",gUF:"_cachedTypeVariables",gUz:"__$script",gV4:"__$trace",gVA:"__$displayValue",gVB:"error_obj",gWL:"_mangledName",gXB:"_message",gXJ:"lines",gXR:"scripts",gXf:"__$iconClass",gXh:"__$instance",gZ6:"locationManager",gZw:"__$code",ga:"a",gai:"displayValue",gb:"b",gb0:"_cachedConstructors",gcC:"hash",geV:"paddedLine",geb:"__$json",gfY:"kind",ghO:"__$error_obj",ghf:"instance",gi0:"__$name",gi2:"isolates",giI:"__$library",giK:"__$instance",gjO:"id",gjd:"_cachedMethods",gk5:"__$devtools",gkc:"error",gkf:"_count",gl7:"iconClass",glD:"currentHashUri",gle:"_metadata",glw:"requestManager",gn2:"responses",gnI:"isolateManager",gnz:"_owner",goc:"name",gpz:"_jsConstructorCache",gqN:"_superclass",gql:"__$function",gqm:"_cachedSuperinterfaces",gt0:"field",gtB:"_cachedFields",gtD:"library",gtH:"__$app",gtN:"trace",gtT:"code",guA:"_cachedMembers",gvH:"index",gvX:"__$source",gvt:"__$field",gxj:"collapsed",gzd:"currentHash",gzj:"devtools"};init.mangledGlobalNames={DI:"_closeIconClass",Vl:"_openIconClass"};(function (reflectionData) {
+;init.mangledNames={gB:"length",gDb:"_cachedDeclarations",gEI:"prefix",gF1:"isolate",gFF:"source",gFJ:"__$cls",gFT:"__$instruction",gFU:"_cachedMethodsMap",gG1:"message",gH8:"_fieldsDescriptor",gHt:"_fieldsMetadata",gKM:"$",gLA:"src",gLf:"__$field",gLy:"_cachedSetters",gM2:"_cachedVariables",gMj:"function",gNI:"instruction",gNl:"script",gO3:"url",gOk:"_cachedMetadata",gP:"value",gP2:"_collapsed",gPw:"__$isolate",gPy:"__$error",gQG:"app",gRu:"cls",gT1:"_cachedGetters",gTn:"json",gTx:"_jsConstructorOrInterceptor",gUF:"_cachedTypeVariables",gUz:"__$script",gV4:"__$trace",gVA:"__$displayValue",gVB:"error_obj",gWL:"_mangledName",gXB:"_message",gXJ:"lines",gXR:"scripts",gXf:"__$iconClass",gXh:"__$instance",gZ6:"locationManager",gZw:"__$code",ga:"a",gai:"displayValue",gb:"b",gb0:"_cachedConstructors",gcC:"hash",geE:"__$msg",geV:"paddedLine",geb:"__$json",gfY:"kind",ghO:"__$error_obj",ghf:"instance",gi0:"__$name",gi2:"isolates",giI:"__$library",giK:"__$instance",gjO:"id",gjd:"_cachedMethods",gk5:"__$devtools",gkc:"error",gkf:"_count",gl7:"iconClass",glD:"currentHashUri",gle:"_metadata",glw:"requestManager",gn2:"responses",gnI:"isolateManager",gnz:"_owner",goc:"name",gpz:"_jsConstructorCache",gqN:"_superclass",gql:"__$function",gqm:"_cachedSuperinterfaces",grs:"msg",gt0:"field",gtB:"_cachedFields",gtD:"library",gtH:"__$app",gtN:"trace",gtT:"code",guA:"_cachedMembers",gvH:"index",gvX:"__$source",gvt:"__$field",gxj:"collapsed",gzd:"currentHash",gzj:"devtools"};init.mangledGlobalNames={DI:"_closeIconClass",Vl:"_openIconClass"};(function (reflectionData) {
function map(x){x={x:x};delete x.x;return x}
if (!init.libraries) init.libraries = [];
if (!init.mangledNames) init.mangledNames = map();
@@ -9438,14 +9438,38 @@
t:function(a,b){if(!J.xC(b,0))H.vh(P.N(b))
return this.zO},
"+[]:1:0":0,
-$isOd:true}}],["app_bootstrap","index.html_bootstrap.dart",,E,{E2:function(){$.x2=["package:observatory/src/observatory_elements/observatory_element.dart","package:observatory/src/observatory_elements/error_view.dart","package:observatory/src/observatory_elements/field_ref.dart","package:observatory/src/observatory_elements/instance_ref.dart","package:observatory/src/observatory_elements/class_view.dart","package:observatory/src/observatory_elements/disassembly_entry.dart","package:observatory/src/observatory_elements/code_view.dart","package:observatory/src/observatory_elements/collapsible_content.dart","package:observatory/src/observatory_elements/field_view.dart","package:observatory/src/observatory_elements/function_view.dart","package:observatory/src/observatory_elements/isolate_summary.dart","package:observatory/src/observatory_elements/isolate_list.dart","package:observatory/src/observatory_elements/instance_view.dart","package:observatory/src/observatory_elements/json_view.dart","package:observatory/src/observatory_elements/library_view.dart","package:observatory/src/observatory_elements/source_view.dart","package:observatory/src/observatory_elements/script_view.dart","package:observatory/src/observatory_elements/stack_trace.dart","package:observatory/src/observatory_elements/message_viewer.dart","package:observatory/src/observatory_elements/navigation_bar.dart","package:observatory/src/observatory_elements/response_viewer.dart","package:observatory/src/observatory_elements/observatory_application.dart","index.html.0.dart"]
+$isOd:true}}],["app_bootstrap","index.html_bootstrap.dart",,E,{E2:function(){$.x2=["package:observatory/src/observatory_elements/observatory_element.dart","package:observatory/src/observatory_elements/breakpoint_list.dart","package:observatory/src/observatory_elements/error_view.dart","package:observatory/src/observatory_elements/field_ref.dart","package:observatory/src/observatory_elements/instance_ref.dart","package:observatory/src/observatory_elements/class_view.dart","package:observatory/src/observatory_elements/disassembly_entry.dart","package:observatory/src/observatory_elements/code_view.dart","package:observatory/src/observatory_elements/collapsible_content.dart","package:observatory/src/observatory_elements/field_view.dart","package:observatory/src/observatory_elements/function_view.dart","package:observatory/src/observatory_elements/isolate_summary.dart","package:observatory/src/observatory_elements/isolate_list.dart","package:observatory/src/observatory_elements/instance_view.dart","package:observatory/src/observatory_elements/json_view.dart","package:observatory/src/observatory_elements/library_view.dart","package:observatory/src/observatory_elements/source_view.dart","package:observatory/src/observatory_elements/script_view.dart","package:observatory/src/observatory_elements/stack_trace.dart","package:observatory/src/observatory_elements/message_viewer.dart","package:observatory/src/observatory_elements/navigation_bar.dart","package:observatory/src/observatory_elements/response_viewer.dart","package:observatory/src/observatory_elements/observatory_application.dart","index.html.0.dart"]
$.uP=!1
-A.Ok()}},1],["class_view_element","package:observatory/src/observatory_elements/class_view.dart",,Z,{aC:{"":["Vf;FJ%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+A.Ok()}},1],["breakpoint_list_element","package:observatory/src/observatory_elements/breakpoint_list.dart",,B,{G6:{"":["Vf;eE%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+grs:function(a){return a.eE
+"38,39,40"},
+"+msg":1,
+srs:function(a,b){a.eE=this.pD(a,C.Ry,a.eE,b)
+"41,32,38,39"},
+"+msg=":1,
+"@":function(){return[C.PT]},
+static:{Dw:function(a){var z,y,x,w,v,u
+z=H.B7([],P.L5(null,null,null,null,null))
+z=R.Jk(z)
+y=$.Nd()
+x=P.Py(null,null,null,J.O,W.I0)
+w=J.O
+v=W.cv
+u=new V.br(P.Py(null,null,null,w,v),null,null)
+H.VM(u,[w,v])
+a.eE=z
+a.Ye=y
+a.mT=x
+a.KM=u
+C.J0.ZL(a)
+C.J0.FH(a)
+return a
+"9"},"+new BreakpointListElement$created:0:0":1}},"+BreakpointListElement": [42],Vf:{"":"uL+Pi;",$isd3:true}}],["class_view_element","package:observatory/src/observatory_elements/class_view.dart",,Z,{aC:{"":["tu;FJ%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gRu:function(a){return a.FJ
-"37,38,39"},
+"38,39,40"},
"+cls":1,
sRu:function(a,b){a.FJ=this.pD(a,C.XA,a.FJ,b)
-"40,31,37,38"},
+"41,32,38,39"},
"+cls=":1,
"@":function(){return[C.aQ]},
static:{zg:function(a){var z,y,x,w,v
@@ -9461,12 +9485,12 @@
C.kk.ZL(a)
C.kk.FH(a)
return a
-"9"},"+new ClassViewElement$created:0:0":1}},"+ClassViewElement": [41],Vf:{"":"uL+Pi;",$isd3:true}}],["code_view_element","package:observatory/src/observatory_elements/code_view.dart",,F,{Be:{"":["tu;Zw%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"10"},"+new ClassViewElement$created:0:0":1}},"+ClassViewElement": [43],tu:{"":"uL+Pi;",$isd3:true}}],["code_view_element","package:observatory/src/observatory_elements/code_view.dart",,F,{Be:{"":["Vc;Zw%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gtT:function(a){return a.Zw
-"37,38,39"},
+"38,39,40"},
"+code":1,
stT:function(a,b){a.Zw=this.pD(a,C.b1,a.Zw,b)
-"40,31,37,38"},
+"41,32,38,39"},
"+code=":1,
grK:function(a){var z=a.Zw
if(z!=null&&J.UQ(z,"is_optimized")!=null)return"panel panel-success"
@@ -9490,41 +9514,41 @@
C.YD.ZL(a)
C.YD.FH(a)
return a
-"10"},"+new CodeViewElement$created:0:0":1}},"+CodeViewElement": [42],tu:{"":"uL+Pi;",$isd3:true}}],["collapsible_content_element","package:observatory/src/observatory_elements/collapsible_content.dart",,R,{i6:{"":["Vc;Xf%-,VA%-,P2%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"11"},"+new CodeViewElement$created:0:0":1}},"+CodeViewElement": [44],Vc:{"":"uL+Pi;",$isd3:true}}],["collapsible_content_element","package:observatory/src/observatory_elements/collapsible_content.dart",,R,{i6:{"":["WZ;Xf%-,VA%-,P2%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gl7:function(a){return a.Xf
-"8,38,43"},
+"8,39,45"},
"+iconClass":1,
sl7:function(a,b){a.Xf=this.pD(a,C.Di,a.Xf,b)
-"40,31,8,38"},
+"41,32,8,39"},
"+iconClass=":1,
gai:function(a){return a.VA
-"8,38,43"},
+"8,39,45"},
"+displayValue":1,
sai:function(a,b){a.VA=this.pD(a,C.Jw,a.VA,b)
-"40,31,8,38"},
+"41,32,8,39"},
"+displayValue=":1,
gxj:function(a){return a.P2
-"44"},
+"46"},
"+collapsed":1,
sxj:function(a,b){a.P2=b
this.dR(a)
-"40,45,44"},
+"41,47,46"},
"+collapsed=":1,
i4:function(a){Z.uL.prototype.i4.call(this,a)
this.dR(a)
-"40"},
+"41"},
"+enteredView:0:0":1,
rS:function(a,b,c,d){a.P2=a.P2!==!0
this.dR(a)
this.dR(a)
-"40,46,47,48,40,49,50"},
+"41,48,49,50,41,51,52"},
"+toggleDisplay:3:0":1,
dR:function(a){var z,y
z=a.P2
y=a.Xf
if(z===!0){a.Xf=this.pD(a,C.Di,y,"glyphicon glyphicon-chevron-down")
a.VA=this.pD(a,C.Jw,a.VA,"none")}else{a.Xf=this.pD(a,C.Di,y,"glyphicon glyphicon-chevron-up")
-a.VA=this.pD(a,C.Jw,a.VA,"block")}"40"},
+a.VA=this.pD(a,C.Jw,a.VA,"block")}"41"},
"+_refresh:0:0":1,
"@":function(){return[C.Gu]},
static:{"":"Vl<-,DI<-",IT:function(a){var z,y,x,w,v
@@ -9543,7 +9567,7 @@
C.j8.ZL(a)
C.j8.FH(a)
return a
-"11"},"+new CollapsibleContentElement$created:0:0":1}},"+CollapsibleContentElement": [51],Vc:{"":"uL+Pi;",$isd3:true}}],["custom_element.polyfill","package:custom_element/polyfill.dart",,B,{G9:function(){if($.LX()==null)return!0
+"12"},"+new CollapsibleContentElement$created:0:0":1}},"+CollapsibleContentElement": [53],WZ:{"":"uL+Pi;",$isd3:true}}],["custom_element.polyfill","package:custom_element/polyfill.dart",,B,{G9:function(){if($.LX()==null)return!0
var z=J.UQ($.LX(),"CustomElements")
if(z==null)return"register" in document
return J.xC(J.UQ(z,"ready"),!0)},zO:{"":"Tp;",
@@ -10111,7 +10135,7 @@
if(typeof y==="object"&&y!==null&&!!z.$isZk)if(!("$reflectable" in y.dl))H.Hz(J.Z0(a))
return H.vn(y.qj(b,c))},
"+invoke:3:0":0,
-"*invoke":[40],
+"*invoke":[41],
CI:function(a,b){return this.F2(a,b,null)},
"+invoke:2:0":0,
Z0:function(a){return $[a]},
@@ -10251,7 +10275,7 @@
"+declarations":0,
F2:function(a,b,c){throw H.b(P.lr(this,a,b,c,null))},
"+invoke:3:0":0,
-"*invoke":[40],
+"*invoke":[41],
CI:function(a,b){return this.F2(a,b,null)},
"+invoke:2:0":0,
rN:function(a){throw H.b(P.lr(this,a,null,null,null))},
@@ -10273,7 +10297,7 @@
y=z+":"+b.length+":0"
return this.tu(a,0,y,b)},
"+invoke:3:0":0,
-"*invoke":[40],
+"*invoke":[41],
CI:function(a,b){return this.F2(a,b,null)},
"+invoke:2:0":0,
tu:function(a,b,c,d){var z,y,x,w,v,u,t,s
@@ -10400,7 +10424,7 @@
return z},
F2:function(a,b,c){return this.NK.F2(a,b,c)},
"+invoke:3:0":0,
-"*invoke":[40],
+"*invoke":[41],
CI:function(a,b){return this.F2(a,b,null)},
"+invoke:2:0":0,
gHA:function(){return!1},
@@ -10452,7 +10476,7 @@
y=J.x(z)
if(typeof z==="object"&&z!==null&&!!y.$isGv)return z.constructor
else return z
-"40"},
+"41"},
"+_jsConstructor":1,
gDI:function(){var z=this.b0
if(z!=null)return z
@@ -10460,7 +10484,7 @@
H.VM(z,[P.wv,P.RS])
this.b0=z
return z
-"52"},
+"54"},
"+constructors":1,
ly:function(a){var z,y,x,w,v,u,t,s,r,q,p,o,n,m,l,k
z=this.gaB().prototype
@@ -10505,14 +10529,14 @@
l=!1}s=H.Sd(k,o,!l,l)
x.push(s)
s.nz=a}return x
-"53,54,55"},
+"55,56,57"},
"+_getMethodsWithOwner:1:0":1,
gEO:function(){var z=this.jd
if(z!=null)return z
z=this.ly(this)
this.jd=z
return z
-"53"},
+"55"},
"+_methods":1,
ws:function(a){var z,y,x,w
z=[]
@@ -10526,14 +10550,14 @@
w=init.statics[this.WL]
if(w!=null)H.jw(a,w[""],!0,z)
return z
-"56,57,55"},
+"58,59,57"},
"+_getFieldsWithOwner:1:0":1,
gKn:function(){var z=this.tB
if(z!=null)return z
z=this.ws(this)
this.tB=z
return z
-"56"},
+"58"},
"+_fields":1,
gtx:function(){var z=this.FU
if(z!=null)return z
@@ -10541,7 +10565,7 @@
H.VM(z,[P.wv,P.RS])
this.FU=z
return z
-"52"},
+"54"},
"+methods":1,
gZ3:function(){var z,y,x
z=this.M2
@@ -10552,7 +10576,7 @@
H.VM(z,[P.wv,P.RY])
this.M2=z
return z
-"58"},
+"60"},
"+variables":1,
glc:function(a){var z=this.uA
if(z!=null)return z
@@ -10560,7 +10584,7 @@
H.VM(z,[P.wv,P.QF])
this.uA=z
return z
-"59"},
+"61"},
"+members":1,
gYK:function(){var z,y
z=this.Db
@@ -10574,7 +10598,7 @@
H.VM(z,[P.wv,P.NL])
this.Db=z
return z
-"60"},
+"62"},
"+declarations":1,
PU:function(a,b){var z,y
z=J.UQ(this.gZ3(),a)
@@ -10582,7 +10606,7 @@
if(!(y in $))throw H.b(H.Pa("Cannot find \""+y+"\" in current isolate."))
$[y]=b
return H.vn(b)}throw H.b(P.lr(this,H.X7(a),[b],null,null))
-"61,62,63,64,0"},
+"63,64,65,66,0"},
"+setField:2:0":1,
rN:function(a){var z,y
z=J.UQ(this.gZ3(),a)
@@ -10590,7 +10614,7 @@
if(!(y in $))throw H.b(H.Pa("Cannot find \""+y+"\" in current isolate."))
if(y in init.lazies)return H.vn($[init.lazies[y]]())
else return H.vn($[y])}throw H.b(P.lr(this,a,null,null,null))
-"61,62,63"},
+"63,64,65"},
"+getField:1:0":1,
gh7:function(){var z,y,x,w,v,u,t
if(this.nz==null){z=this.Tx
@@ -10609,7 +10633,7 @@
z=new H.MH(null,y,z.ew)
z.$builtinTypeInfo=[u,t]
for(;z.G();)for(y=J.GP(z.mD);y.G();)J.pP(y.gl())}if(this.nz==null)throw H.b(new P.lj("Class \""+H.d(J.Z0(this.If))+"\" has no owner"))}return this.nz
-"65"},
+"67"},
"+owner":1,
gc9:function(){var z=this.Ok
if(z!=null)return z
@@ -10618,7 +10642,7 @@
H.VM(z,[P.vr])
this.Ok=z
return z
-"66"},
+"68"},
"+metadata":1,
gAY:function(){var z,y,x,w,v,u
if(this.qN==null){z=init.typeInformation[this.WL]
@@ -10632,7 +10656,7 @@
u=v.length
if(u>1){if(u!==2)throw H.b(H.Pa("Strange mixin: "+H.d(y)))
this.qN=H.jO(v[0])}else this.qN=x.n(w,"")?this:H.jO(w)}}return J.xC(this.qN,this)?null:this.qN
-"67"},
+"69"},
"+superclass":1,
F2:function(a,b,c){var z
if(c!=null&&J.FN(c)!==!0)throw H.b(P.f("Named arguments are not implemented."))
@@ -10640,16 +10664,16 @@
if(z==null||!z.gFo())throw H.b(P.lr(this,a,b,c,null))
if(!z.yR())H.Hz(J.Z0(a))
return H.vn(z.qj(b,c))
-"61,68,63,69,70,71,72"},
+"63,70,65,71,72,73,74"},
"+invoke:3:0":1,
-"*invoke":[40],
+"*invoke":[41],
CI:function(a,b){return this.F2(a,b,null)},
"+invoke:2:0":1,
gHA:function(){return!0
-"44"},
+"46"},
"+isOriginalDeclaration":1,
gJi:function(){return this
-"67"},
+"69"},
"+originalDeclaration":1,
MR:function(a){var z,y,x
z=init.typeInformation[this.WL]
@@ -10659,14 +10683,14 @@
y=new P.Yp(x)
H.VM(y,[P.Ms])
return y
-"73,74,55"},
+"75,76,57"},
"+_getSuperinterfacesWithOwner:1:0":1,
gkZ:function(){var z=this.qm
if(z!=null)return z
z=this.MR(this)
this.qm=z
return z
-"73"},
+"75"},
"+superinterfaces":1,
gNy:function(){var z,y,x,w,v
z=this.UF
@@ -10679,34 +10703,34 @@
H.VM(z,[null])
this.UF=z
return z
-"75"},
+"77"},
"+typeVariables":1,
gw8:function(){return C.hU
-"76"},
+"78"},
"+typeArguments":1,
$isWf:true,
$isMs:true,
$isQF:true,
$isL9u:true,
-$isNL:true},"+JsClassMirror": [77, 67],Un:{"":"EE+M2;",$isQF:true},Ei:{"":"Tp;a-",
+$isNL:true},"+JsClassMirror": [79, 69],Un:{"":"EE+M2;",$isQF:true},Ei:{"":"Tp;a-",
call$2:function(a,b){J.kW(this.a,a,b)
-"40,78,63,31,79"},
+"41,80,65,32,81"},
"+call:2:0":1,
$isEH:true,
-$is_bh:true},"+JsClassMirror_declarations_addToResult": [80],U7:{"":"Tp;b-",
+$is_bh:true},"+JsClassMirror_declarations_addToResult": [82],U7:{"":"Tp;b-",
call$1:function(a){J.kW(this.b,a.gIf(),a)
return a
-"40,81,40"},
+"41,83,41"},
"+call:1:0":1,
$isEH:true,
$is_HB:true,
-$is_Dv:true},"+JsClassMirror_declarations_closure": [80],t0:{"":"Tp;a-",
+$is_Dv:true},"+JsClassMirror_declarations_closure": [82],t0:{"":"Tp;a-",
call$1:function(a){return H.Jf(this.a,init.metadata[a])
-"67,82,30"},
+"69,84,31"},
"+call:1:0":1,
$isEH:true,
$is_HB:true,
-$is_Dv:true},"+JsClassMirror__getSuperinterfacesWithOwner_lookupType": [80],Ld:{"":"am;ao<,V5<,Fo<,n6,nz,le,If",
+$is_Dv:true},"+JsClassMirror__getSuperinterfacesWithOwner_lookupType": [82],Ld:{"":"am;ao<,V5<,Fo<,n6,nz,le,If",
gOO:function(){return"VariableMirror"},
"+_prettyName":0,
gr9:function(a){return $.Cr()},
@@ -11373,7 +11397,7 @@
$is_Dv:true},dm:{"":"Tp;b",
call$2:function(a,b){this.b.K5(a,b)},
"+call:2:0":0,
-"*call":[40],
+"*call":[41],
call$1:function(a){return this.call$2(a,null)},
"+call:1:0":0,
$isEH:true,
@@ -11442,7 +11466,7 @@
if(typeof y!=="object"||y===null||!x.$isvs){z.a=P.Dt(null)
z.a.E6(a,b)}P.HZ(z.a,this.h)},
"+call:2:0":0,
-"*call":[40],
+"*call":[41],
call$1:function(a){return this.call$2(a,null)},
"+call:1:0":0,
$isEH:true,
@@ -14592,7 +14616,7 @@
gor:function(a){return J.pO(this.iY)},
"+isNotEmpty":0,
$isL8:true}}],["dart.dom.html","dart:html",,W,{lq:function(){return window
-"12"},"+window":1,UE:function(a){if(P.F7()===!0)return"webkitTransitionEnd"
+"13"},"+window":1,UE:function(a){if(P.F7()===!0)return"webkitTransitionEnd"
else if(P.dg()===!0)return"oTransitionEnd"
return"transitionend"},r3:function(a,b){return document.createElement(a)},It:function(a,b,c){return W.lt(a,null,null,b,null,null,null,c).ml(new W.Kx())},lt:function(a,b,c,d,e,f,g,h){var z,y,x,w
z=W.fJ
@@ -14663,7 +14687,7 @@
q={prototype: s}
if(!J.xC(w,"HTMLElement"))if(!v)q.extends=e
b.register(c,q)},aF:function(a){if(J.xC($.X3,C.NU))return a
-return $.X3.oj(a,!0)},qE:{"":"cv;","%":"HTMLAppletElement|HTMLBRElement|HTMLBaseFontElement|HTMLBodyElement|HTMLCanvasElement|HTMLContentElement|HTMLDListElement|HTMLDataListElement|HTMLDetailsElement|HTMLDialogElement|HTMLDirectoryElement|HTMLDivElement|HTMLFontElement|HTMLFrameElement|HTMLFrameSetElement|HTMLHRElement|HTMLHeadElement|HTMLHeadingElement|HTMLHtmlElement|HTMLMarqueeElement|HTMLMenuElement|HTMLModElement|HTMLOptGroupElement|HTMLParagraphElement|HTMLPreElement|HTMLQuoteElement|HTMLShadowElement|HTMLSpanElement|HTMLTableCaptionElement|HTMLTableCellElement|HTMLTableColElement|HTMLTableDataCellElement|HTMLTableElement|HTMLTableHeaderCellElement|HTMLTableRowElement|HTMLTableSectionElement|HTMLTitleElement|HTMLUListElement|HTMLUnknownElement;HTMLElement;Sa|GN|ir|Nr|uL|Vf|aC|tu|Be|Vc|i6|WZ|Fv|pv|I3|Vfx|qr|Dsd|Gk|tuj|Ds|Vct|pR|D13|hx|u7|WZq|St|pva|vj|cda|CX|Nh|ih|waa|F1|XP|NQ|V0|fI|V4|kK|V6|uw"},Yy:{"":"Gv;",$isList:true,
+return $.X3.oj(a,!0)},qE:{"":"cv;","%":"HTMLAppletElement|HTMLBRElement|HTMLBaseFontElement|HTMLBodyElement|HTMLCanvasElement|HTMLContentElement|HTMLDListElement|HTMLDataListElement|HTMLDetailsElement|HTMLDialogElement|HTMLDirectoryElement|HTMLDivElement|HTMLFontElement|HTMLFrameElement|HTMLFrameSetElement|HTMLHRElement|HTMLHeadElement|HTMLHeadingElement|HTMLHtmlElement|HTMLMarqueeElement|HTMLMenuElement|HTMLModElement|HTMLOptGroupElement|HTMLParagraphElement|HTMLPreElement|HTMLQuoteElement|HTMLShadowElement|HTMLSpanElement|HTMLTableCaptionElement|HTMLTableCellElement|HTMLTableColElement|HTMLTableDataCellElement|HTMLTableElement|HTMLTableHeaderCellElement|HTMLTableRowElement|HTMLTableSectionElement|HTMLTitleElement|HTMLUListElement|HTMLUnknownElement;HTMLElement;Sa|GN|ir|Nr|uL|Vf|G6|tu|aC|Vc|Be|WZ|i6|pv|Fv|Vfx|I3|Dsd|qr|tuj|Gk|Vct|Ds|D13|pR|WZq|hx|u7|pva|St|cda|vj|waa|CX|Nh|ih|V0|F1|XP|NQ|V4|fI|V6|kK|V8|uw"},Yy:{"":"Gv;",$isList:true,
$asWO:function(){return[W.M5]},
$isqC:true,
$iscX:true,
@@ -15697,12 +15721,12 @@
$iscX:true,
$ascX:function(){return[J.im]},
$isXj:true,
-static:{"":"U9",}}}],["disassembly_entry_element","package:observatory/src/observatory_elements/disassembly_entry.dart",,E,{Fv:{"":["WZ;FT%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+static:{"":"U9",}}}],["disassembly_entry_element","package:observatory/src/observatory_elements/disassembly_entry.dart",,E,{Fv:{"":["pv;FT%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gNI:function(a){return a.FT
-"37,38,39"},
+"38,39,40"},
"+instruction":1,
sNI:function(a,b){a.FT=this.pD(a,C.eJ,a.FT,b)
-"40,31,37,38"},
+"41,32,38,39"},
"+instruction=":1,
"@":function(){return[C.Vy]},
static:{AH:function(a){var z,y,x,w,v,u
@@ -15721,18 +15745,18 @@
C.Tl.ZL(a)
C.Tl.FH(a)
return a
-"13"},"+new DisassemblyEntryElement$created:0:0":1}},"+DisassemblyEntryElement": [83],WZ:{"":"uL+Pi;",$isd3:true}}],["error_view_element","package:observatory/src/observatory_elements/error_view.dart",,F,{I3:{"":["pv;Py%-,hO%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"14"},"+new DisassemblyEntryElement$created:0:0":1}},"+DisassemblyEntryElement": [85],pv:{"":"uL+Pi;",$isd3:true}}],["error_view_element","package:observatory/src/observatory_elements/error_view.dart",,F,{I3:{"":["Vfx;Py%-,hO%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gkc:function(a){return a.Py
-"8,38,39"},
+"8,39,40"},
"+error":1,
skc:function(a,b){a.Py=this.pD(a,C.YU,a.Py,b)
-"40,31,8,38"},
+"41,32,8,39"},
"+error=":1,
gVB:function(a){return a.hO
-"40,38,39"},
+"41,39,40"},
"+error_obj":1,
sVB:function(a,b){a.hO=this.pD(a,C.Yn,a.hO,b)
-"40,31,40,38"},
+"41,32,41,39"},
"+error_obj=":1,
"@":function(){return[C.uW]},
static:{TW:function(a){var z,y,x,w,v
@@ -15749,12 +15773,12 @@
C.OD.ZL(a)
C.OD.FH(a)
return a
-"14"},"+new ErrorViewElement$created:0:0":1}},"+ErrorViewElement": [84],pv:{"":"uL+Pi;",$isd3:true}}],["field_ref_element","package:observatory/src/observatory_elements/field_ref.dart",,D,{qr:{"":["Vfx;Lf%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"15"},"+new ErrorViewElement$created:0:0":1}},"+ErrorViewElement": [86],Vfx:{"":"uL+Pi;",$isd3:true}}],["field_ref_element","package:observatory/src/observatory_elements/field_ref.dart",,D,{qr:{"":["Dsd;Lf%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gt0:function(a){return a.Lf
-"37,38,39"},
+"38,39,40"},
"+field":1,
st0:function(a,b){a.Lf=this.pD(a,C.WQ,a.Lf,b)
-"40,31,37,38"},
+"41,32,38,39"},
"+field=":1,
"@":function(){return[C.ht]},
static:{ip:function(a){var z,y,x,w,v
@@ -15770,12 +15794,12 @@
C.WR.ZL(a)
C.WR.FH(a)
return a
-"15"},"+new FieldRefElement$created:0:0":1}},"+FieldRefElement": [85],Vfx:{"":"uL+Pi;",$isd3:true}}],["field_view_element","package:observatory/src/observatory_elements/field_view.dart",,A,{Gk:{"":["Dsd;vt%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"16"},"+new FieldRefElement$created:0:0":1}},"+FieldRefElement": [87],Dsd:{"":"uL+Pi;",$isd3:true}}],["field_view_element","package:observatory/src/observatory_elements/field_view.dart",,A,{Gk:{"":["tuj;vt%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gt0:function(a){return a.vt
-"37,38,39"},
+"38,39,40"},
"+field":1,
st0:function(a,b){a.vt=this.pD(a,C.WQ,a.vt,b)
-"40,31,37,38"},
+"41,32,38,39"},
"+field=":1,
"@":function(){return[C.Tq]},
static:{cY:function(a){var z,y,x,w,v
@@ -15791,12 +15815,12 @@
C.lS.ZL(a)
C.lS.FH(a)
return a
-"16"},"+new FieldViewElement$created:0:0":1}},"+FieldViewElement": [86],Dsd:{"":"uL+Pi;",$isd3:true}}],["function_view_element","package:observatory/src/observatory_elements/function_view.dart",,N,{Ds:{"":["tuj;ql%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"17"},"+new FieldViewElement$created:0:0":1}},"+FieldViewElement": [88],tuj:{"":"uL+Pi;",$isd3:true}}],["function_view_element","package:observatory/src/observatory_elements/function_view.dart",,N,{Ds:{"":["Vct;ql%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gMj:function(a){return a.ql
-"37,38,39"},
+"38,39,40"},
"+function":1,
sMj:function(a,b){a.ql=this.pD(a,C.nf,a.ql,b)
-"40,31,37,38"},
+"41,32,38,39"},
"+function=":1,
"@":function(){return[C.Uc]},
static:{p7:function(a){var z,y,x,w,v
@@ -15812,7 +15836,7 @@
C.PJ.ZL(a)
C.PJ.FH(a)
return a
-"17"},"+new FunctionViewElement$created:0:0":1}},"+FunctionViewElement": [87],tuj:{"":"uL+Pi;",$isd3:true}}],["html_common","dart:html_common",,P,{jD:function(a){return P.Wu(a.getTime(),!0)},bL:function(a){var z,y
+"18"},"+new FunctionViewElement$created:0:0":1}},"+FunctionViewElement": [89],Vct:{"":"uL+Pi;",$isd3:true}}],["html_common","dart:html_common",,P,{jD:function(a){return P.Wu(a.getTime(),!0)},bL:function(a){var z,y
z=[]
y=new P.Tm(new P.aI([],z),new P.rG(z),new P.yh(z)).call$1(a)
new P.wO().call$0()
@@ -16000,12 +16024,12 @@
"+call:1:0":0,
$isEH:true,
$is_HB:true,
-$is_Dv:true}}],["instance_ref_element","package:observatory/src/observatory_elements/instance_ref.dart",,B,{pR:{"":["Vct;iK%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+$is_Dv:true}}],["instance_ref_element","package:observatory/src/observatory_elements/instance_ref.dart",,B,{pR:{"":["D13;iK%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
ghf:function(a){return a.iK
-"37,38,39"},
+"38,39,40"},
"+instance":1,
shf:function(a,b){a.iK=this.pD(a,C.fn,a.iK,b)
-"40,31,37,38"},
+"41,32,38,39"},
"+instance=":1,
"@":function(){return[C.ay]},
static:{lu:function(a){var z,y,x,w,v
@@ -16021,12 +16045,12 @@
C.cp.ZL(a)
C.cp.FH(a)
return a
-"18"},"+new InstanceRefElement$created:0:0":1}},"+InstanceRefElement": [88],Vct:{"":"uL+Pi;",$isd3:true}}],["instance_view_element","package:observatory/src/observatory_elements/instance_view.dart",,Z,{hx:{"":["D13;Xh%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"19"},"+new InstanceRefElement$created:0:0":1}},"+InstanceRefElement": [90],D13:{"":"uL+Pi;",$isd3:true}}],["instance_view_element","package:observatory/src/observatory_elements/instance_view.dart",,Z,{hx:{"":["WZq;Xh%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
ghf:function(a){return a.Xh
-"37,38,39"},
+"38,39,40"},
"+instance":1,
shf:function(a,b){a.Xh=this.pD(a,C.fn,a.Xh,b)
-"40,31,37,38"},
+"41,32,38,39"},
"+instance=":1,
"@":function(){return[C.ql]},
static:{HC:function(a){var z,y,x,w,v
@@ -16042,7 +16066,7 @@
C.yK.ZL(a)
C.yK.FH(a)
return a
-"19"},"+new InstanceViewElement$created:0:0":1}},"+InstanceViewElement": [89],D13:{"":"uL+Pi;",$isd3:true}}],["isolate_list_element","package:observatory/src/observatory_elements/isolate_list.dart",,L,{u7:{"":["uL;tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"20"},"+new InstanceViewElement$created:0:0":1}},"+InstanceViewElement": [91],WZq:{"":"uL+Pi;",$isd3:true}}],["isolate_list_element","package:observatory/src/observatory_elements/isolate_list.dart",,L,{u7:{"":["uL;tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
"@":function(){return[C.jF]},
static:{Tt:function(a){var z,y,x,w,v
z=$.Nd()
@@ -16057,18 +16081,18 @@
C.Dh.ZL(a)
C.Dh.FH(a)
return a
-"20"},"+new IsolateListElement$created:0:0":1}},"+IsolateListElement": [27]}],["isolate_summary_element","package:observatory/src/observatory_elements/isolate_summary.dart",,D,{St:{"":["WZq;Pw%-,i0%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"21"},"+new IsolateListElement$created:0:0":1}},"+IsolateListElement": [28]}],["isolate_summary_element","package:observatory/src/observatory_elements/isolate_summary.dart",,D,{St:{"":["pva;Pw%-,i0%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gF1:function(a){return a.Pw
-"30,38,39"},
+"31,39,40"},
"+isolate":1,
sF1:function(a,b){a.Pw=this.pD(a,C.Y2,a.Pw,b)
-"40,31,30,38"},
+"41,32,31,39"},
"+isolate=":1,
goc:function(a){return a.i0
-"8,38,39"},
+"8,39,40"},
"+name":1,
soc:function(a,b){a.i0=this.pD(a,C.YS,a.i0,b)
-"40,31,8,38"},
+"41,32,8,39"},
"+name=":1,
"@":function(){return[C.aM]},
static:{N5:function(a){var z,y,x,w,v
@@ -16085,19 +16109,19 @@
C.nM.ZL(a)
C.nM.FH(a)
return a
-"21"},"+new IsolateSummaryElement$created:0:0":1}},"+IsolateSummaryElement": [90],WZq:{"":"uL+Pi;",$isd3:true}}],["json_view_element","package:observatory/src/observatory_elements/json_view.dart",,Z,{vj:{"":["pva;eb%-,kf%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"22"},"+new IsolateSummaryElement$created:0:0":1}},"+IsolateSummaryElement": [92],pva:{"":"uL+Pi;",$isd3:true}}],["json_view_element","package:observatory/src/observatory_elements/json_view.dart",,Z,{vj:{"":["cda;eb%-,kf%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gTn:function(a){return a.eb
-"40,38,39"},
+"41,39,40"},
"+json":1,
sTn:function(a,b){a.eb=this.pD(a,C.Gd,a.eb,b)
-"40,31,40,38"},
+"41,32,41,39"},
"+json=":1,
i4:function(a){Z.uL.prototype.i4.call(this,a)
a.kf=0
-"40"},
+"41"},
"+enteredView:0:0":1,
yC:function(a,b){this.pD(a,C.eR,"a","b")
-"40,91,40"},
+"41,93,41"},
"+jsonChanged:1:0":1,
gE8:function(a){return J.AG(a.eb)
"8"},
@@ -16113,24 +16137,24 @@
gFe:function(a){var z=a.kf
a.kf=J.WB(z,1)
return z
-"30"},
+"31"},
"+counter":1,
gqC:function(a){var z,y
z=a.eb
y=J.x(z)
if(typeof z==="object"&&z!==null&&(z.constructor===Array||!!y.$isList))return z
return[]
-"70"},
+"72"},
"+list":1,
gvc:function(a){var z,y
z=a.eb
y=J.RE(z)
if(typeof z==="object"&&z!==null&&!!y.$isL8)return J.qA(y.gvc(z))
return[]
-"70"},
+"72"},
"+keys":1,
r6:function(a,b){return J.UQ(a.eb,b)
-"40,78,8"},
+"41,80,8"},
"+value:1:0":1,
gP:function(a){return new P.C7(this,Z.vj.prototype.r6,a,"r6")},
"@":function(){return[C.HN]},
@@ -16149,12 +16173,12 @@
C.GB.ZL(a)
C.GB.FH(a)
return a
-"22"},"+new JsonViewElement$created:0:0":1}},"+JsonViewElement": [92],pva:{"":"uL+Pi;",$isd3:true}}],["library_view_element","package:observatory/src/observatory_elements/library_view.dart",,M,{CX:{"":["cda;iI%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"23"},"+new JsonViewElement$created:0:0":1}},"+JsonViewElement": [94],cda:{"":"uL+Pi;",$isd3:true}}],["library_view_element","package:observatory/src/observatory_elements/library_view.dart",,M,{CX:{"":["waa;iI%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gtD:function(a){return a.iI
-"37,38,39"},
+"38,39,40"},
"+library":1,
stD:function(a,b){a.iI=this.pD(a,C.EV,a.iI,b)
-"40,31,37,38"},
+"41,32,38,39"},
"+library=":1,
"@":function(){return[C.Oy]},
static:{SP:function(a){var z,y,x,w,v,u
@@ -16173,7 +16197,7 @@
C.MG.ZL(a)
C.MG.FH(a)
return a
-"23"},"+new LibraryViewElement$created:0:0":1}},"+LibraryViewElement": [93],cda:{"":"uL+Pi;",$isd3:true}}],["logging","package:logging/logging.dart",,N,{TJ:{"":"a;oc>,eT>,yz,Cj>,wd,Gs",
+"24"},"+new LibraryViewElement$created:0:0":1}},"+LibraryViewElement": [95],waa:{"":"uL+Pi;",$isd3:true}}],["logging","package:logging/logging.dart",,N,{TJ:{"":"a;oc>,eT>,yz,Cj>,wd,Gs",
gB8:function(){var z,y,x
z=this.eT
y=z==null||J.xC(J.DA(z),"")
@@ -16241,26 +16265,27 @@
giO:function(a){return this.P},
bu:function(a){return this.oc},
$isNg:true,
-static:{"":"bR,tm,EL,X8,IQ,Fn,Eb,AN,JY,bo",}},HV:{"":"a;OR<,G1>,iJ,Fl,O0,kc>,I4<",
+static:{"":"bR,tm,EL,X8,IQ,Fn,Eb,AN,JY,ac",}},HV:{"":"a;OR<,G1>,iJ,Fl,O0,kc>,I4<",
bu:function(a){return"["+this.OR.oc+"] "+this.iJ+": "+this.G1},
static:{"":"xO",}}}],["message_viewer_element","package:observatory/src/observatory_elements/message_viewer.dart",,L,{Nh:{"":["uL;XB%-,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gG1:function(a){return a.XB
-"37,39"},
+"38,40"},
"+message":1,
sG1:function(a,b){a.XB=b
this.pD(a,C.KY,"",this.gQW(a))
this.pD(a,C.wt,[],this.glc(a))
-"40,94,37,39"},
+"41,96,38,40"},
"+message=":1,
gQW:function(a){var z=a.XB
if(z==null||J.UQ(z,"type")==null)return"Error"
+P.JS("Received message of type '"+H.d(J.UQ(a.XB,"type"))+"' :\n"+H.d(a.XB))
return J.UQ(a.XB,"type")
"8"},
"+messageType":1,
glc:function(a){var z=a.XB
if(z==null||J.UQ(z,"members")==null)return[]
return J.UQ(a.XB,"members")
-"95"},
+"97"},
"+members":1,
"@":function(){return[C.c0]},
static:{rJ:function(a){var z,y,x,w,v
@@ -16276,7 +16301,7 @@
C.Wp.ZL(a)
C.Wp.FH(a)
return a
-"24"},"+new MessageViewerElement$created:0:0":1}},"+MessageViewerElement": [27]}],["metadata","../../../../../../../../../dart/dart-sdk/lib/html/html_common/metadata.dart",,B,{fA:{"":"a;Kr,Jt",static:{"":"Xd,en,yS,PZ,xa",}},tz:{"":"a;"},jR:{"":"a;oc>"},PO:{"":"a;"},c5:{"":"a;"}}],["navigation_bar_element","package:observatory/src/observatory_elements/navigation_bar.dart",,Q,{ih:{"":["uL;tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"25"},"+new MessageViewerElement$created:0:0":1}},"+MessageViewerElement": [28]}],["metadata","../../../../../../../../../dart/dart-sdk/lib/html/html_common/metadata.dart",,B,{fA:{"":"a;Kr,Jt",static:{"":"Xd,en,yS,PZ,xa",}},tz:{"":"a;"},jR:{"":"a;oc>"},PO:{"":"a;"},c5:{"":"a;"}}],["navigation_bar_element","package:observatory/src/observatory_elements/navigation_bar.dart",,Q,{ih:{"":["uL;tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
"@":function(){return[C.KG]},
static:{BW:function(a){var z,y,x,w,v
z=$.Nd()
@@ -16291,7 +16316,7 @@
C.Xg.ZL(a)
C.Xg.FH(a)
return a
-"25"},"+new NavigationBarElement$created:0:0":1}},"+NavigationBarElement": [27]}],["observatory","package:observatory/observatory.dart",,L,{mL:{"":["Pi;Z6<-,lw<-,nI<-,VJ,Ai",function(){return[C.mI]},function(){return[C.mI]},function(){return[C.mI]},null,null],
+"26"},"+new NavigationBarElement$created:0:0":1}},"+NavigationBarElement": [28]}],["observatory","package:observatory/observatory.dart",,L,{mL:{"":["Pi;Z6<-,lw<-,nI<-,VJ,Ai",function(){return[C.mI]},function(){return[C.mI]},function(){return[C.mI]},null,null],
Ey:function(){var z,y,x
z=this.Z6
z.sJR(this)
@@ -16325,16 +16350,16 @@
y.US()
return y}}},bv:{"":["Pi;nk,SS,XR<-,VJ,Ai",null,null,function(){return[C.mI]},null,null],
gjO:function(a){return this.nk
-"30,38,43"},
+"31,39,45"},
"+id":1,
sjO:function(a,b){this.nk=F.Wi(this,C.EN,this.nk,b)
-"40,31,30,38"},
+"41,32,31,39"},
"+id=":1,
goc:function(a){return this.SS
-"8,38,43"},
+"8,39,45"},
"+name":1,
soc:function(a,b){this.SS=F.Wi(this,C.YS,this.SS,b)
-"40,31,8,38"},
+"41,32,8,39"},
"+name=":1,
bu:function(a){return H.d(this.nk)+" "+H.d(this.SS)},
$isbv:true},pt:{"":["Pi;JR?,i2<-,VJ,Ai",null,function(){return[C.mI]},null,null],
@@ -16387,16 +16412,16 @@
$is_HB:true,
$is_Dv:true},dZ:{"":"Pi;JR?,IT,Jj,VJ,Ai",
gzd:function(){return this.IT
-"8,38,43"},
+"8,39,45"},
"+currentHash":1,
szd:function(a){this.IT=F.Wi(this,C.h1,this.IT,a)
-"40,31,8,38"},
+"41,32,8,39"},
"+currentHash=":1,
glD:function(){return this.Jj
-"96,38,43"},
+"98,39,45"},
"+currentHashUri":1,
slD:function(a){this.Jj=F.Wi(this,C.tv,this.Jj,a)
-"40,31,96,38"},
+"41,32,98,39"},
"+currentHashUri=":1,
kI:function(){var z,y
z=C.PP.aM(window)
@@ -16438,35 +16463,35 @@
PI:function(a){var z=this.R6()
if(J.xC(z,0))return"#/isolates/"
return"#/isolates/"+H.d(z)+"/"+H.d(a)
-"8,97,8,43"},
+"8,99,8,45"},
"+currentIsolateRelativeLink:1:0":1,
Ao:function(a){var z=this.R6()
if(J.xC(z,0))return"#/isolates/"
return"#/isolates/"+H.d(z)+"/objects/"+H.d(a)
-"8,98,30,43"},
+"8,100,31,45"},
"+currentIsolateObjectLink:1:0":1,
dL:function(a){var z=this.R6()
if(J.xC(z,0))return"#/isolates/"
return"#/isolates/"+H.d(z)+"/classes/"+H.d(a)
-"8,99,30,43"},
+"8,101,31,45"},
"+currentIsolateClassLink:1:0":1,
WW:function(a,b){var z=this.R6()
if(J.xC(z,0))return"#/isolates/"
return this.yX(z,a,b)
-"8,98,30,7,8,43"},
+"8,100,31,7,8,45"},
"+currentIsolateScriptLink:2:0":1,
r4:function(a,b){return"#/isolates/"+H.d(a)+"/"+H.d(b)
-"8,100,30,97,8,43"},
+"8,102,31,99,8,45"},
"+relativeLink:2:0":1,
Dd:function(a,b){return"#/isolates/"+H.d(a)+"/objects/"+H.d(b)
-"8,100,30,98,30,43"},
+"8,102,31,100,31,45"},
"+objectLink:2:0":1,
bD:function(a,b){return"#/isolates/"+H.d(a)+"/classes/"+H.d(b)
-"8,100,30,99,30,43"},
+"8,102,31,101,31,45"},
"+classLink:2:0":1,
yX:function(a,b,c){var z=P.jW(C.kg,c,!0)
return"#/isolates/"+H.d(a)+"/objects/"+H.d(b)+"?type=Script&name="+z
-"8,100,30,98,30,7,8,43"},
+"8,102,31,100,31,7,8,45"},
"+scriptLink:3:0":1,
static:{"":"kx,K3D,qY",}},Qe:{"":"Tp;a",
call$1:function(a){var z=this.a
@@ -16478,16 +16503,16 @@
$is_Dv:true},Nu:{"":"Pi;JR?,e0?",
pG:function(){return this.e0.call$0()},
gEI:function(){return this.oJ
-"8,38,43"},
+"8,39,45"},
"+prefix":1,
sEI:function(a){this.oJ=F.Wi(this,C.qb,this.oJ,a)
-"40,31,8,38"},
+"41,32,8,39"},
"+prefix=":1,
gn2:function(){return this.vm
-"95,38,43"},
+"97,39,45"},
"+responses":1,
sn2:function(a){this.vm=F.Wi(this,C.wH,this.vm,a)
-"40,31,95,38"},
+"41,32,97,39"},
"+responses=":1,
Qn:function(a){var z,y
z=C.lM.kV(a)
@@ -16574,13 +16599,13 @@
J.Ih(W.uV(window.parent),C.lM.KP(y),"*")
return w.MM}},Zw:{"":["Pi;Rd,n7,LA>-,Vg,VJ,Ai",null,null,function(){return[C.mI]},null,null,null],
geV:function(){return this.Vg
-"8,38,43"},
+"8,39,45"},
"+paddedLine":1,
seV:function(a){var z=this.Vg
if(this.gUV(this)&&!J.xC(z,a)){z=new T.qI(this,C.X9,z,a)
z.$builtinTypeInfo=[null]
this.SZ(this,z)}this.Vg=a
-"40,31,8,38"},
+"41,32,8,39"},
"+paddedLine=":1,
QQ:function(a,b,c){var z,y,x,w,v
z=""+this.Rd
@@ -16594,22 +16619,22 @@
z.QQ(a,b,c)
return z}}},Pf:{"":"Pi;WF,uM,ZQ,VJ,Ai",
gfY:function(a){return this.WF
-"8,38,43"},
+"8,39,45"},
"+kind":1,
sfY:function(a,b){this.WF=F.Wi(this,C.fy,this.WF,b)
-"40,31,8,38"},
+"41,32,8,39"},
"+kind=":1,
gO3:function(a){return this.uM
-"8,38,43"},
+"8,39,45"},
"+url":1,
sO3:function(a,b){this.uM=F.Wi(this,C.Fh,this.uM,b)
-"40,31,8,38"},
+"41,32,8,39"},
"+url=":1,
gXJ:function(){return this.ZQ
-"101,38,43"},
+"103,39,45"},
"+lines":1,
sXJ:function(a){this.ZQ=F.Wi(this,C.Cv,this.ZQ,a)
-"40,31,101,38"},
+"41,32,103,39"},
"+lines=":1,
Cn:function(a){var z,y,x,w,v
z=J.uH(a,"\n")
@@ -16629,17 +16654,17 @@
static:{Sp:function(a){var z=R.Jk([])
z=new L.Pf("","",z,null,null)
z.EQ(a)
-return z}}}}],["observatory_application_element","package:observatory/src/observatory_elements/observatory_application.dart",,V,{F1:{"":["waa;k5%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+return z}}}}],["observatory_application_element","package:observatory/src/observatory_elements/observatory_application.dart",,V,{F1:{"":["V0;k5%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gzj:function(a){return a.k5
-"44,38,39"},
+"46,39,40"},
"+devtools":1,
szj:function(a,b){a.k5=this.pD(a,C.Na,a.k5,b)
-"40,31,44,38"},
+"41,32,46,39"},
"+devtools=":1,
ZB:function(a){var z
if(a.k5===!0){z=L.WS()
a.tH=this.pD(a,C.wh,a.tH,z)}else{z=L.AK()
-a.tH=this.pD(a,C.wh,a.tH,z)}"40"},
+a.tH=this.pD(a,C.wh,a.tH,z)}"41"},
"@":function(){return[C.bd]},
static:{fv:function(a){var z,y,x,w,v
z=$.Nd()
@@ -16656,23 +16681,23 @@
C.k0.FH(a)
C.k0.ZB(a)
return a
-"26"},"+new ObservatoryApplicationElement$created:0:0":1}},"+ObservatoryApplicationElement": [102],waa:{"":"uL+Pi;",$isd3:true}}],["observatory_element","package:observatory/src/observatory_elements/observatory_element.dart",,Z,{uL:{"":["Nr;tH%-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"27"},"+new ObservatoryApplicationElement$created:0:0":1}},"+ObservatoryApplicationElement": [104],V0:{"":"uL+Pi;",$isd3:true}}],["observatory_element","package:observatory/src/observatory_elements/observatory_element.dart",,Z,{uL:{"":["Nr;tH%-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
i4:function(a){A.dM.prototype.i4.call(this,a)
-"40"},
+"41"},
"+enteredView:0:0":1,
Nz:function(a){A.dM.prototype.Nz.call(this,a)
-"40"},
+"41"},
"+leftView:0:0":1,
gQG:function(a){return a.tH
-"103,38,39"},
+"105,39,40"},
"+app":1,
sQG:function(a,b){a.tH=this.pD(a,C.wh,a.tH,b)
-"40,31,103,38"},
+"41,32,105,39"},
"+app=":1,
gpQ:function(a){return!0
-"44"},
+"46"},
"+applyAuthorStyles":1,
-"@":function(){return[C.J0]},
+"@":function(){return[C.Br]},
static:{Hx:function(a){var z,y,x,w,v
z=$.Nd()
y=P.Py(null,null,null,J.O,W.I0)
@@ -16686,7 +16711,7 @@
C.mk.ZL(a)
C.mk.FH(a)
return a
-"27"},"+new ObservatoryElement$created:0:0":1}},"+ObservatoryElement": [104],Nr:{"":"ir+Pi;",$isd3:true}}],["observe.src.change_notifier","package:observe/src/change_notifier.dart",,O,{Pi:{"":"a;",
+"28"},"+new ObservatoryElement$created:0:0":1}},"+ObservatoryElement": [106],Nr:{"":"ir+Pi;",$isd3:true}}],["observe.src.change_notifier","package:observe/src/change_notifier.dart",,O,{Pi:{"":"a;",
gqh:function(a){var z,y
if(a.VJ==null){z=this.gqw(a)
a.VJ=P.bK(this.gl1(a),z,!0,null)}z=a.VJ
@@ -16730,7 +16755,7 @@
gB:function(a){return this.b9.length},
"+length":0,
gP:function(a){return this.Sv
-"40,38"},
+"41,39"},
"+value":1,
r6:function(a,b){return this.gP(a).call$1(b)},
wE:function(a){var z,y,x,w
@@ -17055,11 +17080,11 @@
$isEH:true,
$is_bh:true}}],["observe.src.observable_box","package:observe/src/observable_box.dart",,A,{xh:{"":"Pi;",
gP:function(a){return this.L1
-"105,38"},
+"107,39"},
"+value":1,
r6:function(a,b){return this.gP(a).call$1(b)},
sP:function(a,b){this.L1=F.Wi(this,C.ls,this.L1,b)
-"40,106,105,38"},
+"41,108,107,39"},
"+value=":1,
bu:function(a){return"#<"+H.d(new H.cu(H.dJ(this),null))+" value: "+H.d(this.L1)+">"}}}],["observe.src.observable_list","package:observe/src/observable_list.dart",,Q,{wn:{"":"uF;b3,xg,h3,VJ,Ai",
gRT:function(){var z,y
@@ -17070,7 +17095,7 @@
H.VM(y,[H.W8(z,"WV",0)])
return y},
gB:function(a){return this.h3.length
-"30,38"},
+"31,39"},
"+length":1,
sB:function(a,b){var z,y,x,w,v,u,t
z=this.h3
@@ -17099,12 +17124,12 @@
w=new P.Yp(t)
w.$builtinTypeInfo=[null]
this.iH(new G.W4(this,w,t,y,x))}}C.Nm.sB(z,b)
-"40,31,30,38"},
+"41,32,31,39"},
"+length=":1,
t:function(a,b){var z=this.h3
if(b>>>0!==b||b>=z.length)throw H.e(z,b)
return z[b]
-"107,29,30,38"},
+"109,30,31,39"},
"+[]:1:0":1,
u:function(a,b,c){var z,y,x,w
z=this.h3
@@ -17118,7 +17143,7 @@
w.$builtinTypeInfo=[null]
this.iH(new G.W4(this,w,x,b,1))}if(b>=z.length)throw H.e(z,b)
z[b]=c
-"40,29,30,31,107,38"},
+"41,30,31,32,109,39"},
"+[]=:2:0":1,
h:function(a,b){var z,y,x,w
z=this.h3
@@ -17207,33 +17232,33 @@
$isHA:true},br:{"":"Pi;Zp,VJ,Ai",
gvc:function(a){var z=this.Zp
return z.gvc(z)
-"108,38"},
+"110,39"},
"+keys":1,
gUQ:function(a){var z=this.Zp
return z.gUQ(z)
-"109,38"},
+"111,39"},
"+values":1,
gB:function(a){var z=this.Zp
return z.gB(z)
-"30,38"},
+"31,39"},
"+length":1,
gl0:function(a){var z=this.Zp
return z.gB(z)===0
-"44,38"},
+"46,39"},
"+isEmpty":1,
gor:function(a){var z=this.Zp
return z.gB(z)!==0
-"44,38"},
+"46,39"},
"+isNotEmpty":1,
PF:function(a){return this.Zp.PF(a)
-"44,31,0,38"},
+"46,32,0,39"},
"+containsValue:1:0":1,
x4:function(a){return this.Zp.x4(a)
-"44,78,0,38"},
+"46,80,0,39"},
"+containsKey:1:0":1,
t:function(a,b){var z=this.Zp
return z.t(z,b)
-"110,78,0,38"},
+"112,80,0,39"},
"+[]:1:0":1,
u:function(a,b,c){var z,y,x,w,v
z=this.Zp
@@ -17250,7 +17275,7 @@
z.$builtinTypeInfo=[null,null]
this.SZ(this,z)}else if(!J.xC(x,c)){z=new V.HA(b,x,c,!1,!1)
z.$builtinTypeInfo=[null,null]
-this.SZ(this,z)}"40,78,111,31,110,38"},
+this.SZ(this,z)}"41,80,113,32,112,39"},
"+[]=:2:0":1,
Ay:function(a,b){b.aN(b,new V.zT(this))},
Rz:function(a,b){var z,y,x,w,v
@@ -17361,7 +17386,7 @@
z=y==null?z!=null:y!==z}else z=!1
if(!z)this.ov()
return C.Nm.grZ(this.kN)
-"40,38"},
+"41,39"},
"+value":1,
r6:function(a,b){return this.gP(a).call$1(b)},
sP:function(a,b){var z,y,x,w
@@ -17379,7 +17404,7 @@
if(w>=z.length)throw H.e(z,w)
if(L.h6(x,z[w],b)){z=this.kN
if(y>=z.length)throw H.e(z,y)
-z[y]=b}"40,106,0,38"},
+z[y]=b}"41,108,0,39"},
"+value=":1,
w3:function(a){O.Pi.prototype.w3.call(this,this)
this.ov()
@@ -18541,7 +18566,7 @@
y=typeof z==="object"&&z!==null&&!!y.$isEZ}else y=!1}else y=!1
if(y)return
return new T.Xy(this,b,z)},
-gca:function(){return new T.Dw(this,T.e9.prototype.yt,null,"yt")},
+gca:function(){return new T.PD(this,T.e9.prototype.yt,null,"yt")},
A5:function(a){return new T.uK(this)}},Xy:{"":"Tp;a,b,c",
call$2:function(a,b){var z=J.x(a)
if(typeof a!=="object"||a===null||!z.$isz6)a=new K.z6(null,a,V.WF(this.a.nF,null,null),null)
@@ -18568,14 +18593,14 @@
F.Wi(this,C.ls,z,this.uK)},
gnc:function(){return new H.Pm(this,T.mY.prototype.vr,null,"vr")},
gP:function(a){return this.uK
-"40,38"},
+"41,39"},
"+value":1,
r6:function(a,b){return this.gP(a).call$1(b)},
sP:function(a,b){var z,y,x,w
try{K.jX(this.jf,b,this.qc)}catch(y){x=H.Ru(y)
w=J.x(x)
if(typeof x==="object"&&x!==null&&!!w.$isB0){z=x
-$.IS().A3("Error evaluating expression '"+H.d(this.jf)+"': "+J.z2(z))}else throw y}"40,112,40,38"},
+$.IS().A3("Error evaluating expression '"+H.d(this.jf)+"': "+J.z2(z))}else throw y}"41,114,41,39"},
"+value=":1,
Va:function(a,b,c){var z,y,x,w,v
y=this.jf
@@ -19037,7 +19062,7 @@
return 536870911&a+((16383&a)<<15>>>0)},Fq:{"":"a;",
F2:function(a,b,c){return new U.RW(a,b,c)},
"+invoke:3:0":0,
-"*invoke":[40],
+"*invoke":[41],
CI:function(a,b){return this.F2(a,b,null)},
"+invoke:2:0":0},hw:{"":"a;",$ishw:true},EZ:{"":"hw;",
RR:function(a,b){return b.W9(this)},
@@ -19331,7 +19356,7 @@
static:{i0:function(a,b,c){var z=new K.Ae(a,b)
H.VM(z,[c])
return z
-"28,29,30,31,32"},"+new IndexedValue:2:0":1}},"+IndexedValue": [0],Bt:{"":"mW;YR",
+"29,30,31,32,33"},"+new IndexedValue:2:0":1}},"+IndexedValue": [0],Bt:{"":"mW;YR",
gA:function(a){var z=J.GP(this.YR)
z=new K.vR(z,0,null)
H.VM(z,[H.W8(this,"Bt",0)])
@@ -19525,15 +19550,15 @@
C.Cc.ZL(a)
C.Cc.FH(a)
return a
-"33"},"+new ResponseViewerElement$created:0:0":1}},"+ResponseViewerElement": [27]}],["script_view_element","package:observatory/src/observatory_elements/script_view.dart",,U,{fI:{"":["V0;Uz%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"34"},"+new ResponseViewerElement$created:0:0":1}},"+ResponseViewerElement": [28]}],["script_view_element","package:observatory/src/observatory_elements/script_view.dart",,U,{fI:{"":["V4;Uz%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gNl:function(a){return a.Uz
-"37,38,39"},
+"38,39,40"},
"+script":1,
sNl:function(a,b){a.Uz=this.pD(a,C.fX,a.Uz,b)
-"40,31,37,38"},
+"41,32,38,39"},
"+script=":1,
"@":function(){return[C.Er]},
-static:{Ry:function(a){var z,y,x,w,v
+static:{kL:function(a){var z,y,x,w,v
z=$.Nd()
y=P.Py(null,null,null,J.O,W.I0)
x=J.O
@@ -19546,12 +19571,12 @@
C.cJ.ZL(a)
C.cJ.FH(a)
return a
-"34"},"+new ScriptViewElement$created:0:0":1}},"+ScriptViewElement": [113],V0:{"":"uL+Pi;",$isd3:true}}],["source_view_element","package:observatory/src/observatory_elements/source_view.dart",,X,{kK:{"":["V4;vX%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"35"},"+new ScriptViewElement$created:0:0":1}},"+ScriptViewElement": [115],V4:{"":"uL+Pi;",$isd3:true}}],["source_view_element","package:observatory/src/observatory_elements/source_view.dart",,X,{kK:{"":["V6;vX%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gFF:function(a){return a.vX
-"114,38,39"},
+"116,39,40"},
"+source":1,
sFF:function(a,b){a.vX=this.pD(a,C.hn,a.vX,b)
-"40,31,114,38"},
+"41,32,116,39"},
"+source=":1,
"@":function(){return[C.H8]},
static:{HO:function(a){var z,y,x,w,v
@@ -19567,12 +19592,12 @@
C.Ks.ZL(a)
C.Ks.FH(a)
return a
-"35"},"+new SourceViewElement$created:0:0":1}},"+SourceViewElement": [115],V4:{"":"uL+Pi;",$isd3:true}}],["stack_trace_element","package:observatory/src/observatory_elements/stack_trace.dart",,X,{uw:{"":["V6;V4%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"36"},"+new SourceViewElement$created:0:0":1}},"+SourceViewElement": [117],V6:{"":"uL+Pi;",$isd3:true}}],["stack_trace_element","package:observatory/src/observatory_elements/stack_trace.dart",,X,{uw:{"":["V8;V4%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gtN:function(a){return a.V4
-"37,38,39"},
+"38,39,40"},
"+trace":1,
stN:function(a,b){a.V4=this.pD(a,C.kw,a.V4,b)
-"40,31,37,38"},
+"41,32,38,39"},
"+trace=":1,
"@":function(){return[C.js]},
static:{bV:function(a){var z,y,x,w,v,u
@@ -19591,7 +19616,7 @@
C.bg.ZL(a)
C.bg.FH(a)
return a
-"36"},"+new StackTraceElement$created:0:0":1}},"+StackTraceElement": [116],V6:{"":"uL+Pi;",$isd3:true}}],["template_binding","package:template_binding/template_binding.dart",,M,{IP:function(a){var z=J.RE(a)
+"37"},"+new StackTraceElement$created:0:0":1}},"+StackTraceElement": [118],V8:{"":"uL+Pi;",$isd3:true}}],["template_binding","package:template_binding/template_binding.dart",,M,{IP:function(a){var z=J.RE(a)
if(typeof a==="object"&&a!==null&&!!z.$isQl)return C.io.f0(a)
switch(z.gr9(a)){case"checkbox":return $.FF().aM(a)
case"radio":case"select-multiple":case"select-one":return z.gEr(a)
@@ -20671,6 +20696,7 @@
if(typeof a!="object")return a
if(a instanceof P.a)return a
return J.ks(a)}
+C.J0=B.G6.prototype
C.OL=new U.EZ()
C.Gw=new H.SJ()
C.E3=new J.Q()
@@ -20691,7 +20717,7 @@
C.YD=F.Be.prototype
C.j8=R.i6.prototype
C.Vy=new A.V3("disassembly-entry")
-C.J0=new A.V3("observatory-element")
+C.Br=new A.V3("observatory-element")
C.Er=new A.V3("script-view")
C.ht=new A.V3("field-ref")
C.aM=new A.V3("isolate-summary")
@@ -20703,6 +20729,7 @@
C.c0=new A.V3("message-viewer")
C.js=new A.V3("stack-trace")
C.jF=new A.V3("isolate-list")
+C.PT=new A.V3("breakpoint-list")
C.KG=new A.V3("navigation-bar")
C.ay=new A.V3("instance-ref")
C.Gu=new A.V3("collapsible-content")
@@ -20936,6 +20963,7 @@
C.PC=new H.GD("dart.core.int")
C.wt=new H.GD("members")
C.KY=new H.GD("messageType")
+C.Ry=new H.GD("msg")
C.YS=new H.GD("name")
C.OV=new H.GD("noSuchMethod")
C.Ws=new H.GD("operatingSystem")
@@ -20963,14 +20991,15 @@
C.Ti=H.mm('wn')
C.Mt=new H.Lm(C.Ti,"E",0)
C.Ye=H.mm('hx')
-C.G6=H.mm('F1')
+C.bD=H.mm('F1')
C.NM=H.mm('Nh')
+C.z7=H.mm('G6')
C.nY=H.mm('a')
C.Yc=H.mm('iP')
C.LN=H.mm('Be')
C.Qa=H.mm('u7')
C.xS=H.mm('UZ')
-C.PT=H.mm('CX')
+C.mA=H.mm('CX')
C.Op=H.mm('G8')
C.xF=H.mm('NQ')
C.b4=H.mm('ih')
@@ -21175,8 +21204,8 @@
J.z2=function(a){return J.RE(a).gG1(a)}
J.zZ=function(a,b){return J.RE(a).Yv(a,b)}
J.zj=function(a){return J.RE(a).gvH(a)}
-$.Dq=["Ay","BN","BT","Ba","C","C0","C8","Ch","D","D3","D6","Dh","E","Ec","F","FH","Fr","GB","HG","Hn","Id","Ih","Im","Is","J","J3","JP","JT","JV","Ja","Jk","Kb","LV","Md","Mi","Mu","Nj","Nz","O","On","PM","Pa","Pk","Pv","R3","R4","RB","RR","Rz","SZ","T","T2","TH","TP","TW","Tc","Td","U","UD","UH","UZ","Uc","V","V1","Vr","Vy","W","W3","W4","WO","WZ","Wt","Wz","X6","XG","XU","Xl","Y9","YU","YW","Ys","Yv","Z","Z1","Z2","ZB","ZF","ZL","ZP","Zv","aC","aN","aq","bA","bS","br","bu","cO","cn","d0","dR","dd","du","eR","ea","er","es","ev","ez","f6","fd","fj","fk","fm","g","gA","gB","gBb","gCd","gCj","gDD","gDg","gE8","gEX","gEr","gF1","gFF","gFJ","gFT","gFV","gFe","gG0","gG1","gG3","gGL","gHs","gI","gIi","gJS","gJf","gKE","gKM","gKV","gLA","gLU","gLf","gLm","gM0","gMB","gMj","gN","gNI","gNl","gO3","gP","gP1","gP2","gPp","gPu","gPw","gPy","gQ0","gQG","gQW","gQg","gRn","gRu","gT8","gTM","gTn","gTq","gUQ","gUV","gUz","gV4","gVA","gVB","gVl","gXB","gXf","gXh","gXt","gZw","gai","gbP","gbx","gcC","geT","geb","gey","gfY","ghO","ghf","ghr","gi0","giC","giI","giK","giO","gig","gjL","gjO","gjU","gjb","gk5","gkU","gkc","gkf","gkp","gl0","gl7","glc","gmW","gmm","gn4","goc","gor","gpQ","gpo","gq6","gqC","gqh","gql","gr3","gr9","grK","grZ","gt0","gtD","gtH","gtN","gtT","guD","gvH","gvX","gvc","gvt","gxj","gxr","gyT","gys","gzP","gzZ","gzj","h","h8","hV","hc","i","i4","iA","iM","iw","j","jT","jx","kO","l5","l8","lj","m","mK","mv","n","nB","nC","nH","nP","ni","oB","oW","od","oo","oq","pD","pZ","pl","pr","qZ","r6","rJ","rS","sB","sF1","sFF","sFJ","sFT","sG1","sIt","sLA","sLf","sMj","sNI","sNl","sO3","sP","sP2","sPw","sPy","sQG","sRu","sTn","sTq","sUz","sV4","sVA","sVB","sXB","sXf","sXh","sZw","sa4","sai","scC","seb","sfY","shO","shf","si0","siI","siK","sig","sjO","sk5","skc","skf","sl7","soc","sql","sr9","st0","stD","stH","stN","stT","svX","svt","sxj","sxr","szZ","szj","t","tZ","tg","tt","u","u5","u8","uG","vs","w3","wE","wL","wR","wg","x3","xI","xc","xe","y0","yC","yc","ym","yn","yq","yu","yx","yy","z2","zV"]
-$.Au=[C.Ye,Z.hx,{created:Z.HC},C.G6,V.F1,{created:V.fv},C.NM,L.Nh,{created:L.rJ},C.LN,F.Be,{created:F.Fe},C.Qa,L.u7,{created:L.Tt},C.xS,P.UZ,{},C.PT,M.CX,{created:M.SP},C.Op,P.G8,{},C.xF,Q.NQ,{created:Q.Zo},C.b4,Q.ih,{created:Q.BW},C.Ob,X.kK,{created:X.HO},C.hG,A.ir,{created:A.oa},C.aj,U.fI,{created:U.Ry},C.mo,E.Fv,{created:E.AH},C.xE,Z.aC,{created:Z.zg},C.vuj,X.uw,{created:X.bV},C.j6,D.qr,{created:D.ip},C.C6,Z.vj,{created:Z.un},C.CT,D.St,{created:D.N5},C.Q4,Z.uL,{created:Z.Hx},C.yg,F.I3,{created:F.TW},C.XU,R.i6,{created:R.IT},C.Bm,A.XP,{created:A.XL},C.Wz,B.pR,{created:B.lu},C.mnH,N.Ds,{created:N.p7},C.XK,A.Gk,{created:A.cY}]
+$.Dq=["Ay","BN","BT","Ba","C","C0","C8","Ch","D","D3","D6","Dh","E","Ec","F","FH","Fr","GB","HG","Hn","Id","Ih","Im","Is","J","J3","JP","JT","JV","Ja","Jk","Kb","LV","Md","Mi","Mu","Nj","Nz","O","On","PM","Pa","Pk","Pv","R3","R4","RB","RR","Rz","SZ","T","T2","TH","TP","TW","Tc","Td","U","UD","UH","UZ","Uc","V","V1","Vr","Vy","W","W3","W4","WO","WZ","Wt","Wz","X6","XG","XU","Xl","Y9","YU","YW","Ys","Yv","Z","Z1","Z2","ZB","ZF","ZL","ZP","Zv","aC","aN","aq","bA","bS","br","bu","cO","cn","d0","dR","dd","du","eR","ea","er","es","ev","ez","f6","fd","fj","fk","fm","g","gA","gB","gBb","gCd","gCj","gDD","gDg","gE8","gEX","gEr","gF1","gFF","gFJ","gFT","gFV","gFe","gG0","gG1","gG3","gGL","gHs","gI","gIi","gJS","gJf","gKE","gKM","gKV","gLA","gLU","gLf","gLm","gM0","gMB","gMj","gN","gNI","gNl","gO3","gP","gP1","gP2","gPp","gPu","gPw","gPy","gQ0","gQG","gQW","gQg","gRn","gRu","gT8","gTM","gTn","gTq","gUQ","gUV","gUz","gV4","gVA","gVB","gVl","gXB","gXf","gXh","gXt","gZw","gai","gbP","gbx","gcC","geE","geT","geb","gey","gfY","ghO","ghf","ghr","gi0","giC","giI","giK","giO","gig","gjL","gjO","gjU","gjb","gk5","gkU","gkc","gkf","gkp","gl0","gl7","glc","gmW","gmm","gn4","goc","gor","gpQ","gpo","gq6","gqC","gqh","gql","gr3","gr9","grK","grZ","grs","gt0","gtD","gtH","gtN","gtT","guD","gvH","gvX","gvc","gvt","gxj","gxr","gyT","gys","gzP","gzZ","gzj","h","h8","hV","hc","i","i4","iA","iM","iw","j","jT","jx","kO","l5","l8","lj","m","mK","mv","n","nB","nC","nH","nP","ni","oB","oW","od","oo","oq","pD","pZ","pl","pr","qZ","r6","rJ","rS","sB","sF1","sFF","sFJ","sFT","sG1","sIt","sLA","sLf","sMj","sNI","sNl","sO3","sP","sP2","sPw","sPy","sQG","sRu","sTn","sTq","sUz","sV4","sVA","sVB","sXB","sXf","sXh","sZw","sa4","sai","scC","seE","seb","sfY","shO","shf","si0","siI","siK","sig","sjO","sk5","skc","skf","sl7","soc","sql","sr9","srs","st0","stD","stH","stN","stT","svX","svt","sxj","sxr","szZ","szj","t","tZ","tg","tt","u","u5","u8","uG","vs","w3","wE","wL","wR","wg","x3","xI","xc","xe","y0","yC","yc","ym","yn","yq","yu","yx","yy","z2","zV"]
+$.Au=[C.Ye,Z.hx,{created:Z.HC},C.bD,V.F1,{created:V.fv},C.NM,L.Nh,{created:L.rJ},C.z7,B.G6,{created:B.Dw},C.LN,F.Be,{created:F.Fe},C.Qa,L.u7,{created:L.Tt},C.xS,P.UZ,{},C.mA,M.CX,{created:M.SP},C.Op,P.G8,{},C.xF,Q.NQ,{created:Q.Zo},C.b4,Q.ih,{created:Q.BW},C.Ob,X.kK,{created:X.HO},C.hG,A.ir,{created:A.oa},C.aj,U.fI,{created:U.kL},C.mo,E.Fv,{created:E.AH},C.xE,Z.aC,{created:Z.zg},C.vuj,X.uw,{created:X.bV},C.j6,D.qr,{created:D.ip},C.C6,Z.vj,{created:Z.un},C.CT,D.St,{created:D.N5},C.Q4,Z.uL,{created:Z.Hx},C.yg,F.I3,{created:F.TW},C.XU,R.i6,{created:R.IT},C.Bm,A.XP,{created:A.XL},C.Wz,B.pR,{created:B.lu},C.mnH,N.Ds,{created:N.p7},C.XK,A.Gk,{created:A.cY}]
I.$lazy($,"globalThis","DX","jk",function(){return function() { return this; }()})
I.$lazy($,"globalWindow","pG","Qm",function(){return $.jk().window})
I.$lazy($,"globalWorker","zA","Nl",function(){return $.jk().Worker})
@@ -21276,7 +21305,7 @@
return z})
init.functionAliases={}
-init.metadata=[P.a,C.wK,C.wa,C.WX,C.Mt,C.wW,P.uq,"name",J.O,Z.aC,F.Be,R.i6,W.K5,E.Fv,F.I3,D.qr,A.Gk,N.Ds,B.pR,Z.hx,L.u7,D.St,Z.vj,M.CX,L.Nh,Q.ih,V.F1,Z.uL,[K.Ae,3],"index",J.im,"value",3,Q.NQ,U.fI,X.kK,X.uw,P.L8,C.nJ,C.Us,,Z.Vf,F.tu,C.mI,J.kn,"r","e",W.ea,"detail","target",W.KV,R.Vc,[P.L8,P.wv,P.RS],[J.Q,H.Zk],"methodOwner",P.NL,[J.Q,P.RY],"fieldOwner",[P.L8,P.wv,P.RY],[P.L8,P.wv,P.QF],[P.L8,P.wv,P.NL],P.vr,"fieldName",P.wv,"arg",H.Uz,[J.Q,P.vr],P.Ms,"memberName","positionalArguments",J.Q,"namedArguments",[P.L8,P.wv,null],[J.Q,P.Ms],"owner",[J.Q,P.Fw],[J.Q,P.L9u],H.Un,"key",P.QF,H.Tp,"tv","i",E.WZ,F.pv,D.Vfx,A.Dsd,N.tuj,B.Vct,Z.D13,D.WZq,"oldValue",Z.pva,M.cda,"m",[J.Q,P.L8],P.iD,"l","objectId","cid","isolateId",[J.Q,L.Zw],V.waa,L.mL,Z.Nr,5,"newValue",4,[P.cX,1],[P.cX,2],2,1,"v",U.V0,L.Pf,X.V4,X.V6,];$=null
+init.metadata=[P.a,C.wK,C.wa,C.WX,C.Mt,C.wW,P.uq,"name",J.O,B.G6,Z.aC,F.Be,R.i6,W.K5,E.Fv,F.I3,D.qr,A.Gk,N.Ds,B.pR,Z.hx,L.u7,D.St,Z.vj,M.CX,L.Nh,Q.ih,V.F1,Z.uL,[K.Ae,3],"index",J.im,"value",3,Q.NQ,U.fI,X.kK,X.uw,P.L8,C.nJ,C.Us,,B.Vf,Z.tu,F.Vc,C.mI,J.kn,"r","e",W.ea,"detail","target",W.KV,R.WZ,[P.L8,P.wv,P.RS],[J.Q,H.Zk],"methodOwner",P.NL,[J.Q,P.RY],"fieldOwner",[P.L8,P.wv,P.RY],[P.L8,P.wv,P.QF],[P.L8,P.wv,P.NL],P.vr,"fieldName",P.wv,"arg",H.Uz,[J.Q,P.vr],P.Ms,"memberName","positionalArguments",J.Q,"namedArguments",[P.L8,P.wv,null],[J.Q,P.Ms],"owner",[J.Q,P.Fw],[J.Q,P.L9u],H.Un,"key",P.QF,H.Tp,"tv","i",E.pv,F.Vfx,D.Dsd,A.tuj,N.Vct,B.D13,Z.WZq,D.pva,"oldValue",Z.cda,M.waa,"m",[J.Q,P.L8],P.iD,"l","objectId","cid","isolateId",[J.Q,L.Zw],V.V0,L.mL,Z.Nr,5,"newValue",4,[P.cX,1],[P.cX,2],2,1,"v",U.V4,L.Pf,X.V6,X.V8,];$=null
I = I.$finishIsolateConstructor(I)
$=new I()
function convertToFastObject(properties) {
@@ -23577,6 +23606,35 @@
$desc=$collectedClasses.tQ
if($desc instanceof Array)$desc=$desc[1]
tQ.prototype=$desc
+function G6(eE,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.eE=eE
+this.VJ=VJ
+this.Ai=Ai
+this.tH=tH
+this.VJ=VJ
+this.Ai=Ai
+this.VJ=VJ
+this.Ai=Ai
+this.ZI=ZI
+this.uN=uN
+this.z3=z3
+this.TQ=TQ
+this.Vk=Vk
+this.Ye=Ye
+this.mT=mT
+this.KM=KM}G6.builtin$cls="G6"
+if(!"name" in G6)G6.name="G6"
+$desc=$collectedClasses.G6
+if($desc instanceof Array)$desc=$desc[1]
+G6.prototype=$desc
+G6.prototype.geE=function(receiver){return receiver.eE}
+G6.prototype.geE.$reflectable=1
+G6.prototype.seE=function(receiver,v){return receiver.eE=v}
+G6.prototype.seE.$reflectable=1
+function Vf(){}Vf.builtin$cls="Vf"
+if(!"name" in Vf)Vf.name="Vf"
+$desc=$collectedClasses.Vf
+if($desc instanceof Array)$desc=$desc[1]
+Vf.prototype=$desc
function aC(FJ,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.FJ=FJ
this.VJ=VJ
this.Ai=Ai
@@ -23601,11 +23659,11 @@
aC.prototype.gFJ.$reflectable=1
aC.prototype.sFJ=function(receiver,v){return receiver.FJ=v}
aC.prototype.sFJ.$reflectable=1
-function Vf(){}Vf.builtin$cls="Vf"
-if(!"name" in Vf)Vf.name="Vf"
-$desc=$collectedClasses.Vf
+function tu(){}tu.builtin$cls="tu"
+if(!"name" in tu)tu.name="tu"
+$desc=$collectedClasses.tu
if($desc instanceof Array)$desc=$desc[1]
-Vf.prototype=$desc
+tu.prototype=$desc
function Be(Zw,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.Zw=Zw
this.VJ=VJ
this.Ai=Ai
@@ -23630,11 +23688,11 @@
Be.prototype.gZw.$reflectable=1
Be.prototype.sZw=function(receiver,v){return receiver.Zw=v}
Be.prototype.sZw.$reflectable=1
-function tu(){}tu.builtin$cls="tu"
-if(!"name" in tu)tu.name="tu"
-$desc=$collectedClasses.tu
+function Vc(){}Vc.builtin$cls="Vc"
+if(!"name" in Vc)Vc.name="Vc"
+$desc=$collectedClasses.Vc
if($desc instanceof Array)$desc=$desc[1]
-tu.prototype=$desc
+Vc.prototype=$desc
function i6(Xf,VA,P2,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.Xf=Xf
this.VA=VA
this.P2=P2
@@ -23669,11 +23727,11 @@
i6.prototype.gP2.$reflectable=1
i6.prototype.sP2=function(receiver,v){return receiver.P2=v}
i6.prototype.sP2.$reflectable=1
-function Vc(){}Vc.builtin$cls="Vc"
-if(!"name" in Vc)Vc.name="Vc"
-$desc=$collectedClasses.Vc
+function WZ(){}WZ.builtin$cls="WZ"
+if(!"name" in WZ)WZ.name="WZ"
+$desc=$collectedClasses.WZ
if($desc instanceof Array)$desc=$desc[1]
-Vc.prototype=$desc
+WZ.prototype=$desc
function zO(){}zO.builtin$cls="zO"
if(!"name" in zO)zO.name="zO"
$desc=$collectedClasses.zO
@@ -26130,11 +26188,11 @@
Fv.prototype.gFT.$reflectable=1
Fv.prototype.sFT=function(receiver,v){return receiver.FT=v}
Fv.prototype.sFT.$reflectable=1
-function WZ(){}WZ.builtin$cls="WZ"
-if(!"name" in WZ)WZ.name="WZ"
-$desc=$collectedClasses.WZ
+function pv(){}pv.builtin$cls="pv"
+if(!"name" in pv)pv.name="pv"
+$desc=$collectedClasses.pv
if($desc instanceof Array)$desc=$desc[1]
-WZ.prototype=$desc
+pv.prototype=$desc
function I3(Py,hO,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.Py=Py
this.hO=hO
this.VJ=VJ
@@ -26164,11 +26222,11 @@
I3.prototype.ghO.$reflectable=1
I3.prototype.shO=function(receiver,v){return receiver.hO=v}
I3.prototype.shO.$reflectable=1
-function pv(){}pv.builtin$cls="pv"
-if(!"name" in pv)pv.name="pv"
-$desc=$collectedClasses.pv
+function Vfx(){}Vfx.builtin$cls="Vfx"
+if(!"name" in Vfx)Vfx.name="Vfx"
+$desc=$collectedClasses.Vfx
if($desc instanceof Array)$desc=$desc[1]
-pv.prototype=$desc
+Vfx.prototype=$desc
function qr(Lf,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.Lf=Lf
this.VJ=VJ
this.Ai=Ai
@@ -26193,11 +26251,11 @@
qr.prototype.gLf.$reflectable=1
qr.prototype.sLf=function(receiver,v){return receiver.Lf=v}
qr.prototype.sLf.$reflectable=1
-function Vfx(){}Vfx.builtin$cls="Vfx"
-if(!"name" in Vfx)Vfx.name="Vfx"
-$desc=$collectedClasses.Vfx
+function Dsd(){}Dsd.builtin$cls="Dsd"
+if(!"name" in Dsd)Dsd.name="Dsd"
+$desc=$collectedClasses.Dsd
if($desc instanceof Array)$desc=$desc[1]
-Vfx.prototype=$desc
+Dsd.prototype=$desc
function Gk(vt,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.vt=vt
this.VJ=VJ
this.Ai=Ai
@@ -26222,11 +26280,11 @@
Gk.prototype.gvt.$reflectable=1
Gk.prototype.svt=function(receiver,v){return receiver.vt=v}
Gk.prototype.svt.$reflectable=1
-function Dsd(){}Dsd.builtin$cls="Dsd"
-if(!"name" in Dsd)Dsd.name="Dsd"
-$desc=$collectedClasses.Dsd
+function tuj(){}tuj.builtin$cls="tuj"
+if(!"name" in tuj)tuj.name="tuj"
+$desc=$collectedClasses.tuj
if($desc instanceof Array)$desc=$desc[1]
-Dsd.prototype=$desc
+tuj.prototype=$desc
function Ds(ql,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.ql=ql
this.VJ=VJ
this.Ai=Ai
@@ -26251,11 +26309,11 @@
Ds.prototype.gql.$reflectable=1
Ds.prototype.sql=function(receiver,v){return receiver.ql=v}
Ds.prototype.sql.$reflectable=1
-function tuj(){}tuj.builtin$cls="tuj"
-if(!"name" in tuj)tuj.name="tuj"
-$desc=$collectedClasses.tuj
+function Vct(){}Vct.builtin$cls="Vct"
+if(!"name" in Vct)Vct.name="Vct"
+$desc=$collectedClasses.Vct
if($desc instanceof Array)$desc=$desc[1]
-tuj.prototype=$desc
+Vct.prototype=$desc
function aI(b,c){this.b=b
this.c=c}aI.builtin$cls="aI"
if(!"name" in aI)aI.name="aI"
@@ -26348,11 +26406,11 @@
pR.prototype.giK.$reflectable=1
pR.prototype.siK=function(receiver,v){return receiver.iK=v}
pR.prototype.siK.$reflectable=1
-function Vct(){}Vct.builtin$cls="Vct"
-if(!"name" in Vct)Vct.name="Vct"
-$desc=$collectedClasses.Vct
+function D13(){}D13.builtin$cls="D13"
+if(!"name" in D13)D13.name="D13"
+$desc=$collectedClasses.D13
if($desc instanceof Array)$desc=$desc[1]
-Vct.prototype=$desc
+D13.prototype=$desc
function hx(Xh,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.Xh=Xh
this.VJ=VJ
this.Ai=Ai
@@ -26377,11 +26435,11 @@
hx.prototype.gXh.$reflectable=1
hx.prototype.sXh=function(receiver,v){return receiver.Xh=v}
hx.prototype.sXh.$reflectable=1
-function D13(){}D13.builtin$cls="D13"
-if(!"name" in D13)D13.name="D13"
-$desc=$collectedClasses.D13
+function WZq(){}WZq.builtin$cls="WZq"
+if(!"name" in WZq)WZq.name="WZq"
+$desc=$collectedClasses.WZq
if($desc instanceof Array)$desc=$desc[1]
-D13.prototype=$desc
+WZq.prototype=$desc
function u7(tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.tH=tH
this.VJ=VJ
this.Ai=Ai
@@ -26428,11 +26486,11 @@
St.prototype.gi0.$reflectable=1
St.prototype.si0=function(receiver,v){return receiver.i0=v}
St.prototype.si0.$reflectable=1
-function WZq(){}WZq.builtin$cls="WZq"
-if(!"name" in WZq)WZq.name="WZq"
-$desc=$collectedClasses.WZq
+function pva(){}pva.builtin$cls="pva"
+if(!"name" in pva)pva.name="pva"
+$desc=$collectedClasses.pva
if($desc instanceof Array)$desc=$desc[1]
-WZq.prototype=$desc
+pva.prototype=$desc
function vj(eb,kf,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.eb=eb
this.kf=kf
this.VJ=VJ
@@ -26462,11 +26520,11 @@
vj.prototype.gkf.$reflectable=1
vj.prototype.skf=function(receiver,v){return receiver.kf=v}
vj.prototype.skf.$reflectable=1
-function pva(){}pva.builtin$cls="pva"
-if(!"name" in pva)pva.name="pva"
-$desc=$collectedClasses.pva
+function cda(){}cda.builtin$cls="cda"
+if(!"name" in cda)cda.name="cda"
+$desc=$collectedClasses.cda
if($desc instanceof Array)$desc=$desc[1]
-pva.prototype=$desc
+cda.prototype=$desc
function CX(iI,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.iI=iI
this.VJ=VJ
this.Ai=Ai
@@ -26491,11 +26549,11 @@
CX.prototype.giI.$reflectable=1
CX.prototype.siI=function(receiver,v){return receiver.iI=v}
CX.prototype.siI.$reflectable=1
-function cda(){}cda.builtin$cls="cda"
-if(!"name" in cda)cda.name="cda"
-$desc=$collectedClasses.cda
+function waa(){}waa.builtin$cls="waa"
+if(!"name" in waa)waa.name="waa"
+$desc=$collectedClasses.waa
if($desc instanceof Array)$desc=$desc[1]
-cda.prototype=$desc
+waa.prototype=$desc
function TJ(oc,eT,yz,Cj,wd,Gs){this.oc=oc
this.eT=eT
this.yz=yz
@@ -26783,11 +26841,11 @@
F1.prototype.gk5.$reflectable=1
F1.prototype.sk5=function(receiver,v){return receiver.k5=v}
F1.prototype.sk5.$reflectable=1
-function waa(){}waa.builtin$cls="waa"
-if(!"name" in waa)waa.name="waa"
-$desc=$collectedClasses.waa
+function V0(){}V0.builtin$cls="V0"
+if(!"name" in V0)V0.name="V0"
+$desc=$collectedClasses.V0
if($desc instanceof Array)$desc=$desc[1]
-waa.prototype=$desc
+V0.prototype=$desc
function uL(tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.tH=tH
this.VJ=VJ
this.Ai=Ai
@@ -27397,13 +27455,13 @@
$desc=$collectedClasses.e9
if($desc instanceof Array)$desc=$desc[1]
e9.prototype=$desc
-function Dw(wc,nn,lv,Pp){this.wc=wc
+function PD(wc,nn,lv,Pp){this.wc=wc
this.nn=nn
this.lv=lv
-this.Pp=Pp}Dw.builtin$cls="Dw"
-$desc=$collectedClasses.Dw
+this.Pp=Pp}PD.builtin$cls="PD"
+$desc=$collectedClasses.PD
if($desc instanceof Array)$desc=$desc[1]
-Dw.prototype=$desc
+PD.prototype=$desc
function Xy(a,b,c){this.a=a
this.b=b
this.c=c}Xy.builtin$cls="Xy"
@@ -27938,11 +27996,11 @@
fI.prototype.gUz.$reflectable=1
fI.prototype.sUz=function(receiver,v){return receiver.Uz=v}
fI.prototype.sUz.$reflectable=1
-function V0(){}V0.builtin$cls="V0"
-if(!"name" in V0)V0.name="V0"
-$desc=$collectedClasses.V0
+function V4(){}V4.builtin$cls="V4"
+if(!"name" in V4)V4.name="V4"
+$desc=$collectedClasses.V4
if($desc instanceof Array)$desc=$desc[1]
-V0.prototype=$desc
+V4.prototype=$desc
function kK(vX,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.vX=vX
this.VJ=VJ
this.Ai=Ai
@@ -27967,11 +28025,11 @@
kK.prototype.gvX.$reflectable=1
kK.prototype.svX=function(receiver,v){return receiver.vX=v}
kK.prototype.svX.$reflectable=1
-function V4(){}V4.builtin$cls="V4"
-if(!"name" in V4)V4.name="V4"
-$desc=$collectedClasses.V4
+function V6(){}V6.builtin$cls="V6"
+if(!"name" in V6)V6.name="V6"
+$desc=$collectedClasses.V6
if($desc instanceof Array)$desc=$desc[1]
-V4.prototype=$desc
+V6.prototype=$desc
function uw(V4,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.V4=V4
this.VJ=VJ
this.Ai=Ai
@@ -27996,11 +28054,11 @@
uw.prototype.gV4.$reflectable=1
uw.prototype.sV4=function(receiver,v){return receiver.V4=v}
uw.prototype.sV4.$reflectable=1
-function V6(){}V6.builtin$cls="V6"
-if(!"name" in V6)V6.name="V6"
-$desc=$collectedClasses.V6
+function V8(){}V8.builtin$cls="V8"
+if(!"name" in V8)V8.name="V8"
+$desc=$collectedClasses.V8
if($desc instanceof Array)$desc=$desc[1]
-V6.prototype=$desc
+V8.prototype=$desc
function V2(N1,bn,Ck){this.N1=N1
this.bn=bn
this.Ck=Ck}V2.builtin$cls="V2"
@@ -28338,4 +28396,4 @@
$desc=$collectedClasses.PW
if($desc instanceof Array)$desc=$desc[1]
PW.prototype=$desc
-return[qE,Yy,Ps,rK,fY,Mr,zx,ct,nB,i3,it,Az,QP,QW,n6,Ny,OM,QQ,MA,y4,d7,na,oJ,DG,mN,vH,hh,Em,Sb,rV,Wy,YN,bA,Wq,rv,BK,wj,cv,Fs,SX,ea,D0,as,T5,Aa,u5,Yu,iG,jP,U2,tA,xn,Vb,QH,ST,X2,fJ,Vi,tX,Sg,pA,Mi,Gt,In,Gx,eP,AL,Og,cS,M6,El,zm,SV,aB,ku,KM,cW,DK,qm,ZY,cx,la,Vn,PG,xe,Hw,bn,Im,oB,Aj,oU,qT,KV,BH,mh,G7,wq,Ql,Xp,bP,mX,SN,HD,ni,p3,qj,qW,KR,ew,fs,bX,BL,MC,Mx,j2,yz,lp,pD,I0,QR,Cp,ua,zD,Ul,G0,wb,fq,h4,qk,GI,Tb,tV,BT,yY,kJ,AE,xV,FH,y6,RH,pU,Lq,Mf,BR,r4,aG,J6,K5,UM,UL,rq,nK,kc,ij,ty,Nf,Nc,rj,rh,Zv,Q7,hF,OF,HB,ZJ,mU,eZ,Fl,y5,nV,Zc,ui,D6,DQ,Sm,dx,es,eG,lv,pf,NV,W1,zo,wf,TU,bb,VE,lc,Xu,qM,tk,me,qN,nh,d4,MI,ca,xX,eW,um,Fu,OE,l6,BA,zp,rE,CC,PQ,uz,Yd,U0,AD,Gr,tc,GH,lo,NJ,nd,vt,rQ,EU,LR,MB,hy,r8,aS,CG,qF,MT,Rk,Eo,Dn,UD,ZD,NE,wD,BD,vRT,Fi,Qr,mj,cB,uY,yR,AX,xJ,l4,Et,NC,nb,By,xt,tG,P0,Jq,Xr,qD,Cf,I2,AS,Kq,oI,mJ,rF,vi,ZX,ycx,nE,zt,F0,Lt,Gv,kn,PE,QI,FP,is,Q,jx,ZC,Jt,P,im,Pp,O,PK,JO,O2,aX,cC,RA,IY,JH,jl,Iy,JM,Ua,JG,ns,wd,TA,YP,yc,I9,Bj,NO,II,aJ,X1,HU,Pm,oo,OW,Dd,AP,yH,FA,Av,oH,LP,c2,WT,p8,XR,LI,A2,F3,u8,Gi,t2,Zr,ZQ,az,vV,Hk,XO,dr,TL,KX,uZ,OQ,Tp,v,Z3,D2,GT,Pe,Eq,cu,Lm,dC,wN,VX,VR,EK,KW,Pb,tQ,aC,Vf,Be,tu,i6,Vc,zO,aL,nH,a7,i1,xy,MH,A8,U5,SO,zs,rR,AM,d5,U1,SJ,SU,Tv,XC,iK,GD,Sn,nI,jU,Lj,mb,am,cw,EE,Uz,uh,Kv,oP,YX,BI,y1,M2,iu,mg,zE,bl,Ef,Oo,Tc,Ax,Wf,Un,Ei,U7,t0,Ld,Sz,Zk,fu,ng,Ar,jB,ye,Gj,Zz,Xh,Ca,Ik,JI,Ip,WV,C7,CQ,dz,tK,OR,Bg,DL,b8,j7,oV,TP,Zf,vs,da,xw,dm,rH,ZL,mi,jb,wB,Pu,qh,QC,Yl,Rv,YJ,jv,LB,DO,lz,Rl,Jb,M4,Jp,h7,pr,eN,B5,PI,j4,i9,VV,Dy,lU,xp,UH,Z5,ii,ib,MO,ms,UO,Bc,vp,lk,Gh,XB,ly,cK,O9,yU,nP,KA,Vo,qB,ez,lx,LV,DS,dp,B3,CR,ny,dR,uR,QX,YR,fB,bq,nO,t3,dq,dX,aY,wJ,e4,JB,Id,fZ,TF,Xz,Cg,Hs,uo,pK,eM,Ue,W5,R8,k6,oi,ce,o2,jG,fG,EQ,YB,iX,ou,S9,ey,xd,v6,db,Cm,N6,jg,YO,oz,b6,ef,zQ,Yp,u3,mW,ar,lD,W0,Sw,o0,a1,jp,Xt,Ba,An,LD,YI,OG,ro,DN,ZM,HW,JC,f1,Uk,wI,ob,Ud,K8,by,dI,QM,Sh,tF,z0,Vx,Rw,GY,jZ,h0,CL,uA,a2,fR,iP,MF,Rq,Hn,Zl,pl,a6,P7,DW,Ge,LK,AT,bJ,mp,ub,ds,lj,UV,VS,t7,HG,aE,kM,EH,cX,eL,L8,c8,a,Od,mE,WU,Rn,wv,uq,iD,hb,XX,Kd,yZ,Gs,pm,Tw,wm,FB,Lk,XZ,qz,hQ,Nw,kZ,JT,d9,rI,dD,QZ,BV,E1,wz,B1,M5,Jn,DM,zL,ec,Kx,iO,bU,e7,nj,rl,RAp,ma,cf,E9,nF,FK,Si,vf,Fc,hD,I4,e0,RO,eu,ie,Ea,pu,i2,b0,Ov,qO,RX,kG,Gm,W9,vZ,dW,PA,H2,O7,HI,E4,r7,Tz,Wk,DV,Hp,Nz,Jd,QS,QF,NL,vr,D4,L9u,Ms,Fw,RS,RY,Ys,vg,xG,Vj,VW,RK,DH,ZK,Th,Vju,KB,RKu,xGn,TkQ,VWk,ZKG,DHb,w6W,Hna,z9g,G8,UZ,Fv,WZ,I3,pv,qr,Vfx,Gk,Dsd,Ds,tuj,aI,rG,yh,wO,Tm,rz,CA,YL,KC,xL,As,GE,pR,Vct,hx,D13,u7,St,WZq,vj,pva,CX,cda,TJ,dG,Ng,HV,Nh,fA,tz,jR,PO,c5,ih,mL,bv,pt,Zd,dY,vY,dS,ZW,dZ,Qe,Nu,pF,Ha,nu,be,Pg,jI,Rb,Zw,Pf,F1,waa,uL,Nr,Pi,yj,qI,J3,E5,o5,b5,zI,Zb,id,iV,W4,Fa,x9,d3,X6,xh,wn,uF,cj,HA,br,zT,D7,qL,C4,l9,lP,km,Qt,Dk,A0,rm,eY,OO,BE,Qb,xI,q1,Zj,XP,q6,CK,BO,ZG,Oc,MX,w12,fTP,yL,dM,Y7,WC,Xi,TV,Mq,Oa,n1,xf,L6,Rs,uJ,hm,Ji,Bf,ir,Sa,GN,k8,HJ,S0,V3,Bl,pM,Mh,Md,Lf,fT,pp,Nq,nl,mf,ej,HK,w13,o8,GL,e9,Dw,Xy,uK,mY,fE,mB,XF,iH,wJY,zOQ,W6o,MdQ,YJG,DOe,lPa,Ufa,Raa,w0,w4,w5,w7,w9,w10,w11,c4,z6,Ay,Ed,G1,Os,Dl,Wh,x5,ev,ID,jV,ek,OC,Xm,Jy,ky,fa,WW,vQ,a9,jh,e3,VA,J1,fk,wL,B0,Fq,hw,EZ,no,kB,ae,Iq,w6,jK,uk,K9,RW,xs,FX,Ae,Bt,vR,Pn,hc,hA,fr,a0,NQ,fI,V0,kK,V4,uw,V6,V2,D8,jY,ll,Uf,ik,LfS,NP,Vh,r0,jz,SA,zV,nv,ee,XI,hs,yp,ug,DT,OB,Ra,N9,NW,HS,TG,ts,Kj,VU,Ya,XT,ic,VT,T4,TR,VD,Oh,zy,Nb,Fy,eU,ADW,Ri,kq,Ag,PW]}
\ No newline at end of file
+return[qE,Yy,Ps,rK,fY,Mr,zx,ct,nB,i3,it,Az,QP,QW,n6,Ny,OM,QQ,MA,y4,d7,na,oJ,DG,mN,vH,hh,Em,Sb,rV,Wy,YN,bA,Wq,rv,BK,wj,cv,Fs,SX,ea,D0,as,T5,Aa,u5,Yu,iG,jP,U2,tA,xn,Vb,QH,ST,X2,fJ,Vi,tX,Sg,pA,Mi,Gt,In,Gx,eP,AL,Og,cS,M6,El,zm,SV,aB,ku,KM,cW,DK,qm,ZY,cx,la,Vn,PG,xe,Hw,bn,Im,oB,Aj,oU,qT,KV,BH,mh,G7,wq,Ql,Xp,bP,mX,SN,HD,ni,p3,qj,qW,KR,ew,fs,bX,BL,MC,Mx,j2,yz,lp,pD,I0,QR,Cp,ua,zD,Ul,G0,wb,fq,h4,qk,GI,Tb,tV,BT,yY,kJ,AE,xV,FH,y6,RH,pU,Lq,Mf,BR,r4,aG,J6,K5,UM,UL,rq,nK,kc,ij,ty,Nf,Nc,rj,rh,Zv,Q7,hF,OF,HB,ZJ,mU,eZ,Fl,y5,nV,Zc,ui,D6,DQ,Sm,dx,es,eG,lv,pf,NV,W1,zo,wf,TU,bb,VE,lc,Xu,qM,tk,me,qN,nh,d4,MI,ca,xX,eW,um,Fu,OE,l6,BA,zp,rE,CC,PQ,uz,Yd,U0,AD,Gr,tc,GH,lo,NJ,nd,vt,rQ,EU,LR,MB,hy,r8,aS,CG,qF,MT,Rk,Eo,Dn,UD,ZD,NE,wD,BD,vRT,Fi,Qr,mj,cB,uY,yR,AX,xJ,l4,Et,NC,nb,By,xt,tG,P0,Jq,Xr,qD,Cf,I2,AS,Kq,oI,mJ,rF,vi,ZX,ycx,nE,zt,F0,Lt,Gv,kn,PE,QI,FP,is,Q,jx,ZC,Jt,P,im,Pp,O,PK,JO,O2,aX,cC,RA,IY,JH,jl,Iy,JM,Ua,JG,ns,wd,TA,YP,yc,I9,Bj,NO,II,aJ,X1,HU,Pm,oo,OW,Dd,AP,yH,FA,Av,oH,LP,c2,WT,p8,XR,LI,A2,F3,u8,Gi,t2,Zr,ZQ,az,vV,Hk,XO,dr,TL,KX,uZ,OQ,Tp,v,Z3,D2,GT,Pe,Eq,cu,Lm,dC,wN,VX,VR,EK,KW,Pb,tQ,G6,Vf,aC,tu,Be,Vc,i6,WZ,zO,aL,nH,a7,i1,xy,MH,A8,U5,SO,zs,rR,AM,d5,U1,SJ,SU,Tv,XC,iK,GD,Sn,nI,jU,Lj,mb,am,cw,EE,Uz,uh,Kv,oP,YX,BI,y1,M2,iu,mg,zE,bl,Ef,Oo,Tc,Ax,Wf,Un,Ei,U7,t0,Ld,Sz,Zk,fu,ng,Ar,jB,ye,Gj,Zz,Xh,Ca,Ik,JI,Ip,WV,C7,CQ,dz,tK,OR,Bg,DL,b8,j7,oV,TP,Zf,vs,da,xw,dm,rH,ZL,mi,jb,wB,Pu,qh,QC,Yl,Rv,YJ,jv,LB,DO,lz,Rl,Jb,M4,Jp,h7,pr,eN,B5,PI,j4,i9,VV,Dy,lU,xp,UH,Z5,ii,ib,MO,ms,UO,Bc,vp,lk,Gh,XB,ly,cK,O9,yU,nP,KA,Vo,qB,ez,lx,LV,DS,dp,B3,CR,ny,dR,uR,QX,YR,fB,bq,nO,t3,dq,dX,aY,wJ,e4,JB,Id,fZ,TF,Xz,Cg,Hs,uo,pK,eM,Ue,W5,R8,k6,oi,ce,o2,jG,fG,EQ,YB,iX,ou,S9,ey,xd,v6,db,Cm,N6,jg,YO,oz,b6,ef,zQ,Yp,u3,mW,ar,lD,W0,Sw,o0,a1,jp,Xt,Ba,An,LD,YI,OG,ro,DN,ZM,HW,JC,f1,Uk,wI,ob,Ud,K8,by,dI,QM,Sh,tF,z0,Vx,Rw,GY,jZ,h0,CL,uA,a2,fR,iP,MF,Rq,Hn,Zl,pl,a6,P7,DW,Ge,LK,AT,bJ,mp,ub,ds,lj,UV,VS,t7,HG,aE,kM,EH,cX,eL,L8,c8,a,Od,mE,WU,Rn,wv,uq,iD,hb,XX,Kd,yZ,Gs,pm,Tw,wm,FB,Lk,XZ,qz,hQ,Nw,kZ,JT,d9,rI,dD,QZ,BV,E1,wz,B1,M5,Jn,DM,zL,ec,Kx,iO,bU,e7,nj,rl,RAp,ma,cf,E9,nF,FK,Si,vf,Fc,hD,I4,e0,RO,eu,ie,Ea,pu,i2,b0,Ov,qO,RX,kG,Gm,W9,vZ,dW,PA,H2,O7,HI,E4,r7,Tz,Wk,DV,Hp,Nz,Jd,QS,QF,NL,vr,D4,L9u,Ms,Fw,RS,RY,Ys,vg,xG,Vj,VW,RK,DH,ZK,Th,Vju,KB,RKu,xGn,TkQ,VWk,ZKG,DHb,w6W,Hna,z9g,G8,UZ,Fv,pv,I3,Vfx,qr,Dsd,Gk,tuj,Ds,Vct,aI,rG,yh,wO,Tm,rz,CA,YL,KC,xL,As,GE,pR,D13,hx,WZq,u7,St,pva,vj,cda,CX,waa,TJ,dG,Ng,HV,Nh,fA,tz,jR,PO,c5,ih,mL,bv,pt,Zd,dY,vY,dS,ZW,dZ,Qe,Nu,pF,Ha,nu,be,Pg,jI,Rb,Zw,Pf,F1,V0,uL,Nr,Pi,yj,qI,J3,E5,o5,b5,zI,Zb,id,iV,W4,Fa,x9,d3,X6,xh,wn,uF,cj,HA,br,zT,D7,qL,C4,l9,lP,km,Qt,Dk,A0,rm,eY,OO,BE,Qb,xI,q1,Zj,XP,q6,CK,BO,ZG,Oc,MX,w12,fTP,yL,dM,Y7,WC,Xi,TV,Mq,Oa,n1,xf,L6,Rs,uJ,hm,Ji,Bf,ir,Sa,GN,k8,HJ,S0,V3,Bl,pM,Mh,Md,Lf,fT,pp,Nq,nl,mf,ej,HK,w13,o8,GL,e9,PD,Xy,uK,mY,fE,mB,XF,iH,wJY,zOQ,W6o,MdQ,YJG,DOe,lPa,Ufa,Raa,w0,w4,w5,w7,w9,w10,w11,c4,z6,Ay,Ed,G1,Os,Dl,Wh,x5,ev,ID,jV,ek,OC,Xm,Jy,ky,fa,WW,vQ,a9,jh,e3,VA,J1,fk,wL,B0,Fq,hw,EZ,no,kB,ae,Iq,w6,jK,uk,K9,RW,xs,FX,Ae,Bt,vR,Pn,hc,hA,fr,a0,NQ,fI,V4,kK,V6,uw,V8,V2,D8,jY,ll,Uf,ik,LfS,NP,Vh,r0,jz,SA,zV,nv,ee,XI,hs,yp,ug,DT,OB,Ra,N9,NW,HS,TG,ts,Kj,VU,Ya,XT,ic,VT,T4,TR,VD,Oh,zy,Nb,Fy,eU,ADW,Ri,kq,Ag,PW]}
\ No newline at end of file
diff --git a/runtime/bin/vmservice/client/deployed/web/index_devtools.html b/runtime/bin/vmservice/client/deployed/web/index_devtools.html
index c776551..e931ab5 100644
--- a/runtime/bin/vmservice/client/deployed/web/index_devtools.html
+++ b/runtime/bin/vmservice/client/deployed/web/index_devtools.html
@@ -11,6 +11,24 @@
</head>
<body><polymer-element name="observatory-element">
+</polymer-element><polymer-element name="breakpoint-list" extends="observatory-element">
+ <template>
+ <template if="{{ msg['breakpoints'].isEmpty }}">
+ <div class="panel panel-warning">
+ <div class="panel-body">No breakpoints</div>
+ </div>
+ </template>
+ <template if="{{ msg['breakpoints'].isNotEmpty }}">
+ <ul class="list-group">
+ <template repeat="{{ bpt in msg['breakpoints'] }}">
+ <li class="list-group-item">
+ {{ bpt }}
+ </li>
+ </template>
+ </ul>
+ </template>
+ </template>
+
</polymer-element><polymer-element name="error-view" extends="observatory-element">
<template>
<div class="row">
@@ -297,6 +315,9 @@
<div class="col-md-1">
<a href="{{ app.locationManager.relativeLink(isolate, 'library') }}">Library</a>
</div>
+ <div class="col-md-1">
+ <a href="{{ app.locationManager.relativeLink(isolate, 'debug/breakpoints') }}">Breakpoints</a>
+ </div>
<div class="col-md-8"></div>
</div>
</template>
@@ -514,6 +535,9 @@
<template if="{{ messageType == 'StackTrace' }}">
<stack-trace app="{{ app }}" trace="{{ message }}"></stack-trace>
</template>
+ <template if="{{ messageType == 'BreakpointList' }}">
+ <breakpoint-list app="{{ app }}" msg="{{ message }}"></breakpoint-list>
+ </template>
<!-- If the message type is a RequestError -->
<template if="{{ messageType == 'RequestError' }}">
<error-view app="{{ app }}" error="{{ message['error'] }}"></error-view>
diff --git a/runtime/bin/vmservice/client/deployed/web/index_devtools.html_bootstrap.dart.js b/runtime/bin/vmservice/client/deployed/web/index_devtools.html_bootstrap.dart.js
index 1cb385f..5e54f7a 100644
--- a/runtime/bin/vmservice/client/deployed/web/index_devtools.html_bootstrap.dart.js
+++ b/runtime/bin/vmservice/client/deployed/web/index_devtools.html_bootstrap.dart.js
@@ -7782,7 +7782,7 @@
$$.Y7=[A,{"":"v;wc,nn,lv,Pp",
call$2:function(a,b){return this.nn.call(this.wc,this.lv,a,b)},
$is_bh:true}]
-$$.Dw=[T,{"":"v;wc,nn,lv,Pp",
+$$.PD=[T,{"":"v;wc,nn,lv,Pp",
call$3:function(a,b,c){return this.nn.call(this.wc,a,b,c)}}]
$$.zy=[H,{"":"Tp;call$2,$name",$is_bh:true}]
$$.Nb=[H,{"":"Tp;call$1,$name",$is_HB:true,$is_Dv:true}]
@@ -7805,7 +7805,7 @@
call$catchAll:function(){return{onError:null,radix:null}},
$is_HB:true,
$is_Dv:true}]
-;init.mangledNames={gB:"length",gDb:"_cachedDeclarations",gEI:"prefix",gF1:"isolate",gFF:"source",gFJ:"__$cls",gFT:"__$instruction",gFU:"_cachedMethodsMap",gG1:"message",gH8:"_fieldsDescriptor",gHt:"_fieldsMetadata",gKM:"$",gLA:"src",gLf:"__$field",gLy:"_cachedSetters",gM2:"_cachedVariables",gMj:"function",gNI:"instruction",gNl:"script",gO3:"url",gOk:"_cachedMetadata",gP:"value",gP2:"_collapsed",gPw:"__$isolate",gPy:"__$error",gQG:"app",gRu:"cls",gT1:"_cachedGetters",gTn:"json",gTx:"_jsConstructorOrInterceptor",gUF:"_cachedTypeVariables",gUz:"__$script",gV4:"__$trace",gVA:"__$displayValue",gVB:"error_obj",gWL:"_mangledName",gXB:"_message",gXJ:"lines",gXR:"scripts",gXf:"__$iconClass",gXh:"__$instance",gZ6:"locationManager",gZw:"__$code",ga:"a",gai:"displayValue",gb:"b",gb0:"_cachedConstructors",gcC:"hash",geV:"paddedLine",geb:"__$json",gfY:"kind",ghO:"__$error_obj",ghf:"instance",gi0:"__$name",gi2:"isolates",giI:"__$library",giK:"__$instance",gjO:"id",gjd:"_cachedMethods",gk5:"__$devtools",gkc:"error",gkf:"_count",gl7:"iconClass",glD:"currentHashUri",gle:"_metadata",glw:"requestManager",gn2:"responses",gnI:"isolateManager",gnz:"_owner",goc:"name",gpz:"_jsConstructorCache",gqN:"_superclass",gql:"__$function",gqm:"_cachedSuperinterfaces",gt0:"field",gtB:"_cachedFields",gtD:"library",gtH:"__$app",gtN:"trace",gtT:"code",guA:"_cachedMembers",gvH:"index",gvX:"__$source",gvt:"__$field",gxj:"collapsed",gzd:"currentHash",gzj:"devtools"};init.mangledGlobalNames={DI:"_closeIconClass",Vl:"_openIconClass"};(function (reflectionData) {
+;init.mangledNames={gB:"length",gDb:"_cachedDeclarations",gEI:"prefix",gF1:"isolate",gFF:"source",gFJ:"__$cls",gFT:"__$instruction",gFU:"_cachedMethodsMap",gG1:"message",gH8:"_fieldsDescriptor",gHt:"_fieldsMetadata",gKM:"$",gLA:"src",gLf:"__$field",gLy:"_cachedSetters",gM2:"_cachedVariables",gMj:"function",gNI:"instruction",gNl:"script",gO3:"url",gOk:"_cachedMetadata",gP:"value",gP2:"_collapsed",gPw:"__$isolate",gPy:"__$error",gQG:"app",gRu:"cls",gT1:"_cachedGetters",gTn:"json",gTx:"_jsConstructorOrInterceptor",gUF:"_cachedTypeVariables",gUz:"__$script",gV4:"__$trace",gVA:"__$displayValue",gVB:"error_obj",gWL:"_mangledName",gXB:"_message",gXJ:"lines",gXR:"scripts",gXf:"__$iconClass",gXh:"__$instance",gZ6:"locationManager",gZw:"__$code",ga:"a",gai:"displayValue",gb:"b",gb0:"_cachedConstructors",gcC:"hash",geE:"__$msg",geV:"paddedLine",geb:"__$json",gfY:"kind",ghO:"__$error_obj",ghf:"instance",gi0:"__$name",gi2:"isolates",giI:"__$library",giK:"__$instance",gjO:"id",gjd:"_cachedMethods",gk5:"__$devtools",gkc:"error",gkf:"_count",gl7:"iconClass",glD:"currentHashUri",gle:"_metadata",glw:"requestManager",gn2:"responses",gnI:"isolateManager",gnz:"_owner",goc:"name",gpz:"_jsConstructorCache",gqN:"_superclass",gql:"__$function",gqm:"_cachedSuperinterfaces",grs:"msg",gt0:"field",gtB:"_cachedFields",gtD:"library",gtH:"__$app",gtN:"trace",gtT:"code",guA:"_cachedMembers",gvH:"index",gvX:"__$source",gvt:"__$field",gxj:"collapsed",gzd:"currentHash",gzj:"devtools"};init.mangledGlobalNames={DI:"_closeIconClass",Vl:"_openIconClass"};(function (reflectionData) {
function map(x){x={x:x};delete x.x;return x}
if (!init.libraries) init.libraries = [];
if (!init.mangledNames) init.mangledNames = map();
@@ -9438,14 +9438,38 @@
t:function(a,b){if(!J.xC(b,0))H.vh(P.N(b))
return this.zO},
"+[]:1:0":0,
-$isOd:true}}],["app_bootstrap","index.html_bootstrap.dart",,E,{E2:function(){$.x2=["package:observatory/src/observatory_elements/observatory_element.dart","package:observatory/src/observatory_elements/error_view.dart","package:observatory/src/observatory_elements/field_ref.dart","package:observatory/src/observatory_elements/instance_ref.dart","package:observatory/src/observatory_elements/class_view.dart","package:observatory/src/observatory_elements/disassembly_entry.dart","package:observatory/src/observatory_elements/code_view.dart","package:observatory/src/observatory_elements/collapsible_content.dart","package:observatory/src/observatory_elements/field_view.dart","package:observatory/src/observatory_elements/function_view.dart","package:observatory/src/observatory_elements/isolate_summary.dart","package:observatory/src/observatory_elements/isolate_list.dart","package:observatory/src/observatory_elements/instance_view.dart","package:observatory/src/observatory_elements/json_view.dart","package:observatory/src/observatory_elements/library_view.dart","package:observatory/src/observatory_elements/source_view.dart","package:observatory/src/observatory_elements/script_view.dart","package:observatory/src/observatory_elements/stack_trace.dart","package:observatory/src/observatory_elements/message_viewer.dart","package:observatory/src/observatory_elements/navigation_bar.dart","package:observatory/src/observatory_elements/response_viewer.dart","package:observatory/src/observatory_elements/observatory_application.dart","index.html.0.dart"]
+$isOd:true}}],["app_bootstrap","index.html_bootstrap.dart",,E,{E2:function(){$.x2=["package:observatory/src/observatory_elements/observatory_element.dart","package:observatory/src/observatory_elements/breakpoint_list.dart","package:observatory/src/observatory_elements/error_view.dart","package:observatory/src/observatory_elements/field_ref.dart","package:observatory/src/observatory_elements/instance_ref.dart","package:observatory/src/observatory_elements/class_view.dart","package:observatory/src/observatory_elements/disassembly_entry.dart","package:observatory/src/observatory_elements/code_view.dart","package:observatory/src/observatory_elements/collapsible_content.dart","package:observatory/src/observatory_elements/field_view.dart","package:observatory/src/observatory_elements/function_view.dart","package:observatory/src/observatory_elements/isolate_summary.dart","package:observatory/src/observatory_elements/isolate_list.dart","package:observatory/src/observatory_elements/instance_view.dart","package:observatory/src/observatory_elements/json_view.dart","package:observatory/src/observatory_elements/library_view.dart","package:observatory/src/observatory_elements/source_view.dart","package:observatory/src/observatory_elements/script_view.dart","package:observatory/src/observatory_elements/stack_trace.dart","package:observatory/src/observatory_elements/message_viewer.dart","package:observatory/src/observatory_elements/navigation_bar.dart","package:observatory/src/observatory_elements/response_viewer.dart","package:observatory/src/observatory_elements/observatory_application.dart","index.html.0.dart"]
$.uP=!1
-A.Ok()}},1],["class_view_element","package:observatory/src/observatory_elements/class_view.dart",,Z,{aC:{"":["Vf;FJ%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+A.Ok()}},1],["breakpoint_list_element","package:observatory/src/observatory_elements/breakpoint_list.dart",,B,{G6:{"":["Vf;eE%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+grs:function(a){return a.eE
+"38,39,40"},
+"+msg":1,
+srs:function(a,b){a.eE=this.pD(a,C.Ry,a.eE,b)
+"41,32,38,39"},
+"+msg=":1,
+"@":function(){return[C.PT]},
+static:{Dw:function(a){var z,y,x,w,v,u
+z=H.B7([],P.L5(null,null,null,null,null))
+z=R.Jk(z)
+y=$.Nd()
+x=P.Py(null,null,null,J.O,W.I0)
+w=J.O
+v=W.cv
+u=new V.br(P.Py(null,null,null,w,v),null,null)
+H.VM(u,[w,v])
+a.eE=z
+a.Ye=y
+a.mT=x
+a.KM=u
+C.J0.ZL(a)
+C.J0.FH(a)
+return a
+"9"},"+new BreakpointListElement$created:0:0":1}},"+BreakpointListElement": [42],Vf:{"":"uL+Pi;",$isd3:true}}],["class_view_element","package:observatory/src/observatory_elements/class_view.dart",,Z,{aC:{"":["tu;FJ%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gRu:function(a){return a.FJ
-"37,38,39"},
+"38,39,40"},
"+cls":1,
sRu:function(a,b){a.FJ=this.pD(a,C.XA,a.FJ,b)
-"40,31,37,38"},
+"41,32,38,39"},
"+cls=":1,
"@":function(){return[C.aQ]},
static:{zg:function(a){var z,y,x,w,v
@@ -9461,12 +9485,12 @@
C.kk.ZL(a)
C.kk.FH(a)
return a
-"9"},"+new ClassViewElement$created:0:0":1}},"+ClassViewElement": [41],Vf:{"":"uL+Pi;",$isd3:true}}],["code_view_element","package:observatory/src/observatory_elements/code_view.dart",,F,{Be:{"":["tu;Zw%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"10"},"+new ClassViewElement$created:0:0":1}},"+ClassViewElement": [43],tu:{"":"uL+Pi;",$isd3:true}}],["code_view_element","package:observatory/src/observatory_elements/code_view.dart",,F,{Be:{"":["Vc;Zw%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gtT:function(a){return a.Zw
-"37,38,39"},
+"38,39,40"},
"+code":1,
stT:function(a,b){a.Zw=this.pD(a,C.b1,a.Zw,b)
-"40,31,37,38"},
+"41,32,38,39"},
"+code=":1,
grK:function(a){var z=a.Zw
if(z!=null&&J.UQ(z,"is_optimized")!=null)return"panel panel-success"
@@ -9490,41 +9514,41 @@
C.YD.ZL(a)
C.YD.FH(a)
return a
-"10"},"+new CodeViewElement$created:0:0":1}},"+CodeViewElement": [42],tu:{"":"uL+Pi;",$isd3:true}}],["collapsible_content_element","package:observatory/src/observatory_elements/collapsible_content.dart",,R,{i6:{"":["Vc;Xf%-,VA%-,P2%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"11"},"+new CodeViewElement$created:0:0":1}},"+CodeViewElement": [44],Vc:{"":"uL+Pi;",$isd3:true}}],["collapsible_content_element","package:observatory/src/observatory_elements/collapsible_content.dart",,R,{i6:{"":["WZ;Xf%-,VA%-,P2%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gl7:function(a){return a.Xf
-"8,38,43"},
+"8,39,45"},
"+iconClass":1,
sl7:function(a,b){a.Xf=this.pD(a,C.Di,a.Xf,b)
-"40,31,8,38"},
+"41,32,8,39"},
"+iconClass=":1,
gai:function(a){return a.VA
-"8,38,43"},
+"8,39,45"},
"+displayValue":1,
sai:function(a,b){a.VA=this.pD(a,C.Jw,a.VA,b)
-"40,31,8,38"},
+"41,32,8,39"},
"+displayValue=":1,
gxj:function(a){return a.P2
-"44"},
+"46"},
"+collapsed":1,
sxj:function(a,b){a.P2=b
this.dR(a)
-"40,45,44"},
+"41,47,46"},
"+collapsed=":1,
i4:function(a){Z.uL.prototype.i4.call(this,a)
this.dR(a)
-"40"},
+"41"},
"+enteredView:0:0":1,
rS:function(a,b,c,d){a.P2=a.P2!==!0
this.dR(a)
this.dR(a)
-"40,46,47,48,40,49,50"},
+"41,48,49,50,41,51,52"},
"+toggleDisplay:3:0":1,
dR:function(a){var z,y
z=a.P2
y=a.Xf
if(z===!0){a.Xf=this.pD(a,C.Di,y,"glyphicon glyphicon-chevron-down")
a.VA=this.pD(a,C.Jw,a.VA,"none")}else{a.Xf=this.pD(a,C.Di,y,"glyphicon glyphicon-chevron-up")
-a.VA=this.pD(a,C.Jw,a.VA,"block")}"40"},
+a.VA=this.pD(a,C.Jw,a.VA,"block")}"41"},
"+_refresh:0:0":1,
"@":function(){return[C.Gu]},
static:{"":"Vl<-,DI<-",IT:function(a){var z,y,x,w,v
@@ -9543,7 +9567,7 @@
C.j8.ZL(a)
C.j8.FH(a)
return a
-"11"},"+new CollapsibleContentElement$created:0:0":1}},"+CollapsibleContentElement": [51],Vc:{"":"uL+Pi;",$isd3:true}}],["custom_element.polyfill","package:custom_element/polyfill.dart",,B,{G9:function(){if($.LX()==null)return!0
+"12"},"+new CollapsibleContentElement$created:0:0":1}},"+CollapsibleContentElement": [53],WZ:{"":"uL+Pi;",$isd3:true}}],["custom_element.polyfill","package:custom_element/polyfill.dart",,B,{G9:function(){if($.LX()==null)return!0
var z=J.UQ($.LX(),"CustomElements")
if(z==null)return"register" in document
return J.xC(J.UQ(z,"ready"),!0)},zO:{"":"Tp;",
@@ -10111,7 +10135,7 @@
if(typeof y==="object"&&y!==null&&!!z.$isZk)if(!("$reflectable" in y.dl))H.Hz(J.Z0(a))
return H.vn(y.qj(b,c))},
"+invoke:3:0":0,
-"*invoke":[40],
+"*invoke":[41],
CI:function(a,b){return this.F2(a,b,null)},
"+invoke:2:0":0,
Z0:function(a){return $[a]},
@@ -10251,7 +10275,7 @@
"+declarations":0,
F2:function(a,b,c){throw H.b(P.lr(this,a,b,c,null))},
"+invoke:3:0":0,
-"*invoke":[40],
+"*invoke":[41],
CI:function(a,b){return this.F2(a,b,null)},
"+invoke:2:0":0,
rN:function(a){throw H.b(P.lr(this,a,null,null,null))},
@@ -10273,7 +10297,7 @@
y=z+":"+b.length+":0"
return this.tu(a,0,y,b)},
"+invoke:3:0":0,
-"*invoke":[40],
+"*invoke":[41],
CI:function(a,b){return this.F2(a,b,null)},
"+invoke:2:0":0,
tu:function(a,b,c,d){var z,y,x,w,v,u,t,s
@@ -10400,7 +10424,7 @@
return z},
F2:function(a,b,c){return this.NK.F2(a,b,c)},
"+invoke:3:0":0,
-"*invoke":[40],
+"*invoke":[41],
CI:function(a,b){return this.F2(a,b,null)},
"+invoke:2:0":0,
gHA:function(){return!1},
@@ -10452,7 +10476,7 @@
y=J.x(z)
if(typeof z==="object"&&z!==null&&!!y.$isGv)return z.constructor
else return z
-"40"},
+"41"},
"+_jsConstructor":1,
gDI:function(){var z=this.b0
if(z!=null)return z
@@ -10460,7 +10484,7 @@
H.VM(z,[P.wv,P.RS])
this.b0=z
return z
-"52"},
+"54"},
"+constructors":1,
ly:function(a){var z,y,x,w,v,u,t,s,r,q,p,o,n,m,l,k
z=this.gaB().prototype
@@ -10505,14 +10529,14 @@
l=!1}s=H.Sd(k,o,!l,l)
x.push(s)
s.nz=a}return x
-"53,54,55"},
+"55,56,57"},
"+_getMethodsWithOwner:1:0":1,
gEO:function(){var z=this.jd
if(z!=null)return z
z=this.ly(this)
this.jd=z
return z
-"53"},
+"55"},
"+_methods":1,
ws:function(a){var z,y,x,w
z=[]
@@ -10526,14 +10550,14 @@
w=init.statics[this.WL]
if(w!=null)H.jw(a,w[""],!0,z)
return z
-"56,57,55"},
+"58,59,57"},
"+_getFieldsWithOwner:1:0":1,
gKn:function(){var z=this.tB
if(z!=null)return z
z=this.ws(this)
this.tB=z
return z
-"56"},
+"58"},
"+_fields":1,
gtx:function(){var z=this.FU
if(z!=null)return z
@@ -10541,7 +10565,7 @@
H.VM(z,[P.wv,P.RS])
this.FU=z
return z
-"52"},
+"54"},
"+methods":1,
gZ3:function(){var z,y,x
z=this.M2
@@ -10552,7 +10576,7 @@
H.VM(z,[P.wv,P.RY])
this.M2=z
return z
-"58"},
+"60"},
"+variables":1,
glc:function(a){var z=this.uA
if(z!=null)return z
@@ -10560,7 +10584,7 @@
H.VM(z,[P.wv,P.QF])
this.uA=z
return z
-"59"},
+"61"},
"+members":1,
gYK:function(){var z,y
z=this.Db
@@ -10574,7 +10598,7 @@
H.VM(z,[P.wv,P.NL])
this.Db=z
return z
-"60"},
+"62"},
"+declarations":1,
PU:function(a,b){var z,y
z=J.UQ(this.gZ3(),a)
@@ -10582,7 +10606,7 @@
if(!(y in $))throw H.b(H.Pa("Cannot find \""+y+"\" in current isolate."))
$[y]=b
return H.vn(b)}throw H.b(P.lr(this,H.X7(a),[b],null,null))
-"61,62,63,64,0"},
+"63,64,65,66,0"},
"+setField:2:0":1,
rN:function(a){var z,y
z=J.UQ(this.gZ3(),a)
@@ -10590,7 +10614,7 @@
if(!(y in $))throw H.b(H.Pa("Cannot find \""+y+"\" in current isolate."))
if(y in init.lazies)return H.vn($[init.lazies[y]]())
else return H.vn($[y])}throw H.b(P.lr(this,a,null,null,null))
-"61,62,63"},
+"63,64,65"},
"+getField:1:0":1,
gh7:function(){var z,y,x,w,v,u,t
if(this.nz==null){z=this.Tx
@@ -10609,7 +10633,7 @@
z=new H.MH(null,y,z.ew)
z.$builtinTypeInfo=[u,t]
for(;z.G();)for(y=J.GP(z.mD);y.G();)J.pP(y.gl())}if(this.nz==null)throw H.b(new P.lj("Class \""+H.d(J.Z0(this.If))+"\" has no owner"))}return this.nz
-"65"},
+"67"},
"+owner":1,
gc9:function(){var z=this.Ok
if(z!=null)return z
@@ -10618,7 +10642,7 @@
H.VM(z,[P.vr])
this.Ok=z
return z
-"66"},
+"68"},
"+metadata":1,
gAY:function(){var z,y,x,w,v,u
if(this.qN==null){z=init.typeInformation[this.WL]
@@ -10632,7 +10656,7 @@
u=v.length
if(u>1){if(u!==2)throw H.b(H.Pa("Strange mixin: "+H.d(y)))
this.qN=H.jO(v[0])}else this.qN=x.n(w,"")?this:H.jO(w)}}return J.xC(this.qN,this)?null:this.qN
-"67"},
+"69"},
"+superclass":1,
F2:function(a,b,c){var z
if(c!=null&&J.FN(c)!==!0)throw H.b(P.f("Named arguments are not implemented."))
@@ -10640,16 +10664,16 @@
if(z==null||!z.gFo())throw H.b(P.lr(this,a,b,c,null))
if(!z.yR())H.Hz(J.Z0(a))
return H.vn(z.qj(b,c))
-"61,68,63,69,70,71,72"},
+"63,70,65,71,72,73,74"},
"+invoke:3:0":1,
-"*invoke":[40],
+"*invoke":[41],
CI:function(a,b){return this.F2(a,b,null)},
"+invoke:2:0":1,
gHA:function(){return!0
-"44"},
+"46"},
"+isOriginalDeclaration":1,
gJi:function(){return this
-"67"},
+"69"},
"+originalDeclaration":1,
MR:function(a){var z,y,x
z=init.typeInformation[this.WL]
@@ -10659,14 +10683,14 @@
y=new P.Yp(x)
H.VM(y,[P.Ms])
return y
-"73,74,55"},
+"75,76,57"},
"+_getSuperinterfacesWithOwner:1:0":1,
gkZ:function(){var z=this.qm
if(z!=null)return z
z=this.MR(this)
this.qm=z
return z
-"73"},
+"75"},
"+superinterfaces":1,
gNy:function(){var z,y,x,w,v
z=this.UF
@@ -10679,34 +10703,34 @@
H.VM(z,[null])
this.UF=z
return z
-"75"},
+"77"},
"+typeVariables":1,
gw8:function(){return C.hU
-"76"},
+"78"},
"+typeArguments":1,
$isWf:true,
$isMs:true,
$isQF:true,
$isL9u:true,
-$isNL:true},"+JsClassMirror": [77, 67],Un:{"":"EE+M2;",$isQF:true},Ei:{"":"Tp;a-",
+$isNL:true},"+JsClassMirror": [79, 69],Un:{"":"EE+M2;",$isQF:true},Ei:{"":"Tp;a-",
call$2:function(a,b){J.kW(this.a,a,b)
-"40,78,63,31,79"},
+"41,80,65,32,81"},
"+call:2:0":1,
$isEH:true,
-$is_bh:true},"+JsClassMirror_declarations_addToResult": [80],U7:{"":"Tp;b-",
+$is_bh:true},"+JsClassMirror_declarations_addToResult": [82],U7:{"":"Tp;b-",
call$1:function(a){J.kW(this.b,a.gIf(),a)
return a
-"40,81,40"},
+"41,83,41"},
"+call:1:0":1,
$isEH:true,
$is_HB:true,
-$is_Dv:true},"+JsClassMirror_declarations_closure": [80],t0:{"":"Tp;a-",
+$is_Dv:true},"+JsClassMirror_declarations_closure": [82],t0:{"":"Tp;a-",
call$1:function(a){return H.Jf(this.a,init.metadata[a])
-"67,82,30"},
+"69,84,31"},
"+call:1:0":1,
$isEH:true,
$is_HB:true,
-$is_Dv:true},"+JsClassMirror__getSuperinterfacesWithOwner_lookupType": [80],Ld:{"":"am;ao<,V5<,Fo<,n6,nz,le,If",
+$is_Dv:true},"+JsClassMirror__getSuperinterfacesWithOwner_lookupType": [82],Ld:{"":"am;ao<,V5<,Fo<,n6,nz,le,If",
gOO:function(){return"VariableMirror"},
"+_prettyName":0,
gr9:function(a){return $.Cr()},
@@ -11373,7 +11397,7 @@
$is_Dv:true},dm:{"":"Tp;b",
call$2:function(a,b){this.b.K5(a,b)},
"+call:2:0":0,
-"*call":[40],
+"*call":[41],
call$1:function(a){return this.call$2(a,null)},
"+call:1:0":0,
$isEH:true,
@@ -11442,7 +11466,7 @@
if(typeof y!=="object"||y===null||!x.$isvs){z.a=P.Dt(null)
z.a.E6(a,b)}P.HZ(z.a,this.h)},
"+call:2:0":0,
-"*call":[40],
+"*call":[41],
call$1:function(a){return this.call$2(a,null)},
"+call:1:0":0,
$isEH:true,
@@ -14592,7 +14616,7 @@
gor:function(a){return J.pO(this.iY)},
"+isNotEmpty":0,
$isL8:true}}],["dart.dom.html","dart:html",,W,{lq:function(){return window
-"12"},"+window":1,UE:function(a){if(P.F7()===!0)return"webkitTransitionEnd"
+"13"},"+window":1,UE:function(a){if(P.F7()===!0)return"webkitTransitionEnd"
else if(P.dg()===!0)return"oTransitionEnd"
return"transitionend"},r3:function(a,b){return document.createElement(a)},It:function(a,b,c){return W.lt(a,null,null,b,null,null,null,c).ml(new W.Kx())},lt:function(a,b,c,d,e,f,g,h){var z,y,x,w
z=W.fJ
@@ -14663,7 +14687,7 @@
q={prototype: s}
if(!J.xC(w,"HTMLElement"))if(!v)q.extends=e
b.register(c,q)},aF:function(a){if(J.xC($.X3,C.NU))return a
-return $.X3.oj(a,!0)},qE:{"":"cv;","%":"HTMLAppletElement|HTMLBRElement|HTMLBaseFontElement|HTMLBodyElement|HTMLCanvasElement|HTMLContentElement|HTMLDListElement|HTMLDataListElement|HTMLDetailsElement|HTMLDialogElement|HTMLDirectoryElement|HTMLDivElement|HTMLFontElement|HTMLFrameElement|HTMLFrameSetElement|HTMLHRElement|HTMLHeadElement|HTMLHeadingElement|HTMLHtmlElement|HTMLMarqueeElement|HTMLMenuElement|HTMLModElement|HTMLOptGroupElement|HTMLParagraphElement|HTMLPreElement|HTMLQuoteElement|HTMLShadowElement|HTMLSpanElement|HTMLTableCaptionElement|HTMLTableCellElement|HTMLTableColElement|HTMLTableDataCellElement|HTMLTableElement|HTMLTableHeaderCellElement|HTMLTableRowElement|HTMLTableSectionElement|HTMLTitleElement|HTMLUListElement|HTMLUnknownElement;HTMLElement;Sa|GN|ir|Nr|uL|Vf|aC|tu|Be|Vc|i6|WZ|Fv|pv|I3|Vfx|qr|Dsd|Gk|tuj|Ds|Vct|pR|D13|hx|u7|WZq|St|pva|vj|cda|CX|Nh|ih|waa|F1|XP|NQ|V0|fI|V4|kK|V6|uw"},Yy:{"":"Gv;",$isList:true,
+return $.X3.oj(a,!0)},qE:{"":"cv;","%":"HTMLAppletElement|HTMLBRElement|HTMLBaseFontElement|HTMLBodyElement|HTMLCanvasElement|HTMLContentElement|HTMLDListElement|HTMLDataListElement|HTMLDetailsElement|HTMLDialogElement|HTMLDirectoryElement|HTMLDivElement|HTMLFontElement|HTMLFrameElement|HTMLFrameSetElement|HTMLHRElement|HTMLHeadElement|HTMLHeadingElement|HTMLHtmlElement|HTMLMarqueeElement|HTMLMenuElement|HTMLModElement|HTMLOptGroupElement|HTMLParagraphElement|HTMLPreElement|HTMLQuoteElement|HTMLShadowElement|HTMLSpanElement|HTMLTableCaptionElement|HTMLTableCellElement|HTMLTableColElement|HTMLTableDataCellElement|HTMLTableElement|HTMLTableHeaderCellElement|HTMLTableRowElement|HTMLTableSectionElement|HTMLTitleElement|HTMLUListElement|HTMLUnknownElement;HTMLElement;Sa|GN|ir|Nr|uL|Vf|G6|tu|aC|Vc|Be|WZ|i6|pv|Fv|Vfx|I3|Dsd|qr|tuj|Gk|Vct|Ds|D13|pR|WZq|hx|u7|pva|St|cda|vj|waa|CX|Nh|ih|V0|F1|XP|NQ|V4|fI|V6|kK|V8|uw"},Yy:{"":"Gv;",$isList:true,
$asWO:function(){return[W.M5]},
$isqC:true,
$iscX:true,
@@ -15697,12 +15721,12 @@
$iscX:true,
$ascX:function(){return[J.im]},
$isXj:true,
-static:{"":"U9",}}}],["disassembly_entry_element","package:observatory/src/observatory_elements/disassembly_entry.dart",,E,{Fv:{"":["WZ;FT%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+static:{"":"U9",}}}],["disassembly_entry_element","package:observatory/src/observatory_elements/disassembly_entry.dart",,E,{Fv:{"":["pv;FT%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gNI:function(a){return a.FT
-"37,38,39"},
+"38,39,40"},
"+instruction":1,
sNI:function(a,b){a.FT=this.pD(a,C.eJ,a.FT,b)
-"40,31,37,38"},
+"41,32,38,39"},
"+instruction=":1,
"@":function(){return[C.Vy]},
static:{AH:function(a){var z,y,x,w,v,u
@@ -15721,18 +15745,18 @@
C.Tl.ZL(a)
C.Tl.FH(a)
return a
-"13"},"+new DisassemblyEntryElement$created:0:0":1}},"+DisassemblyEntryElement": [83],WZ:{"":"uL+Pi;",$isd3:true}}],["error_view_element","package:observatory/src/observatory_elements/error_view.dart",,F,{I3:{"":["pv;Py%-,hO%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"14"},"+new DisassemblyEntryElement$created:0:0":1}},"+DisassemblyEntryElement": [85],pv:{"":"uL+Pi;",$isd3:true}}],["error_view_element","package:observatory/src/observatory_elements/error_view.dart",,F,{I3:{"":["Vfx;Py%-,hO%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gkc:function(a){return a.Py
-"8,38,39"},
+"8,39,40"},
"+error":1,
skc:function(a,b){a.Py=this.pD(a,C.YU,a.Py,b)
-"40,31,8,38"},
+"41,32,8,39"},
"+error=":1,
gVB:function(a){return a.hO
-"40,38,39"},
+"41,39,40"},
"+error_obj":1,
sVB:function(a,b){a.hO=this.pD(a,C.Yn,a.hO,b)
-"40,31,40,38"},
+"41,32,41,39"},
"+error_obj=":1,
"@":function(){return[C.uW]},
static:{TW:function(a){var z,y,x,w,v
@@ -15749,12 +15773,12 @@
C.OD.ZL(a)
C.OD.FH(a)
return a
-"14"},"+new ErrorViewElement$created:0:0":1}},"+ErrorViewElement": [84],pv:{"":"uL+Pi;",$isd3:true}}],["field_ref_element","package:observatory/src/observatory_elements/field_ref.dart",,D,{qr:{"":["Vfx;Lf%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"15"},"+new ErrorViewElement$created:0:0":1}},"+ErrorViewElement": [86],Vfx:{"":"uL+Pi;",$isd3:true}}],["field_ref_element","package:observatory/src/observatory_elements/field_ref.dart",,D,{qr:{"":["Dsd;Lf%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gt0:function(a){return a.Lf
-"37,38,39"},
+"38,39,40"},
"+field":1,
st0:function(a,b){a.Lf=this.pD(a,C.WQ,a.Lf,b)
-"40,31,37,38"},
+"41,32,38,39"},
"+field=":1,
"@":function(){return[C.ht]},
static:{ip:function(a){var z,y,x,w,v
@@ -15770,12 +15794,12 @@
C.WR.ZL(a)
C.WR.FH(a)
return a
-"15"},"+new FieldRefElement$created:0:0":1}},"+FieldRefElement": [85],Vfx:{"":"uL+Pi;",$isd3:true}}],["field_view_element","package:observatory/src/observatory_elements/field_view.dart",,A,{Gk:{"":["Dsd;vt%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"16"},"+new FieldRefElement$created:0:0":1}},"+FieldRefElement": [87],Dsd:{"":"uL+Pi;",$isd3:true}}],["field_view_element","package:observatory/src/observatory_elements/field_view.dart",,A,{Gk:{"":["tuj;vt%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gt0:function(a){return a.vt
-"37,38,39"},
+"38,39,40"},
"+field":1,
st0:function(a,b){a.vt=this.pD(a,C.WQ,a.vt,b)
-"40,31,37,38"},
+"41,32,38,39"},
"+field=":1,
"@":function(){return[C.Tq]},
static:{cY:function(a){var z,y,x,w,v
@@ -15791,12 +15815,12 @@
C.lS.ZL(a)
C.lS.FH(a)
return a
-"16"},"+new FieldViewElement$created:0:0":1}},"+FieldViewElement": [86],Dsd:{"":"uL+Pi;",$isd3:true}}],["function_view_element","package:observatory/src/observatory_elements/function_view.dart",,N,{Ds:{"":["tuj;ql%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"17"},"+new FieldViewElement$created:0:0":1}},"+FieldViewElement": [88],tuj:{"":"uL+Pi;",$isd3:true}}],["function_view_element","package:observatory/src/observatory_elements/function_view.dart",,N,{Ds:{"":["Vct;ql%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gMj:function(a){return a.ql
-"37,38,39"},
+"38,39,40"},
"+function":1,
sMj:function(a,b){a.ql=this.pD(a,C.nf,a.ql,b)
-"40,31,37,38"},
+"41,32,38,39"},
"+function=":1,
"@":function(){return[C.Uc]},
static:{p7:function(a){var z,y,x,w,v
@@ -15812,7 +15836,7 @@
C.PJ.ZL(a)
C.PJ.FH(a)
return a
-"17"},"+new FunctionViewElement$created:0:0":1}},"+FunctionViewElement": [87],tuj:{"":"uL+Pi;",$isd3:true}}],["html_common","dart:html_common",,P,{jD:function(a){return P.Wu(a.getTime(),!0)},bL:function(a){var z,y
+"18"},"+new FunctionViewElement$created:0:0":1}},"+FunctionViewElement": [89],Vct:{"":"uL+Pi;",$isd3:true}}],["html_common","dart:html_common",,P,{jD:function(a){return P.Wu(a.getTime(),!0)},bL:function(a){var z,y
z=[]
y=new P.Tm(new P.aI([],z),new P.rG(z),new P.yh(z)).call$1(a)
new P.wO().call$0()
@@ -16000,12 +16024,12 @@
"+call:1:0":0,
$isEH:true,
$is_HB:true,
-$is_Dv:true}}],["instance_ref_element","package:observatory/src/observatory_elements/instance_ref.dart",,B,{pR:{"":["Vct;iK%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+$is_Dv:true}}],["instance_ref_element","package:observatory/src/observatory_elements/instance_ref.dart",,B,{pR:{"":["D13;iK%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
ghf:function(a){return a.iK
-"37,38,39"},
+"38,39,40"},
"+instance":1,
shf:function(a,b){a.iK=this.pD(a,C.fn,a.iK,b)
-"40,31,37,38"},
+"41,32,38,39"},
"+instance=":1,
"@":function(){return[C.ay]},
static:{lu:function(a){var z,y,x,w,v
@@ -16021,12 +16045,12 @@
C.cp.ZL(a)
C.cp.FH(a)
return a
-"18"},"+new InstanceRefElement$created:0:0":1}},"+InstanceRefElement": [88],Vct:{"":"uL+Pi;",$isd3:true}}],["instance_view_element","package:observatory/src/observatory_elements/instance_view.dart",,Z,{hx:{"":["D13;Xh%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"19"},"+new InstanceRefElement$created:0:0":1}},"+InstanceRefElement": [90],D13:{"":"uL+Pi;",$isd3:true}}],["instance_view_element","package:observatory/src/observatory_elements/instance_view.dart",,Z,{hx:{"":["WZq;Xh%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
ghf:function(a){return a.Xh
-"37,38,39"},
+"38,39,40"},
"+instance":1,
shf:function(a,b){a.Xh=this.pD(a,C.fn,a.Xh,b)
-"40,31,37,38"},
+"41,32,38,39"},
"+instance=":1,
"@":function(){return[C.ql]},
static:{HC:function(a){var z,y,x,w,v
@@ -16042,7 +16066,7 @@
C.yK.ZL(a)
C.yK.FH(a)
return a
-"19"},"+new InstanceViewElement$created:0:0":1}},"+InstanceViewElement": [89],D13:{"":"uL+Pi;",$isd3:true}}],["isolate_list_element","package:observatory/src/observatory_elements/isolate_list.dart",,L,{u7:{"":["uL;tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"20"},"+new InstanceViewElement$created:0:0":1}},"+InstanceViewElement": [91],WZq:{"":"uL+Pi;",$isd3:true}}],["isolate_list_element","package:observatory/src/observatory_elements/isolate_list.dart",,L,{u7:{"":["uL;tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
"@":function(){return[C.jF]},
static:{Tt:function(a){var z,y,x,w,v
z=$.Nd()
@@ -16057,18 +16081,18 @@
C.Dh.ZL(a)
C.Dh.FH(a)
return a
-"20"},"+new IsolateListElement$created:0:0":1}},"+IsolateListElement": [27]}],["isolate_summary_element","package:observatory/src/observatory_elements/isolate_summary.dart",,D,{St:{"":["WZq;Pw%-,i0%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"21"},"+new IsolateListElement$created:0:0":1}},"+IsolateListElement": [28]}],["isolate_summary_element","package:observatory/src/observatory_elements/isolate_summary.dart",,D,{St:{"":["pva;Pw%-,i0%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gF1:function(a){return a.Pw
-"30,38,39"},
+"31,39,40"},
"+isolate":1,
sF1:function(a,b){a.Pw=this.pD(a,C.Y2,a.Pw,b)
-"40,31,30,38"},
+"41,32,31,39"},
"+isolate=":1,
goc:function(a){return a.i0
-"8,38,39"},
+"8,39,40"},
"+name":1,
soc:function(a,b){a.i0=this.pD(a,C.YS,a.i0,b)
-"40,31,8,38"},
+"41,32,8,39"},
"+name=":1,
"@":function(){return[C.aM]},
static:{N5:function(a){var z,y,x,w,v
@@ -16085,19 +16109,19 @@
C.nM.ZL(a)
C.nM.FH(a)
return a
-"21"},"+new IsolateSummaryElement$created:0:0":1}},"+IsolateSummaryElement": [90],WZq:{"":"uL+Pi;",$isd3:true}}],["json_view_element","package:observatory/src/observatory_elements/json_view.dart",,Z,{vj:{"":["pva;eb%-,kf%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"22"},"+new IsolateSummaryElement$created:0:0":1}},"+IsolateSummaryElement": [92],pva:{"":"uL+Pi;",$isd3:true}}],["json_view_element","package:observatory/src/observatory_elements/json_view.dart",,Z,{vj:{"":["cda;eb%-,kf%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gTn:function(a){return a.eb
-"40,38,39"},
+"41,39,40"},
"+json":1,
sTn:function(a,b){a.eb=this.pD(a,C.Gd,a.eb,b)
-"40,31,40,38"},
+"41,32,41,39"},
"+json=":1,
i4:function(a){Z.uL.prototype.i4.call(this,a)
a.kf=0
-"40"},
+"41"},
"+enteredView:0:0":1,
yC:function(a,b){this.pD(a,C.eR,"a","b")
-"40,91,40"},
+"41,93,41"},
"+jsonChanged:1:0":1,
gE8:function(a){return J.AG(a.eb)
"8"},
@@ -16113,24 +16137,24 @@
gFe:function(a){var z=a.kf
a.kf=J.WB(z,1)
return z
-"30"},
+"31"},
"+counter":1,
gqC:function(a){var z,y
z=a.eb
y=J.x(z)
if(typeof z==="object"&&z!==null&&(z.constructor===Array||!!y.$isList))return z
return[]
-"70"},
+"72"},
"+list":1,
gvc:function(a){var z,y
z=a.eb
y=J.RE(z)
if(typeof z==="object"&&z!==null&&!!y.$isL8)return J.qA(y.gvc(z))
return[]
-"70"},
+"72"},
"+keys":1,
r6:function(a,b){return J.UQ(a.eb,b)
-"40,78,8"},
+"41,80,8"},
"+value:1:0":1,
gP:function(a){return new P.C7(this,Z.vj.prototype.r6,a,"r6")},
"@":function(){return[C.HN]},
@@ -16149,12 +16173,12 @@
C.GB.ZL(a)
C.GB.FH(a)
return a
-"22"},"+new JsonViewElement$created:0:0":1}},"+JsonViewElement": [92],pva:{"":"uL+Pi;",$isd3:true}}],["library_view_element","package:observatory/src/observatory_elements/library_view.dart",,M,{CX:{"":["cda;iI%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"23"},"+new JsonViewElement$created:0:0":1}},"+JsonViewElement": [94],cda:{"":"uL+Pi;",$isd3:true}}],["library_view_element","package:observatory/src/observatory_elements/library_view.dart",,M,{CX:{"":["waa;iI%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gtD:function(a){return a.iI
-"37,38,39"},
+"38,39,40"},
"+library":1,
stD:function(a,b){a.iI=this.pD(a,C.EV,a.iI,b)
-"40,31,37,38"},
+"41,32,38,39"},
"+library=":1,
"@":function(){return[C.Oy]},
static:{SP:function(a){var z,y,x,w,v,u
@@ -16173,7 +16197,7 @@
C.MG.ZL(a)
C.MG.FH(a)
return a
-"23"},"+new LibraryViewElement$created:0:0":1}},"+LibraryViewElement": [93],cda:{"":"uL+Pi;",$isd3:true}}],["logging","package:logging/logging.dart",,N,{TJ:{"":"a;oc>,eT>,yz,Cj>,wd,Gs",
+"24"},"+new LibraryViewElement$created:0:0":1}},"+LibraryViewElement": [95],waa:{"":"uL+Pi;",$isd3:true}}],["logging","package:logging/logging.dart",,N,{TJ:{"":"a;oc>,eT>,yz,Cj>,wd,Gs",
gB8:function(){var z,y,x
z=this.eT
y=z==null||J.xC(J.DA(z),"")
@@ -16241,26 +16265,27 @@
giO:function(a){return this.P},
bu:function(a){return this.oc},
$isNg:true,
-static:{"":"bR,tm,EL,X8,IQ,Fn,Eb,AN,JY,bo",}},HV:{"":"a;OR<,G1>,iJ,Fl,O0,kc>,I4<",
+static:{"":"bR,tm,EL,X8,IQ,Fn,Eb,AN,JY,ac",}},HV:{"":"a;OR<,G1>,iJ,Fl,O0,kc>,I4<",
bu:function(a){return"["+this.OR.oc+"] "+this.iJ+": "+this.G1},
static:{"":"xO",}}}],["message_viewer_element","package:observatory/src/observatory_elements/message_viewer.dart",,L,{Nh:{"":["uL;XB%-,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gG1:function(a){return a.XB
-"37,39"},
+"38,40"},
"+message":1,
sG1:function(a,b){a.XB=b
this.pD(a,C.KY,"",this.gQW(a))
this.pD(a,C.wt,[],this.glc(a))
-"40,94,37,39"},
+"41,96,38,40"},
"+message=":1,
gQW:function(a){var z=a.XB
if(z==null||J.UQ(z,"type")==null)return"Error"
+P.JS("Received message of type '"+H.d(J.UQ(a.XB,"type"))+"' :\n"+H.d(a.XB))
return J.UQ(a.XB,"type")
"8"},
"+messageType":1,
glc:function(a){var z=a.XB
if(z==null||J.UQ(z,"members")==null)return[]
return J.UQ(a.XB,"members")
-"95"},
+"97"},
"+members":1,
"@":function(){return[C.c0]},
static:{rJ:function(a){var z,y,x,w,v
@@ -16276,7 +16301,7 @@
C.Wp.ZL(a)
C.Wp.FH(a)
return a
-"24"},"+new MessageViewerElement$created:0:0":1}},"+MessageViewerElement": [27]}],["metadata","../../../../../../../../../dart/dart-sdk/lib/html/html_common/metadata.dart",,B,{fA:{"":"a;Kr,Jt",static:{"":"Xd,en,yS,PZ,xa",}},tz:{"":"a;"},jR:{"":"a;oc>"},PO:{"":"a;"},c5:{"":"a;"}}],["navigation_bar_element","package:observatory/src/observatory_elements/navigation_bar.dart",,Q,{ih:{"":["uL;tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"25"},"+new MessageViewerElement$created:0:0":1}},"+MessageViewerElement": [28]}],["metadata","../../../../../../../../../dart/dart-sdk/lib/html/html_common/metadata.dart",,B,{fA:{"":"a;Kr,Jt",static:{"":"Xd,en,yS,PZ,xa",}},tz:{"":"a;"},jR:{"":"a;oc>"},PO:{"":"a;"},c5:{"":"a;"}}],["navigation_bar_element","package:observatory/src/observatory_elements/navigation_bar.dart",,Q,{ih:{"":["uL;tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
"@":function(){return[C.KG]},
static:{BW:function(a){var z,y,x,w,v
z=$.Nd()
@@ -16291,7 +16316,7 @@
C.Xg.ZL(a)
C.Xg.FH(a)
return a
-"25"},"+new NavigationBarElement$created:0:0":1}},"+NavigationBarElement": [27]}],["observatory","package:observatory/observatory.dart",,L,{mL:{"":["Pi;Z6<-,lw<-,nI<-,VJ,Ai",function(){return[C.mI]},function(){return[C.mI]},function(){return[C.mI]},null,null],
+"26"},"+new NavigationBarElement$created:0:0":1}},"+NavigationBarElement": [28]}],["observatory","package:observatory/observatory.dart",,L,{mL:{"":["Pi;Z6<-,lw<-,nI<-,VJ,Ai",function(){return[C.mI]},function(){return[C.mI]},function(){return[C.mI]},null,null],
Ey:function(){var z,y,x
z=this.Z6
z.sJR(this)
@@ -16325,16 +16350,16 @@
y.US()
return y}}},bv:{"":["Pi;nk,SS,XR<-,VJ,Ai",null,null,function(){return[C.mI]},null,null],
gjO:function(a){return this.nk
-"30,38,43"},
+"31,39,45"},
"+id":1,
sjO:function(a,b){this.nk=F.Wi(this,C.EN,this.nk,b)
-"40,31,30,38"},
+"41,32,31,39"},
"+id=":1,
goc:function(a){return this.SS
-"8,38,43"},
+"8,39,45"},
"+name":1,
soc:function(a,b){this.SS=F.Wi(this,C.YS,this.SS,b)
-"40,31,8,38"},
+"41,32,8,39"},
"+name=":1,
bu:function(a){return H.d(this.nk)+" "+H.d(this.SS)},
$isbv:true},pt:{"":["Pi;JR?,i2<-,VJ,Ai",null,function(){return[C.mI]},null,null],
@@ -16387,16 +16412,16 @@
$is_HB:true,
$is_Dv:true},dZ:{"":"Pi;JR?,IT,Jj,VJ,Ai",
gzd:function(){return this.IT
-"8,38,43"},
+"8,39,45"},
"+currentHash":1,
szd:function(a){this.IT=F.Wi(this,C.h1,this.IT,a)
-"40,31,8,38"},
+"41,32,8,39"},
"+currentHash=":1,
glD:function(){return this.Jj
-"96,38,43"},
+"98,39,45"},
"+currentHashUri":1,
slD:function(a){this.Jj=F.Wi(this,C.tv,this.Jj,a)
-"40,31,96,38"},
+"41,32,98,39"},
"+currentHashUri=":1,
kI:function(){var z,y
z=C.PP.aM(window)
@@ -16438,35 +16463,35 @@
PI:function(a){var z=this.R6()
if(J.xC(z,0))return"#/isolates/"
return"#/isolates/"+H.d(z)+"/"+H.d(a)
-"8,97,8,43"},
+"8,99,8,45"},
"+currentIsolateRelativeLink:1:0":1,
Ao:function(a){var z=this.R6()
if(J.xC(z,0))return"#/isolates/"
return"#/isolates/"+H.d(z)+"/objects/"+H.d(a)
-"8,98,30,43"},
+"8,100,31,45"},
"+currentIsolateObjectLink:1:0":1,
dL:function(a){var z=this.R6()
if(J.xC(z,0))return"#/isolates/"
return"#/isolates/"+H.d(z)+"/classes/"+H.d(a)
-"8,99,30,43"},
+"8,101,31,45"},
"+currentIsolateClassLink:1:0":1,
WW:function(a,b){var z=this.R6()
if(J.xC(z,0))return"#/isolates/"
return this.yX(z,a,b)
-"8,98,30,7,8,43"},
+"8,100,31,7,8,45"},
"+currentIsolateScriptLink:2:0":1,
r4:function(a,b){return"#/isolates/"+H.d(a)+"/"+H.d(b)
-"8,100,30,97,8,43"},
+"8,102,31,99,8,45"},
"+relativeLink:2:0":1,
Dd:function(a,b){return"#/isolates/"+H.d(a)+"/objects/"+H.d(b)
-"8,100,30,98,30,43"},
+"8,102,31,100,31,45"},
"+objectLink:2:0":1,
bD:function(a,b){return"#/isolates/"+H.d(a)+"/classes/"+H.d(b)
-"8,100,30,99,30,43"},
+"8,102,31,101,31,45"},
"+classLink:2:0":1,
yX:function(a,b,c){var z=P.jW(C.kg,c,!0)
return"#/isolates/"+H.d(a)+"/objects/"+H.d(b)+"?type=Script&name="+z
-"8,100,30,98,30,7,8,43"},
+"8,102,31,100,31,7,8,45"},
"+scriptLink:3:0":1,
static:{"":"kx,K3D,qY",}},Qe:{"":"Tp;a",
call$1:function(a){var z=this.a
@@ -16478,16 +16503,16 @@
$is_Dv:true},Nu:{"":"Pi;JR?,e0?",
pG:function(){return this.e0.call$0()},
gEI:function(){return this.oJ
-"8,38,43"},
+"8,39,45"},
"+prefix":1,
sEI:function(a){this.oJ=F.Wi(this,C.qb,this.oJ,a)
-"40,31,8,38"},
+"41,32,8,39"},
"+prefix=":1,
gn2:function(){return this.vm
-"95,38,43"},
+"97,39,45"},
"+responses":1,
sn2:function(a){this.vm=F.Wi(this,C.wH,this.vm,a)
-"40,31,95,38"},
+"41,32,97,39"},
"+responses=":1,
Qn:function(a){var z,y
z=C.lM.kV(a)
@@ -16574,13 +16599,13 @@
J.Ih(W.uV(window.parent),C.lM.KP(y),"*")
return w.MM}},Zw:{"":["Pi;Rd,n7,LA>-,Vg,VJ,Ai",null,null,function(){return[C.mI]},null,null,null],
geV:function(){return this.Vg
-"8,38,43"},
+"8,39,45"},
"+paddedLine":1,
seV:function(a){var z=this.Vg
if(this.gUV(this)&&!J.xC(z,a)){z=new T.qI(this,C.X9,z,a)
z.$builtinTypeInfo=[null]
this.SZ(this,z)}this.Vg=a
-"40,31,8,38"},
+"41,32,8,39"},
"+paddedLine=":1,
QQ:function(a,b,c){var z,y,x,w,v
z=""+this.Rd
@@ -16594,22 +16619,22 @@
z.QQ(a,b,c)
return z}}},Pf:{"":"Pi;WF,uM,ZQ,VJ,Ai",
gfY:function(a){return this.WF
-"8,38,43"},
+"8,39,45"},
"+kind":1,
sfY:function(a,b){this.WF=F.Wi(this,C.fy,this.WF,b)
-"40,31,8,38"},
+"41,32,8,39"},
"+kind=":1,
gO3:function(a){return this.uM
-"8,38,43"},
+"8,39,45"},
"+url":1,
sO3:function(a,b){this.uM=F.Wi(this,C.Fh,this.uM,b)
-"40,31,8,38"},
+"41,32,8,39"},
"+url=":1,
gXJ:function(){return this.ZQ
-"101,38,43"},
+"103,39,45"},
"+lines":1,
sXJ:function(a){this.ZQ=F.Wi(this,C.Cv,this.ZQ,a)
-"40,31,101,38"},
+"41,32,103,39"},
"+lines=":1,
Cn:function(a){var z,y,x,w,v
z=J.uH(a,"\n")
@@ -16629,17 +16654,17 @@
static:{Sp:function(a){var z=R.Jk([])
z=new L.Pf("","",z,null,null)
z.EQ(a)
-return z}}}}],["observatory_application_element","package:observatory/src/observatory_elements/observatory_application.dart",,V,{F1:{"":["waa;k5%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+return z}}}}],["observatory_application_element","package:observatory/src/observatory_elements/observatory_application.dart",,V,{F1:{"":["V0;k5%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gzj:function(a){return a.k5
-"44,38,39"},
+"46,39,40"},
"+devtools":1,
szj:function(a,b){a.k5=this.pD(a,C.Na,a.k5,b)
-"40,31,44,38"},
+"41,32,46,39"},
"+devtools=":1,
ZB:function(a){var z
if(a.k5===!0){z=L.WS()
a.tH=this.pD(a,C.wh,a.tH,z)}else{z=L.AK()
-a.tH=this.pD(a,C.wh,a.tH,z)}"40"},
+a.tH=this.pD(a,C.wh,a.tH,z)}"41"},
"@":function(){return[C.bd]},
static:{fv:function(a){var z,y,x,w,v
z=$.Nd()
@@ -16656,23 +16681,23 @@
C.k0.FH(a)
C.k0.ZB(a)
return a
-"26"},"+new ObservatoryApplicationElement$created:0:0":1}},"+ObservatoryApplicationElement": [102],waa:{"":"uL+Pi;",$isd3:true}}],["observatory_element","package:observatory/src/observatory_elements/observatory_element.dart",,Z,{uL:{"":["Nr;tH%-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"27"},"+new ObservatoryApplicationElement$created:0:0":1}},"+ObservatoryApplicationElement": [104],V0:{"":"uL+Pi;",$isd3:true}}],["observatory_element","package:observatory/src/observatory_elements/observatory_element.dart",,Z,{uL:{"":["Nr;tH%-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
i4:function(a){A.dM.prototype.i4.call(this,a)
-"40"},
+"41"},
"+enteredView:0:0":1,
Nz:function(a){A.dM.prototype.Nz.call(this,a)
-"40"},
+"41"},
"+leftView:0:0":1,
gQG:function(a){return a.tH
-"103,38,39"},
+"105,39,40"},
"+app":1,
sQG:function(a,b){a.tH=this.pD(a,C.wh,a.tH,b)
-"40,31,103,38"},
+"41,32,105,39"},
"+app=":1,
gpQ:function(a){return!0
-"44"},
+"46"},
"+applyAuthorStyles":1,
-"@":function(){return[C.J0]},
+"@":function(){return[C.Br]},
static:{Hx:function(a){var z,y,x,w,v
z=$.Nd()
y=P.Py(null,null,null,J.O,W.I0)
@@ -16686,7 +16711,7 @@
C.mk.ZL(a)
C.mk.FH(a)
return a
-"27"},"+new ObservatoryElement$created:0:0":1}},"+ObservatoryElement": [104],Nr:{"":"ir+Pi;",$isd3:true}}],["observe.src.change_notifier","package:observe/src/change_notifier.dart",,O,{Pi:{"":"a;",
+"28"},"+new ObservatoryElement$created:0:0":1}},"+ObservatoryElement": [106],Nr:{"":"ir+Pi;",$isd3:true}}],["observe.src.change_notifier","package:observe/src/change_notifier.dart",,O,{Pi:{"":"a;",
gqh:function(a){var z,y
if(a.VJ==null){z=this.gqw(a)
a.VJ=P.bK(this.gl1(a),z,!0,null)}z=a.VJ
@@ -16730,7 +16755,7 @@
gB:function(a){return this.b9.length},
"+length":0,
gP:function(a){return this.Sv
-"40,38"},
+"41,39"},
"+value":1,
r6:function(a,b){return this.gP(a).call$1(b)},
wE:function(a){var z,y,x,w
@@ -17055,11 +17080,11 @@
$isEH:true,
$is_bh:true}}],["observe.src.observable_box","package:observe/src/observable_box.dart",,A,{xh:{"":"Pi;",
gP:function(a){return this.L1
-"105,38"},
+"107,39"},
"+value":1,
r6:function(a,b){return this.gP(a).call$1(b)},
sP:function(a,b){this.L1=F.Wi(this,C.ls,this.L1,b)
-"40,106,105,38"},
+"41,108,107,39"},
"+value=":1,
bu:function(a){return"#<"+H.d(new H.cu(H.dJ(this),null))+" value: "+H.d(this.L1)+">"}}}],["observe.src.observable_list","package:observe/src/observable_list.dart",,Q,{wn:{"":"uF;b3,xg,h3,VJ,Ai",
gRT:function(){var z,y
@@ -17070,7 +17095,7 @@
H.VM(y,[H.W8(z,"WV",0)])
return y},
gB:function(a){return this.h3.length
-"30,38"},
+"31,39"},
"+length":1,
sB:function(a,b){var z,y,x,w,v,u,t
z=this.h3
@@ -17099,12 +17124,12 @@
w=new P.Yp(t)
w.$builtinTypeInfo=[null]
this.iH(new G.W4(this,w,t,y,x))}}C.Nm.sB(z,b)
-"40,31,30,38"},
+"41,32,31,39"},
"+length=":1,
t:function(a,b){var z=this.h3
if(b>>>0!==b||b>=z.length)throw H.e(z,b)
return z[b]
-"107,29,30,38"},
+"109,30,31,39"},
"+[]:1:0":1,
u:function(a,b,c){var z,y,x,w
z=this.h3
@@ -17118,7 +17143,7 @@
w.$builtinTypeInfo=[null]
this.iH(new G.W4(this,w,x,b,1))}if(b>=z.length)throw H.e(z,b)
z[b]=c
-"40,29,30,31,107,38"},
+"41,30,31,32,109,39"},
"+[]=:2:0":1,
h:function(a,b){var z,y,x,w
z=this.h3
@@ -17207,33 +17232,33 @@
$isHA:true},br:{"":"Pi;Zp,VJ,Ai",
gvc:function(a){var z=this.Zp
return z.gvc(z)
-"108,38"},
+"110,39"},
"+keys":1,
gUQ:function(a){var z=this.Zp
return z.gUQ(z)
-"109,38"},
+"111,39"},
"+values":1,
gB:function(a){var z=this.Zp
return z.gB(z)
-"30,38"},
+"31,39"},
"+length":1,
gl0:function(a){var z=this.Zp
return z.gB(z)===0
-"44,38"},
+"46,39"},
"+isEmpty":1,
gor:function(a){var z=this.Zp
return z.gB(z)!==0
-"44,38"},
+"46,39"},
"+isNotEmpty":1,
PF:function(a){return this.Zp.PF(a)
-"44,31,0,38"},
+"46,32,0,39"},
"+containsValue:1:0":1,
x4:function(a){return this.Zp.x4(a)
-"44,78,0,38"},
+"46,80,0,39"},
"+containsKey:1:0":1,
t:function(a,b){var z=this.Zp
return z.t(z,b)
-"110,78,0,38"},
+"112,80,0,39"},
"+[]:1:0":1,
u:function(a,b,c){var z,y,x,w,v
z=this.Zp
@@ -17250,7 +17275,7 @@
z.$builtinTypeInfo=[null,null]
this.SZ(this,z)}else if(!J.xC(x,c)){z=new V.HA(b,x,c,!1,!1)
z.$builtinTypeInfo=[null,null]
-this.SZ(this,z)}"40,78,111,31,110,38"},
+this.SZ(this,z)}"41,80,113,32,112,39"},
"+[]=:2:0":1,
Ay:function(a,b){b.aN(b,new V.zT(this))},
Rz:function(a,b){var z,y,x,w,v
@@ -17361,7 +17386,7 @@
z=y==null?z!=null:y!==z}else z=!1
if(!z)this.ov()
return C.Nm.grZ(this.kN)
-"40,38"},
+"41,39"},
"+value":1,
r6:function(a,b){return this.gP(a).call$1(b)},
sP:function(a,b){var z,y,x,w
@@ -17379,7 +17404,7 @@
if(w>=z.length)throw H.e(z,w)
if(L.h6(x,z[w],b)){z=this.kN
if(y>=z.length)throw H.e(z,y)
-z[y]=b}"40,106,0,38"},
+z[y]=b}"41,108,0,39"},
"+value=":1,
w3:function(a){O.Pi.prototype.w3.call(this,this)
this.ov()
@@ -18541,7 +18566,7 @@
y=typeof z==="object"&&z!==null&&!!y.$isEZ}else y=!1}else y=!1
if(y)return
return new T.Xy(this,b,z)},
-gca:function(){return new T.Dw(this,T.e9.prototype.yt,null,"yt")},
+gca:function(){return new T.PD(this,T.e9.prototype.yt,null,"yt")},
A5:function(a){return new T.uK(this)}},Xy:{"":"Tp;a,b,c",
call$2:function(a,b){var z=J.x(a)
if(typeof a!=="object"||a===null||!z.$isz6)a=new K.z6(null,a,V.WF(this.a.nF,null,null),null)
@@ -18568,14 +18593,14 @@
F.Wi(this,C.ls,z,this.uK)},
gnc:function(){return new H.Pm(this,T.mY.prototype.vr,null,"vr")},
gP:function(a){return this.uK
-"40,38"},
+"41,39"},
"+value":1,
r6:function(a,b){return this.gP(a).call$1(b)},
sP:function(a,b){var z,y,x,w
try{K.jX(this.jf,b,this.qc)}catch(y){x=H.Ru(y)
w=J.x(x)
if(typeof x==="object"&&x!==null&&!!w.$isB0){z=x
-$.IS().A3("Error evaluating expression '"+H.d(this.jf)+"': "+J.z2(z))}else throw y}"40,112,40,38"},
+$.IS().A3("Error evaluating expression '"+H.d(this.jf)+"': "+J.z2(z))}else throw y}"41,114,41,39"},
"+value=":1,
Va:function(a,b,c){var z,y,x,w,v
y=this.jf
@@ -19037,7 +19062,7 @@
return 536870911&a+((16383&a)<<15>>>0)},Fq:{"":"a;",
F2:function(a,b,c){return new U.RW(a,b,c)},
"+invoke:3:0":0,
-"*invoke":[40],
+"*invoke":[41],
CI:function(a,b){return this.F2(a,b,null)},
"+invoke:2:0":0},hw:{"":"a;",$ishw:true},EZ:{"":"hw;",
RR:function(a,b){return b.W9(this)},
@@ -19331,7 +19356,7 @@
static:{i0:function(a,b,c){var z=new K.Ae(a,b)
H.VM(z,[c])
return z
-"28,29,30,31,32"},"+new IndexedValue:2:0":1}},"+IndexedValue": [0],Bt:{"":"mW;YR",
+"29,30,31,32,33"},"+new IndexedValue:2:0":1}},"+IndexedValue": [0],Bt:{"":"mW;YR",
gA:function(a){var z=J.GP(this.YR)
z=new K.vR(z,0,null)
H.VM(z,[H.W8(this,"Bt",0)])
@@ -19525,15 +19550,15 @@
C.Cc.ZL(a)
C.Cc.FH(a)
return a
-"33"},"+new ResponseViewerElement$created:0:0":1}},"+ResponseViewerElement": [27]}],["script_view_element","package:observatory/src/observatory_elements/script_view.dart",,U,{fI:{"":["V0;Uz%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"34"},"+new ResponseViewerElement$created:0:0":1}},"+ResponseViewerElement": [28]}],["script_view_element","package:observatory/src/observatory_elements/script_view.dart",,U,{fI:{"":["V4;Uz%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gNl:function(a){return a.Uz
-"37,38,39"},
+"38,39,40"},
"+script":1,
sNl:function(a,b){a.Uz=this.pD(a,C.fX,a.Uz,b)
-"40,31,37,38"},
+"41,32,38,39"},
"+script=":1,
"@":function(){return[C.Er]},
-static:{Ry:function(a){var z,y,x,w,v
+static:{kL:function(a){var z,y,x,w,v
z=$.Nd()
y=P.Py(null,null,null,J.O,W.I0)
x=J.O
@@ -19546,12 +19571,12 @@
C.cJ.ZL(a)
C.cJ.FH(a)
return a
-"34"},"+new ScriptViewElement$created:0:0":1}},"+ScriptViewElement": [113],V0:{"":"uL+Pi;",$isd3:true}}],["source_view_element","package:observatory/src/observatory_elements/source_view.dart",,X,{kK:{"":["V4;vX%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"35"},"+new ScriptViewElement$created:0:0":1}},"+ScriptViewElement": [115],V4:{"":"uL+Pi;",$isd3:true}}],["source_view_element","package:observatory/src/observatory_elements/source_view.dart",,X,{kK:{"":["V6;vX%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gFF:function(a){return a.vX
-"114,38,39"},
+"116,39,40"},
"+source":1,
sFF:function(a,b){a.vX=this.pD(a,C.hn,a.vX,b)
-"40,31,114,38"},
+"41,32,116,39"},
"+source=":1,
"@":function(){return[C.H8]},
static:{HO:function(a){var z,y,x,w,v
@@ -19567,12 +19592,12 @@
C.Ks.ZL(a)
C.Ks.FH(a)
return a
-"35"},"+new SourceViewElement$created:0:0":1}},"+SourceViewElement": [115],V4:{"":"uL+Pi;",$isd3:true}}],["stack_trace_element","package:observatory/src/observatory_elements/stack_trace.dart",,X,{uw:{"":["V6;V4%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"36"},"+new SourceViewElement$created:0:0":1}},"+SourceViewElement": [117],V6:{"":"uL+Pi;",$isd3:true}}],["stack_trace_element","package:observatory/src/observatory_elements/stack_trace.dart",,X,{uw:{"":["V8;V4%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gtN:function(a){return a.V4
-"37,38,39"},
+"38,39,40"},
"+trace":1,
stN:function(a,b){a.V4=this.pD(a,C.kw,a.V4,b)
-"40,31,37,38"},
+"41,32,38,39"},
"+trace=":1,
"@":function(){return[C.js]},
static:{bV:function(a){var z,y,x,w,v,u
@@ -19591,7 +19616,7 @@
C.bg.ZL(a)
C.bg.FH(a)
return a
-"36"},"+new StackTraceElement$created:0:0":1}},"+StackTraceElement": [116],V6:{"":"uL+Pi;",$isd3:true}}],["template_binding","package:template_binding/template_binding.dart",,M,{IP:function(a){var z=J.RE(a)
+"37"},"+new StackTraceElement$created:0:0":1}},"+StackTraceElement": [118],V8:{"":"uL+Pi;",$isd3:true}}],["template_binding","package:template_binding/template_binding.dart",,M,{IP:function(a){var z=J.RE(a)
if(typeof a==="object"&&a!==null&&!!z.$isQl)return C.io.f0(a)
switch(z.gr9(a)){case"checkbox":return $.FF().aM(a)
case"radio":case"select-multiple":case"select-one":return z.gEr(a)
@@ -20671,6 +20696,7 @@
if(typeof a!="object")return a
if(a instanceof P.a)return a
return J.ks(a)}
+C.J0=B.G6.prototype
C.OL=new U.EZ()
C.Gw=new H.SJ()
C.E3=new J.Q()
@@ -20691,7 +20717,7 @@
C.YD=F.Be.prototype
C.j8=R.i6.prototype
C.Vy=new A.V3("disassembly-entry")
-C.J0=new A.V3("observatory-element")
+C.Br=new A.V3("observatory-element")
C.Er=new A.V3("script-view")
C.ht=new A.V3("field-ref")
C.aM=new A.V3("isolate-summary")
@@ -20703,6 +20729,7 @@
C.c0=new A.V3("message-viewer")
C.js=new A.V3("stack-trace")
C.jF=new A.V3("isolate-list")
+C.PT=new A.V3("breakpoint-list")
C.KG=new A.V3("navigation-bar")
C.ay=new A.V3("instance-ref")
C.Gu=new A.V3("collapsible-content")
@@ -20936,6 +20963,7 @@
C.PC=new H.GD("dart.core.int")
C.wt=new H.GD("members")
C.KY=new H.GD("messageType")
+C.Ry=new H.GD("msg")
C.YS=new H.GD("name")
C.OV=new H.GD("noSuchMethod")
C.Ws=new H.GD("operatingSystem")
@@ -20963,14 +20991,15 @@
C.Ti=H.mm('wn')
C.Mt=new H.Lm(C.Ti,"E",0)
C.Ye=H.mm('hx')
-C.G6=H.mm('F1')
+C.bD=H.mm('F1')
C.NM=H.mm('Nh')
+C.z7=H.mm('G6')
C.nY=H.mm('a')
C.Yc=H.mm('iP')
C.LN=H.mm('Be')
C.Qa=H.mm('u7')
C.xS=H.mm('UZ')
-C.PT=H.mm('CX')
+C.mA=H.mm('CX')
C.Op=H.mm('G8')
C.xF=H.mm('NQ')
C.b4=H.mm('ih')
@@ -21175,8 +21204,8 @@
J.z2=function(a){return J.RE(a).gG1(a)}
J.zZ=function(a,b){return J.RE(a).Yv(a,b)}
J.zj=function(a){return J.RE(a).gvH(a)}
-$.Dq=["Ay","BN","BT","Ba","C","C0","C8","Ch","D","D3","D6","Dh","E","Ec","F","FH","Fr","GB","HG","Hn","Id","Ih","Im","Is","J","J3","JP","JT","JV","Ja","Jk","Kb","LV","Md","Mi","Mu","Nj","Nz","O","On","PM","Pa","Pk","Pv","R3","R4","RB","RR","Rz","SZ","T","T2","TH","TP","TW","Tc","Td","U","UD","UH","UZ","Uc","V","V1","Vr","Vy","W","W3","W4","WO","WZ","Wt","Wz","X6","XG","XU","Xl","Y9","YU","YW","Ys","Yv","Z","Z1","Z2","ZB","ZF","ZL","ZP","Zv","aC","aN","aq","bA","bS","br","bu","cO","cn","d0","dR","dd","du","eR","ea","er","es","ev","ez","f6","fd","fj","fk","fm","g","gA","gB","gBb","gCd","gCj","gDD","gDg","gE8","gEX","gEr","gF1","gFF","gFJ","gFT","gFV","gFe","gG0","gG1","gG3","gGL","gHs","gI","gIi","gJS","gJf","gKE","gKM","gKV","gLA","gLU","gLf","gLm","gM0","gMB","gMj","gN","gNI","gNl","gO3","gP","gP1","gP2","gPp","gPu","gPw","gPy","gQ0","gQG","gQW","gQg","gRn","gRu","gT8","gTM","gTn","gTq","gUQ","gUV","gUz","gV4","gVA","gVB","gVl","gXB","gXf","gXh","gXt","gZw","gai","gbP","gbx","gcC","geT","geb","gey","gfY","ghO","ghf","ghr","gi0","giC","giI","giK","giO","gig","gjL","gjO","gjU","gjb","gk5","gkU","gkc","gkf","gkp","gl0","gl7","glc","gmW","gmm","gn4","goc","gor","gpQ","gpo","gq6","gqC","gqh","gql","gr3","gr9","grK","grZ","gt0","gtD","gtH","gtN","gtT","guD","gvH","gvX","gvc","gvt","gxj","gxr","gyT","gys","gzP","gzZ","gzj","h","h8","hV","hc","i","i4","iA","iM","iw","j","jT","jx","kO","l5","l8","lj","m","mK","mv","n","nB","nC","nH","nP","ni","oB","oW","od","oo","oq","pD","pZ","pl","pr","qZ","r6","rJ","rS","sB","sF1","sFF","sFJ","sFT","sG1","sIt","sLA","sLf","sMj","sNI","sNl","sO3","sP","sP2","sPw","sPy","sQG","sRu","sTn","sTq","sUz","sV4","sVA","sVB","sXB","sXf","sXh","sZw","sa4","sai","scC","seb","sfY","shO","shf","si0","siI","siK","sig","sjO","sk5","skc","skf","sl7","soc","sql","sr9","st0","stD","stH","stN","stT","svX","svt","sxj","sxr","szZ","szj","t","tZ","tg","tt","u","u5","u8","uG","vs","w3","wE","wL","wR","wg","x3","xI","xc","xe","y0","yC","yc","ym","yn","yq","yu","yx","yy","z2","zV"]
-$.Au=[C.Ye,Z.hx,{created:Z.HC},C.G6,V.F1,{created:V.fv},C.NM,L.Nh,{created:L.rJ},C.LN,F.Be,{created:F.Fe},C.Qa,L.u7,{created:L.Tt},C.xS,P.UZ,{},C.PT,M.CX,{created:M.SP},C.Op,P.G8,{},C.xF,Q.NQ,{created:Q.Zo},C.b4,Q.ih,{created:Q.BW},C.Ob,X.kK,{created:X.HO},C.hG,A.ir,{created:A.oa},C.aj,U.fI,{created:U.Ry},C.mo,E.Fv,{created:E.AH},C.xE,Z.aC,{created:Z.zg},C.vuj,X.uw,{created:X.bV},C.j6,D.qr,{created:D.ip},C.C6,Z.vj,{created:Z.un},C.CT,D.St,{created:D.N5},C.Q4,Z.uL,{created:Z.Hx},C.yg,F.I3,{created:F.TW},C.XU,R.i6,{created:R.IT},C.Bm,A.XP,{created:A.XL},C.Wz,B.pR,{created:B.lu},C.mnH,N.Ds,{created:N.p7},C.XK,A.Gk,{created:A.cY}]
+$.Dq=["Ay","BN","BT","Ba","C","C0","C8","Ch","D","D3","D6","Dh","E","Ec","F","FH","Fr","GB","HG","Hn","Id","Ih","Im","Is","J","J3","JP","JT","JV","Ja","Jk","Kb","LV","Md","Mi","Mu","Nj","Nz","O","On","PM","Pa","Pk","Pv","R3","R4","RB","RR","Rz","SZ","T","T2","TH","TP","TW","Tc","Td","U","UD","UH","UZ","Uc","V","V1","Vr","Vy","W","W3","W4","WO","WZ","Wt","Wz","X6","XG","XU","Xl","Y9","YU","YW","Ys","Yv","Z","Z1","Z2","ZB","ZF","ZL","ZP","Zv","aC","aN","aq","bA","bS","br","bu","cO","cn","d0","dR","dd","du","eR","ea","er","es","ev","ez","f6","fd","fj","fk","fm","g","gA","gB","gBb","gCd","gCj","gDD","gDg","gE8","gEX","gEr","gF1","gFF","gFJ","gFT","gFV","gFe","gG0","gG1","gG3","gGL","gHs","gI","gIi","gJS","gJf","gKE","gKM","gKV","gLA","gLU","gLf","gLm","gM0","gMB","gMj","gN","gNI","gNl","gO3","gP","gP1","gP2","gPp","gPu","gPw","gPy","gQ0","gQG","gQW","gQg","gRn","gRu","gT8","gTM","gTn","gTq","gUQ","gUV","gUz","gV4","gVA","gVB","gVl","gXB","gXf","gXh","gXt","gZw","gai","gbP","gbx","gcC","geE","geT","geb","gey","gfY","ghO","ghf","ghr","gi0","giC","giI","giK","giO","gig","gjL","gjO","gjU","gjb","gk5","gkU","gkc","gkf","gkp","gl0","gl7","glc","gmW","gmm","gn4","goc","gor","gpQ","gpo","gq6","gqC","gqh","gql","gr3","gr9","grK","grZ","grs","gt0","gtD","gtH","gtN","gtT","guD","gvH","gvX","gvc","gvt","gxj","gxr","gyT","gys","gzP","gzZ","gzj","h","h8","hV","hc","i","i4","iA","iM","iw","j","jT","jx","kO","l5","l8","lj","m","mK","mv","n","nB","nC","nH","nP","ni","oB","oW","od","oo","oq","pD","pZ","pl","pr","qZ","r6","rJ","rS","sB","sF1","sFF","sFJ","sFT","sG1","sIt","sLA","sLf","sMj","sNI","sNl","sO3","sP","sP2","sPw","sPy","sQG","sRu","sTn","sTq","sUz","sV4","sVA","sVB","sXB","sXf","sXh","sZw","sa4","sai","scC","seE","seb","sfY","shO","shf","si0","siI","siK","sig","sjO","sk5","skc","skf","sl7","soc","sql","sr9","srs","st0","stD","stH","stN","stT","svX","svt","sxj","sxr","szZ","szj","t","tZ","tg","tt","u","u5","u8","uG","vs","w3","wE","wL","wR","wg","x3","xI","xc","xe","y0","yC","yc","ym","yn","yq","yu","yx","yy","z2","zV"]
+$.Au=[C.Ye,Z.hx,{created:Z.HC},C.bD,V.F1,{created:V.fv},C.NM,L.Nh,{created:L.rJ},C.z7,B.G6,{created:B.Dw},C.LN,F.Be,{created:F.Fe},C.Qa,L.u7,{created:L.Tt},C.xS,P.UZ,{},C.mA,M.CX,{created:M.SP},C.Op,P.G8,{},C.xF,Q.NQ,{created:Q.Zo},C.b4,Q.ih,{created:Q.BW},C.Ob,X.kK,{created:X.HO},C.hG,A.ir,{created:A.oa},C.aj,U.fI,{created:U.kL},C.mo,E.Fv,{created:E.AH},C.xE,Z.aC,{created:Z.zg},C.vuj,X.uw,{created:X.bV},C.j6,D.qr,{created:D.ip},C.C6,Z.vj,{created:Z.un},C.CT,D.St,{created:D.N5},C.Q4,Z.uL,{created:Z.Hx},C.yg,F.I3,{created:F.TW},C.XU,R.i6,{created:R.IT},C.Bm,A.XP,{created:A.XL},C.Wz,B.pR,{created:B.lu},C.mnH,N.Ds,{created:N.p7},C.XK,A.Gk,{created:A.cY}]
I.$lazy($,"globalThis","DX","jk",function(){return function() { return this; }()})
I.$lazy($,"globalWindow","pG","Qm",function(){return $.jk().window})
I.$lazy($,"globalWorker","zA","Nl",function(){return $.jk().Worker})
@@ -21276,7 +21305,7 @@
return z})
init.functionAliases={}
-init.metadata=[P.a,C.wK,C.wa,C.WX,C.Mt,C.wW,P.uq,"name",J.O,Z.aC,F.Be,R.i6,W.K5,E.Fv,F.I3,D.qr,A.Gk,N.Ds,B.pR,Z.hx,L.u7,D.St,Z.vj,M.CX,L.Nh,Q.ih,V.F1,Z.uL,[K.Ae,3],"index",J.im,"value",3,Q.NQ,U.fI,X.kK,X.uw,P.L8,C.nJ,C.Us,,Z.Vf,F.tu,C.mI,J.kn,"r","e",W.ea,"detail","target",W.KV,R.Vc,[P.L8,P.wv,P.RS],[J.Q,H.Zk],"methodOwner",P.NL,[J.Q,P.RY],"fieldOwner",[P.L8,P.wv,P.RY],[P.L8,P.wv,P.QF],[P.L8,P.wv,P.NL],P.vr,"fieldName",P.wv,"arg",H.Uz,[J.Q,P.vr],P.Ms,"memberName","positionalArguments",J.Q,"namedArguments",[P.L8,P.wv,null],[J.Q,P.Ms],"owner",[J.Q,P.Fw],[J.Q,P.L9u],H.Un,"key",P.QF,H.Tp,"tv","i",E.WZ,F.pv,D.Vfx,A.Dsd,N.tuj,B.Vct,Z.D13,D.WZq,"oldValue",Z.pva,M.cda,"m",[J.Q,P.L8],P.iD,"l","objectId","cid","isolateId",[J.Q,L.Zw],V.waa,L.mL,Z.Nr,5,"newValue",4,[P.cX,1],[P.cX,2],2,1,"v",U.V0,L.Pf,X.V4,X.V6,];$=null
+init.metadata=[P.a,C.wK,C.wa,C.WX,C.Mt,C.wW,P.uq,"name",J.O,B.G6,Z.aC,F.Be,R.i6,W.K5,E.Fv,F.I3,D.qr,A.Gk,N.Ds,B.pR,Z.hx,L.u7,D.St,Z.vj,M.CX,L.Nh,Q.ih,V.F1,Z.uL,[K.Ae,3],"index",J.im,"value",3,Q.NQ,U.fI,X.kK,X.uw,P.L8,C.nJ,C.Us,,B.Vf,Z.tu,F.Vc,C.mI,J.kn,"r","e",W.ea,"detail","target",W.KV,R.WZ,[P.L8,P.wv,P.RS],[J.Q,H.Zk],"methodOwner",P.NL,[J.Q,P.RY],"fieldOwner",[P.L8,P.wv,P.RY],[P.L8,P.wv,P.QF],[P.L8,P.wv,P.NL],P.vr,"fieldName",P.wv,"arg",H.Uz,[J.Q,P.vr],P.Ms,"memberName","positionalArguments",J.Q,"namedArguments",[P.L8,P.wv,null],[J.Q,P.Ms],"owner",[J.Q,P.Fw],[J.Q,P.L9u],H.Un,"key",P.QF,H.Tp,"tv","i",E.pv,F.Vfx,D.Dsd,A.tuj,N.Vct,B.D13,Z.WZq,D.pva,"oldValue",Z.cda,M.waa,"m",[J.Q,P.L8],P.iD,"l","objectId","cid","isolateId",[J.Q,L.Zw],V.V0,L.mL,Z.Nr,5,"newValue",4,[P.cX,1],[P.cX,2],2,1,"v",U.V4,L.Pf,X.V6,X.V8,];$=null
I = I.$finishIsolateConstructor(I)
$=new I()
function convertToFastObject(properties) {
@@ -23577,6 +23606,35 @@
$desc=$collectedClasses.tQ
if($desc instanceof Array)$desc=$desc[1]
tQ.prototype=$desc
+function G6(eE,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.eE=eE
+this.VJ=VJ
+this.Ai=Ai
+this.tH=tH
+this.VJ=VJ
+this.Ai=Ai
+this.VJ=VJ
+this.Ai=Ai
+this.ZI=ZI
+this.uN=uN
+this.z3=z3
+this.TQ=TQ
+this.Vk=Vk
+this.Ye=Ye
+this.mT=mT
+this.KM=KM}G6.builtin$cls="G6"
+if(!"name" in G6)G6.name="G6"
+$desc=$collectedClasses.G6
+if($desc instanceof Array)$desc=$desc[1]
+G6.prototype=$desc
+G6.prototype.geE=function(receiver){return receiver.eE}
+G6.prototype.geE.$reflectable=1
+G6.prototype.seE=function(receiver,v){return receiver.eE=v}
+G6.prototype.seE.$reflectable=1
+function Vf(){}Vf.builtin$cls="Vf"
+if(!"name" in Vf)Vf.name="Vf"
+$desc=$collectedClasses.Vf
+if($desc instanceof Array)$desc=$desc[1]
+Vf.prototype=$desc
function aC(FJ,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.FJ=FJ
this.VJ=VJ
this.Ai=Ai
@@ -23601,11 +23659,11 @@
aC.prototype.gFJ.$reflectable=1
aC.prototype.sFJ=function(receiver,v){return receiver.FJ=v}
aC.prototype.sFJ.$reflectable=1
-function Vf(){}Vf.builtin$cls="Vf"
-if(!"name" in Vf)Vf.name="Vf"
-$desc=$collectedClasses.Vf
+function tu(){}tu.builtin$cls="tu"
+if(!"name" in tu)tu.name="tu"
+$desc=$collectedClasses.tu
if($desc instanceof Array)$desc=$desc[1]
-Vf.prototype=$desc
+tu.prototype=$desc
function Be(Zw,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.Zw=Zw
this.VJ=VJ
this.Ai=Ai
@@ -23630,11 +23688,11 @@
Be.prototype.gZw.$reflectable=1
Be.prototype.sZw=function(receiver,v){return receiver.Zw=v}
Be.prototype.sZw.$reflectable=1
-function tu(){}tu.builtin$cls="tu"
-if(!"name" in tu)tu.name="tu"
-$desc=$collectedClasses.tu
+function Vc(){}Vc.builtin$cls="Vc"
+if(!"name" in Vc)Vc.name="Vc"
+$desc=$collectedClasses.Vc
if($desc instanceof Array)$desc=$desc[1]
-tu.prototype=$desc
+Vc.prototype=$desc
function i6(Xf,VA,P2,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.Xf=Xf
this.VA=VA
this.P2=P2
@@ -23669,11 +23727,11 @@
i6.prototype.gP2.$reflectable=1
i6.prototype.sP2=function(receiver,v){return receiver.P2=v}
i6.prototype.sP2.$reflectable=1
-function Vc(){}Vc.builtin$cls="Vc"
-if(!"name" in Vc)Vc.name="Vc"
-$desc=$collectedClasses.Vc
+function WZ(){}WZ.builtin$cls="WZ"
+if(!"name" in WZ)WZ.name="WZ"
+$desc=$collectedClasses.WZ
if($desc instanceof Array)$desc=$desc[1]
-Vc.prototype=$desc
+WZ.prototype=$desc
function zO(){}zO.builtin$cls="zO"
if(!"name" in zO)zO.name="zO"
$desc=$collectedClasses.zO
@@ -26130,11 +26188,11 @@
Fv.prototype.gFT.$reflectable=1
Fv.prototype.sFT=function(receiver,v){return receiver.FT=v}
Fv.prototype.sFT.$reflectable=1
-function WZ(){}WZ.builtin$cls="WZ"
-if(!"name" in WZ)WZ.name="WZ"
-$desc=$collectedClasses.WZ
+function pv(){}pv.builtin$cls="pv"
+if(!"name" in pv)pv.name="pv"
+$desc=$collectedClasses.pv
if($desc instanceof Array)$desc=$desc[1]
-WZ.prototype=$desc
+pv.prototype=$desc
function I3(Py,hO,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.Py=Py
this.hO=hO
this.VJ=VJ
@@ -26164,11 +26222,11 @@
I3.prototype.ghO.$reflectable=1
I3.prototype.shO=function(receiver,v){return receiver.hO=v}
I3.prototype.shO.$reflectable=1
-function pv(){}pv.builtin$cls="pv"
-if(!"name" in pv)pv.name="pv"
-$desc=$collectedClasses.pv
+function Vfx(){}Vfx.builtin$cls="Vfx"
+if(!"name" in Vfx)Vfx.name="Vfx"
+$desc=$collectedClasses.Vfx
if($desc instanceof Array)$desc=$desc[1]
-pv.prototype=$desc
+Vfx.prototype=$desc
function qr(Lf,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.Lf=Lf
this.VJ=VJ
this.Ai=Ai
@@ -26193,11 +26251,11 @@
qr.prototype.gLf.$reflectable=1
qr.prototype.sLf=function(receiver,v){return receiver.Lf=v}
qr.prototype.sLf.$reflectable=1
-function Vfx(){}Vfx.builtin$cls="Vfx"
-if(!"name" in Vfx)Vfx.name="Vfx"
-$desc=$collectedClasses.Vfx
+function Dsd(){}Dsd.builtin$cls="Dsd"
+if(!"name" in Dsd)Dsd.name="Dsd"
+$desc=$collectedClasses.Dsd
if($desc instanceof Array)$desc=$desc[1]
-Vfx.prototype=$desc
+Dsd.prototype=$desc
function Gk(vt,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.vt=vt
this.VJ=VJ
this.Ai=Ai
@@ -26222,11 +26280,11 @@
Gk.prototype.gvt.$reflectable=1
Gk.prototype.svt=function(receiver,v){return receiver.vt=v}
Gk.prototype.svt.$reflectable=1
-function Dsd(){}Dsd.builtin$cls="Dsd"
-if(!"name" in Dsd)Dsd.name="Dsd"
-$desc=$collectedClasses.Dsd
+function tuj(){}tuj.builtin$cls="tuj"
+if(!"name" in tuj)tuj.name="tuj"
+$desc=$collectedClasses.tuj
if($desc instanceof Array)$desc=$desc[1]
-Dsd.prototype=$desc
+tuj.prototype=$desc
function Ds(ql,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.ql=ql
this.VJ=VJ
this.Ai=Ai
@@ -26251,11 +26309,11 @@
Ds.prototype.gql.$reflectable=1
Ds.prototype.sql=function(receiver,v){return receiver.ql=v}
Ds.prototype.sql.$reflectable=1
-function tuj(){}tuj.builtin$cls="tuj"
-if(!"name" in tuj)tuj.name="tuj"
-$desc=$collectedClasses.tuj
+function Vct(){}Vct.builtin$cls="Vct"
+if(!"name" in Vct)Vct.name="Vct"
+$desc=$collectedClasses.Vct
if($desc instanceof Array)$desc=$desc[1]
-tuj.prototype=$desc
+Vct.prototype=$desc
function aI(b,c){this.b=b
this.c=c}aI.builtin$cls="aI"
if(!"name" in aI)aI.name="aI"
@@ -26348,11 +26406,11 @@
pR.prototype.giK.$reflectable=1
pR.prototype.siK=function(receiver,v){return receiver.iK=v}
pR.prototype.siK.$reflectable=1
-function Vct(){}Vct.builtin$cls="Vct"
-if(!"name" in Vct)Vct.name="Vct"
-$desc=$collectedClasses.Vct
+function D13(){}D13.builtin$cls="D13"
+if(!"name" in D13)D13.name="D13"
+$desc=$collectedClasses.D13
if($desc instanceof Array)$desc=$desc[1]
-Vct.prototype=$desc
+D13.prototype=$desc
function hx(Xh,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.Xh=Xh
this.VJ=VJ
this.Ai=Ai
@@ -26377,11 +26435,11 @@
hx.prototype.gXh.$reflectable=1
hx.prototype.sXh=function(receiver,v){return receiver.Xh=v}
hx.prototype.sXh.$reflectable=1
-function D13(){}D13.builtin$cls="D13"
-if(!"name" in D13)D13.name="D13"
-$desc=$collectedClasses.D13
+function WZq(){}WZq.builtin$cls="WZq"
+if(!"name" in WZq)WZq.name="WZq"
+$desc=$collectedClasses.WZq
if($desc instanceof Array)$desc=$desc[1]
-D13.prototype=$desc
+WZq.prototype=$desc
function u7(tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.tH=tH
this.VJ=VJ
this.Ai=Ai
@@ -26428,11 +26486,11 @@
St.prototype.gi0.$reflectable=1
St.prototype.si0=function(receiver,v){return receiver.i0=v}
St.prototype.si0.$reflectable=1
-function WZq(){}WZq.builtin$cls="WZq"
-if(!"name" in WZq)WZq.name="WZq"
-$desc=$collectedClasses.WZq
+function pva(){}pva.builtin$cls="pva"
+if(!"name" in pva)pva.name="pva"
+$desc=$collectedClasses.pva
if($desc instanceof Array)$desc=$desc[1]
-WZq.prototype=$desc
+pva.prototype=$desc
function vj(eb,kf,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.eb=eb
this.kf=kf
this.VJ=VJ
@@ -26462,11 +26520,11 @@
vj.prototype.gkf.$reflectable=1
vj.prototype.skf=function(receiver,v){return receiver.kf=v}
vj.prototype.skf.$reflectable=1
-function pva(){}pva.builtin$cls="pva"
-if(!"name" in pva)pva.name="pva"
-$desc=$collectedClasses.pva
+function cda(){}cda.builtin$cls="cda"
+if(!"name" in cda)cda.name="cda"
+$desc=$collectedClasses.cda
if($desc instanceof Array)$desc=$desc[1]
-pva.prototype=$desc
+cda.prototype=$desc
function CX(iI,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.iI=iI
this.VJ=VJ
this.Ai=Ai
@@ -26491,11 +26549,11 @@
CX.prototype.giI.$reflectable=1
CX.prototype.siI=function(receiver,v){return receiver.iI=v}
CX.prototype.siI.$reflectable=1
-function cda(){}cda.builtin$cls="cda"
-if(!"name" in cda)cda.name="cda"
-$desc=$collectedClasses.cda
+function waa(){}waa.builtin$cls="waa"
+if(!"name" in waa)waa.name="waa"
+$desc=$collectedClasses.waa
if($desc instanceof Array)$desc=$desc[1]
-cda.prototype=$desc
+waa.prototype=$desc
function TJ(oc,eT,yz,Cj,wd,Gs){this.oc=oc
this.eT=eT
this.yz=yz
@@ -26783,11 +26841,11 @@
F1.prototype.gk5.$reflectable=1
F1.prototype.sk5=function(receiver,v){return receiver.k5=v}
F1.prototype.sk5.$reflectable=1
-function waa(){}waa.builtin$cls="waa"
-if(!"name" in waa)waa.name="waa"
-$desc=$collectedClasses.waa
+function V0(){}V0.builtin$cls="V0"
+if(!"name" in V0)V0.name="V0"
+$desc=$collectedClasses.V0
if($desc instanceof Array)$desc=$desc[1]
-waa.prototype=$desc
+V0.prototype=$desc
function uL(tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.tH=tH
this.VJ=VJ
this.Ai=Ai
@@ -27397,13 +27455,13 @@
$desc=$collectedClasses.e9
if($desc instanceof Array)$desc=$desc[1]
e9.prototype=$desc
-function Dw(wc,nn,lv,Pp){this.wc=wc
+function PD(wc,nn,lv,Pp){this.wc=wc
this.nn=nn
this.lv=lv
-this.Pp=Pp}Dw.builtin$cls="Dw"
-$desc=$collectedClasses.Dw
+this.Pp=Pp}PD.builtin$cls="PD"
+$desc=$collectedClasses.PD
if($desc instanceof Array)$desc=$desc[1]
-Dw.prototype=$desc
+PD.prototype=$desc
function Xy(a,b,c){this.a=a
this.b=b
this.c=c}Xy.builtin$cls="Xy"
@@ -27938,11 +27996,11 @@
fI.prototype.gUz.$reflectable=1
fI.prototype.sUz=function(receiver,v){return receiver.Uz=v}
fI.prototype.sUz.$reflectable=1
-function V0(){}V0.builtin$cls="V0"
-if(!"name" in V0)V0.name="V0"
-$desc=$collectedClasses.V0
+function V4(){}V4.builtin$cls="V4"
+if(!"name" in V4)V4.name="V4"
+$desc=$collectedClasses.V4
if($desc instanceof Array)$desc=$desc[1]
-V0.prototype=$desc
+V4.prototype=$desc
function kK(vX,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.vX=vX
this.VJ=VJ
this.Ai=Ai
@@ -27967,11 +28025,11 @@
kK.prototype.gvX.$reflectable=1
kK.prototype.svX=function(receiver,v){return receiver.vX=v}
kK.prototype.svX.$reflectable=1
-function V4(){}V4.builtin$cls="V4"
-if(!"name" in V4)V4.name="V4"
-$desc=$collectedClasses.V4
+function V6(){}V6.builtin$cls="V6"
+if(!"name" in V6)V6.name="V6"
+$desc=$collectedClasses.V6
if($desc instanceof Array)$desc=$desc[1]
-V4.prototype=$desc
+V6.prototype=$desc
function uw(V4,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.V4=V4
this.VJ=VJ
this.Ai=Ai
@@ -27996,11 +28054,11 @@
uw.prototype.gV4.$reflectable=1
uw.prototype.sV4=function(receiver,v){return receiver.V4=v}
uw.prototype.sV4.$reflectable=1
-function V6(){}V6.builtin$cls="V6"
-if(!"name" in V6)V6.name="V6"
-$desc=$collectedClasses.V6
+function V8(){}V8.builtin$cls="V8"
+if(!"name" in V8)V8.name="V8"
+$desc=$collectedClasses.V8
if($desc instanceof Array)$desc=$desc[1]
-V6.prototype=$desc
+V8.prototype=$desc
function V2(N1,bn,Ck){this.N1=N1
this.bn=bn
this.Ck=Ck}V2.builtin$cls="V2"
@@ -28338,7 +28396,7 @@
$desc=$collectedClasses.PW
if($desc instanceof Array)$desc=$desc[1]
PW.prototype=$desc
-return[qE,Yy,Ps,rK,fY,Mr,zx,ct,nB,i3,it,Az,QP,QW,n6,Ny,OM,QQ,MA,y4,d7,na,oJ,DG,mN,vH,hh,Em,Sb,rV,Wy,YN,bA,Wq,rv,BK,wj,cv,Fs,SX,ea,D0,as,T5,Aa,u5,Yu,iG,jP,U2,tA,xn,Vb,QH,ST,X2,fJ,Vi,tX,Sg,pA,Mi,Gt,In,Gx,eP,AL,Og,cS,M6,El,zm,SV,aB,ku,KM,cW,DK,qm,ZY,cx,la,Vn,PG,xe,Hw,bn,Im,oB,Aj,oU,qT,KV,BH,mh,G7,wq,Ql,Xp,bP,mX,SN,HD,ni,p3,qj,qW,KR,ew,fs,bX,BL,MC,Mx,j2,yz,lp,pD,I0,QR,Cp,ua,zD,Ul,G0,wb,fq,h4,qk,GI,Tb,tV,BT,yY,kJ,AE,xV,FH,y6,RH,pU,Lq,Mf,BR,r4,aG,J6,K5,UM,UL,rq,nK,kc,ij,ty,Nf,Nc,rj,rh,Zv,Q7,hF,OF,HB,ZJ,mU,eZ,Fl,y5,nV,Zc,ui,D6,DQ,Sm,dx,es,eG,lv,pf,NV,W1,zo,wf,TU,bb,VE,lc,Xu,qM,tk,me,qN,nh,d4,MI,ca,xX,eW,um,Fu,OE,l6,BA,zp,rE,CC,PQ,uz,Yd,U0,AD,Gr,tc,GH,lo,NJ,nd,vt,rQ,EU,LR,MB,hy,r8,aS,CG,qF,MT,Rk,Eo,Dn,UD,ZD,NE,wD,BD,vRT,Fi,Qr,mj,cB,uY,yR,AX,xJ,l4,Et,NC,nb,By,xt,tG,P0,Jq,Xr,qD,Cf,I2,AS,Kq,oI,mJ,rF,vi,ZX,ycx,nE,zt,F0,Lt,Gv,kn,PE,QI,FP,is,Q,jx,ZC,Jt,P,im,Pp,O,PK,JO,O2,aX,cC,RA,IY,JH,jl,Iy,JM,Ua,JG,ns,wd,TA,YP,yc,I9,Bj,NO,II,aJ,X1,HU,Pm,oo,OW,Dd,AP,yH,FA,Av,oH,LP,c2,WT,p8,XR,LI,A2,F3,u8,Gi,t2,Zr,ZQ,az,vV,Hk,XO,dr,TL,KX,uZ,OQ,Tp,v,Z3,D2,GT,Pe,Eq,cu,Lm,dC,wN,VX,VR,EK,KW,Pb,tQ,aC,Vf,Be,tu,i6,Vc,zO,aL,nH,a7,i1,xy,MH,A8,U5,SO,zs,rR,AM,d5,U1,SJ,SU,Tv,XC,iK,GD,Sn,nI,jU,Lj,mb,am,cw,EE,Uz,uh,Kv,oP,YX,BI,y1,M2,iu,mg,zE,bl,Ef,Oo,Tc,Ax,Wf,Un,Ei,U7,t0,Ld,Sz,Zk,fu,ng,Ar,jB,ye,Gj,Zz,Xh,Ca,Ik,JI,Ip,WV,C7,CQ,dz,tK,OR,Bg,DL,b8,j7,oV,TP,Zf,vs,da,xw,dm,rH,ZL,mi,jb,wB,Pu,qh,QC,Yl,Rv,YJ,jv,LB,DO,lz,Rl,Jb,M4,Jp,h7,pr,eN,B5,PI,j4,i9,VV,Dy,lU,xp,UH,Z5,ii,ib,MO,ms,UO,Bc,vp,lk,Gh,XB,ly,cK,O9,yU,nP,KA,Vo,qB,ez,lx,LV,DS,dp,B3,CR,ny,dR,uR,QX,YR,fB,bq,nO,t3,dq,dX,aY,wJ,e4,JB,Id,fZ,TF,Xz,Cg,Hs,uo,pK,eM,Ue,W5,R8,k6,oi,ce,o2,jG,fG,EQ,YB,iX,ou,S9,ey,xd,v6,db,Cm,N6,jg,YO,oz,b6,ef,zQ,Yp,u3,mW,ar,lD,W0,Sw,o0,a1,jp,Xt,Ba,An,LD,YI,OG,ro,DN,ZM,HW,JC,f1,Uk,wI,ob,Ud,K8,by,dI,QM,Sh,tF,z0,Vx,Rw,GY,jZ,h0,CL,uA,a2,fR,iP,MF,Rq,Hn,Zl,pl,a6,P7,DW,Ge,LK,AT,bJ,mp,ub,ds,lj,UV,VS,t7,HG,aE,kM,EH,cX,eL,L8,c8,a,Od,mE,WU,Rn,wv,uq,iD,hb,XX,Kd,yZ,Gs,pm,Tw,wm,FB,Lk,XZ,qz,hQ,Nw,kZ,JT,d9,rI,dD,QZ,BV,E1,wz,B1,M5,Jn,DM,zL,ec,Kx,iO,bU,e7,nj,rl,RAp,ma,cf,E9,nF,FK,Si,vf,Fc,hD,I4,e0,RO,eu,ie,Ea,pu,i2,b0,Ov,qO,RX,kG,Gm,W9,vZ,dW,PA,H2,O7,HI,E4,r7,Tz,Wk,DV,Hp,Nz,Jd,QS,QF,NL,vr,D4,L9u,Ms,Fw,RS,RY,Ys,vg,xG,Vj,VW,RK,DH,ZK,Th,Vju,KB,RKu,xGn,TkQ,VWk,ZKG,DHb,w6W,Hna,z9g,G8,UZ,Fv,WZ,I3,pv,qr,Vfx,Gk,Dsd,Ds,tuj,aI,rG,yh,wO,Tm,rz,CA,YL,KC,xL,As,GE,pR,Vct,hx,D13,u7,St,WZq,vj,pva,CX,cda,TJ,dG,Ng,HV,Nh,fA,tz,jR,PO,c5,ih,mL,bv,pt,Zd,dY,vY,dS,ZW,dZ,Qe,Nu,pF,Ha,nu,be,Pg,jI,Rb,Zw,Pf,F1,waa,uL,Nr,Pi,yj,qI,J3,E5,o5,b5,zI,Zb,id,iV,W4,Fa,x9,d3,X6,xh,wn,uF,cj,HA,br,zT,D7,qL,C4,l9,lP,km,Qt,Dk,A0,rm,eY,OO,BE,Qb,xI,q1,Zj,XP,q6,CK,BO,ZG,Oc,MX,w12,fTP,yL,dM,Y7,WC,Xi,TV,Mq,Oa,n1,xf,L6,Rs,uJ,hm,Ji,Bf,ir,Sa,GN,k8,HJ,S0,V3,Bl,pM,Mh,Md,Lf,fT,pp,Nq,nl,mf,ej,HK,w13,o8,GL,e9,Dw,Xy,uK,mY,fE,mB,XF,iH,wJY,zOQ,W6o,MdQ,YJG,DOe,lPa,Ufa,Raa,w0,w4,w5,w7,w9,w10,w11,c4,z6,Ay,Ed,G1,Os,Dl,Wh,x5,ev,ID,jV,ek,OC,Xm,Jy,ky,fa,WW,vQ,a9,jh,e3,VA,J1,fk,wL,B0,Fq,hw,EZ,no,kB,ae,Iq,w6,jK,uk,K9,RW,xs,FX,Ae,Bt,vR,Pn,hc,hA,fr,a0,NQ,fI,V0,kK,V4,uw,V6,V2,D8,jY,ll,Uf,ik,LfS,NP,Vh,r0,jz,SA,zV,nv,ee,XI,hs,yp,ug,DT,OB,Ra,N9,NW,HS,TG,ts,Kj,VU,Ya,XT,ic,VT,T4,TR,VD,Oh,zy,Nb,Fy,eU,ADW,Ri,kq,Ag,PW]}// Generated by dart2js, the Dart to JavaScript compiler version: 1.0.0.3_r30188.
+return[qE,Yy,Ps,rK,fY,Mr,zx,ct,nB,i3,it,Az,QP,QW,n6,Ny,OM,QQ,MA,y4,d7,na,oJ,DG,mN,vH,hh,Em,Sb,rV,Wy,YN,bA,Wq,rv,BK,wj,cv,Fs,SX,ea,D0,as,T5,Aa,u5,Yu,iG,jP,U2,tA,xn,Vb,QH,ST,X2,fJ,Vi,tX,Sg,pA,Mi,Gt,In,Gx,eP,AL,Og,cS,M6,El,zm,SV,aB,ku,KM,cW,DK,qm,ZY,cx,la,Vn,PG,xe,Hw,bn,Im,oB,Aj,oU,qT,KV,BH,mh,G7,wq,Ql,Xp,bP,mX,SN,HD,ni,p3,qj,qW,KR,ew,fs,bX,BL,MC,Mx,j2,yz,lp,pD,I0,QR,Cp,ua,zD,Ul,G0,wb,fq,h4,qk,GI,Tb,tV,BT,yY,kJ,AE,xV,FH,y6,RH,pU,Lq,Mf,BR,r4,aG,J6,K5,UM,UL,rq,nK,kc,ij,ty,Nf,Nc,rj,rh,Zv,Q7,hF,OF,HB,ZJ,mU,eZ,Fl,y5,nV,Zc,ui,D6,DQ,Sm,dx,es,eG,lv,pf,NV,W1,zo,wf,TU,bb,VE,lc,Xu,qM,tk,me,qN,nh,d4,MI,ca,xX,eW,um,Fu,OE,l6,BA,zp,rE,CC,PQ,uz,Yd,U0,AD,Gr,tc,GH,lo,NJ,nd,vt,rQ,EU,LR,MB,hy,r8,aS,CG,qF,MT,Rk,Eo,Dn,UD,ZD,NE,wD,BD,vRT,Fi,Qr,mj,cB,uY,yR,AX,xJ,l4,Et,NC,nb,By,xt,tG,P0,Jq,Xr,qD,Cf,I2,AS,Kq,oI,mJ,rF,vi,ZX,ycx,nE,zt,F0,Lt,Gv,kn,PE,QI,FP,is,Q,jx,ZC,Jt,P,im,Pp,O,PK,JO,O2,aX,cC,RA,IY,JH,jl,Iy,JM,Ua,JG,ns,wd,TA,YP,yc,I9,Bj,NO,II,aJ,X1,HU,Pm,oo,OW,Dd,AP,yH,FA,Av,oH,LP,c2,WT,p8,XR,LI,A2,F3,u8,Gi,t2,Zr,ZQ,az,vV,Hk,XO,dr,TL,KX,uZ,OQ,Tp,v,Z3,D2,GT,Pe,Eq,cu,Lm,dC,wN,VX,VR,EK,KW,Pb,tQ,G6,Vf,aC,tu,Be,Vc,i6,WZ,zO,aL,nH,a7,i1,xy,MH,A8,U5,SO,zs,rR,AM,d5,U1,SJ,SU,Tv,XC,iK,GD,Sn,nI,jU,Lj,mb,am,cw,EE,Uz,uh,Kv,oP,YX,BI,y1,M2,iu,mg,zE,bl,Ef,Oo,Tc,Ax,Wf,Un,Ei,U7,t0,Ld,Sz,Zk,fu,ng,Ar,jB,ye,Gj,Zz,Xh,Ca,Ik,JI,Ip,WV,C7,CQ,dz,tK,OR,Bg,DL,b8,j7,oV,TP,Zf,vs,da,xw,dm,rH,ZL,mi,jb,wB,Pu,qh,QC,Yl,Rv,YJ,jv,LB,DO,lz,Rl,Jb,M4,Jp,h7,pr,eN,B5,PI,j4,i9,VV,Dy,lU,xp,UH,Z5,ii,ib,MO,ms,UO,Bc,vp,lk,Gh,XB,ly,cK,O9,yU,nP,KA,Vo,qB,ez,lx,LV,DS,dp,B3,CR,ny,dR,uR,QX,YR,fB,bq,nO,t3,dq,dX,aY,wJ,e4,JB,Id,fZ,TF,Xz,Cg,Hs,uo,pK,eM,Ue,W5,R8,k6,oi,ce,o2,jG,fG,EQ,YB,iX,ou,S9,ey,xd,v6,db,Cm,N6,jg,YO,oz,b6,ef,zQ,Yp,u3,mW,ar,lD,W0,Sw,o0,a1,jp,Xt,Ba,An,LD,YI,OG,ro,DN,ZM,HW,JC,f1,Uk,wI,ob,Ud,K8,by,dI,QM,Sh,tF,z0,Vx,Rw,GY,jZ,h0,CL,uA,a2,fR,iP,MF,Rq,Hn,Zl,pl,a6,P7,DW,Ge,LK,AT,bJ,mp,ub,ds,lj,UV,VS,t7,HG,aE,kM,EH,cX,eL,L8,c8,a,Od,mE,WU,Rn,wv,uq,iD,hb,XX,Kd,yZ,Gs,pm,Tw,wm,FB,Lk,XZ,qz,hQ,Nw,kZ,JT,d9,rI,dD,QZ,BV,E1,wz,B1,M5,Jn,DM,zL,ec,Kx,iO,bU,e7,nj,rl,RAp,ma,cf,E9,nF,FK,Si,vf,Fc,hD,I4,e0,RO,eu,ie,Ea,pu,i2,b0,Ov,qO,RX,kG,Gm,W9,vZ,dW,PA,H2,O7,HI,E4,r7,Tz,Wk,DV,Hp,Nz,Jd,QS,QF,NL,vr,D4,L9u,Ms,Fw,RS,RY,Ys,vg,xG,Vj,VW,RK,DH,ZK,Th,Vju,KB,RKu,xGn,TkQ,VWk,ZKG,DHb,w6W,Hna,z9g,G8,UZ,Fv,pv,I3,Vfx,qr,Dsd,Gk,tuj,Ds,Vct,aI,rG,yh,wO,Tm,rz,CA,YL,KC,xL,As,GE,pR,D13,hx,WZq,u7,St,pva,vj,cda,CX,waa,TJ,dG,Ng,HV,Nh,fA,tz,jR,PO,c5,ih,mL,bv,pt,Zd,dY,vY,dS,ZW,dZ,Qe,Nu,pF,Ha,nu,be,Pg,jI,Rb,Zw,Pf,F1,V0,uL,Nr,Pi,yj,qI,J3,E5,o5,b5,zI,Zb,id,iV,W4,Fa,x9,d3,X6,xh,wn,uF,cj,HA,br,zT,D7,qL,C4,l9,lP,km,Qt,Dk,A0,rm,eY,OO,BE,Qb,xI,q1,Zj,XP,q6,CK,BO,ZG,Oc,MX,w12,fTP,yL,dM,Y7,WC,Xi,TV,Mq,Oa,n1,xf,L6,Rs,uJ,hm,Ji,Bf,ir,Sa,GN,k8,HJ,S0,V3,Bl,pM,Mh,Md,Lf,fT,pp,Nq,nl,mf,ej,HK,w13,o8,GL,e9,PD,Xy,uK,mY,fE,mB,XF,iH,wJY,zOQ,W6o,MdQ,YJG,DOe,lPa,Ufa,Raa,w0,w4,w5,w7,w9,w10,w11,c4,z6,Ay,Ed,G1,Os,Dl,Wh,x5,ev,ID,jV,ek,OC,Xm,Jy,ky,fa,WW,vQ,a9,jh,e3,VA,J1,fk,wL,B0,Fq,hw,EZ,no,kB,ae,Iq,w6,jK,uk,K9,RW,xs,FX,Ae,Bt,vR,Pn,hc,hA,fr,a0,NQ,fI,V4,kK,V6,uw,V8,V2,D8,jY,ll,Uf,ik,LfS,NP,Vh,r0,jz,SA,zV,nv,ee,XI,hs,yp,ug,DT,OB,Ra,N9,NW,HS,TG,ts,Kj,VU,Ya,XT,ic,VT,T4,TR,VD,Oh,zy,Nb,Fy,eU,ADW,Ri,kq,Ag,PW]}// Generated by dart2js, the Dart to JavaScript compiler version: 1.0.0.3_r30188.
(function($){var A={}
delete A.x
var B={}
@@ -28420,7 +28478,7 @@
$$.Y7=[A,{"":"v;wc,nn,lv,Pp",
call$2:function(a,b){return this.nn.call(this.wc,this.lv,a,b)},
$is_bh:true}]
-$$.Dw=[T,{"":"v;wc,nn,lv,Pp",
+$$.PD=[T,{"":"v;wc,nn,lv,Pp",
call$3:function(a,b,c){return this.nn.call(this.wc,a,b,c)}}]
$$.zy=[H,{"":"Tp;call$2,$name",$is_bh:true}]
$$.Nb=[H,{"":"Tp;call$1,$name",$is_HB:true,$is_Dv:true}]
@@ -28443,7 +28501,7 @@
call$catchAll:function(){return{onError:null,radix:null}},
$is_HB:true,
$is_Dv:true}]
-;init.mangledNames={gB:"length",gDb:"_cachedDeclarations",gEI:"prefix",gF1:"isolate",gFF:"source",gFJ:"__$cls",gFT:"__$instruction",gFU:"_cachedMethodsMap",gG1:"message",gH8:"_fieldsDescriptor",gHt:"_fieldsMetadata",gKM:"$",gLA:"src",gLf:"__$field",gLy:"_cachedSetters",gM2:"_cachedVariables",gMj:"function",gNI:"instruction",gNl:"script",gO3:"url",gOk:"_cachedMetadata",gP:"value",gP2:"_collapsed",gPw:"__$isolate",gPy:"__$error",gQG:"app",gRu:"cls",gT1:"_cachedGetters",gTn:"json",gTx:"_jsConstructorOrInterceptor",gUF:"_cachedTypeVariables",gUz:"__$script",gV4:"__$trace",gVA:"__$displayValue",gVB:"error_obj",gWL:"_mangledName",gXB:"_message",gXJ:"lines",gXR:"scripts",gXf:"__$iconClass",gXh:"__$instance",gZ6:"locationManager",gZw:"__$code",ga:"a",gai:"displayValue",gb:"b",gb0:"_cachedConstructors",gcC:"hash",geV:"paddedLine",geb:"__$json",gfY:"kind",ghO:"__$error_obj",ghf:"instance",gi0:"__$name",gi2:"isolates",giI:"__$library",giK:"__$instance",gjO:"id",gjd:"_cachedMethods",gk5:"__$devtools",gkc:"error",gkf:"_count",gl7:"iconClass",glD:"currentHashUri",gle:"_metadata",glw:"requestManager",gn2:"responses",gnI:"isolateManager",gnz:"_owner",goc:"name",gpz:"_jsConstructorCache",gqN:"_superclass",gql:"__$function",gqm:"_cachedSuperinterfaces",gt0:"field",gtB:"_cachedFields",gtD:"library",gtH:"__$app",gtN:"trace",gtT:"code",guA:"_cachedMembers",gvH:"index",gvX:"__$source",gvt:"__$field",gxj:"collapsed",gzd:"currentHash",gzj:"devtools"};init.mangledGlobalNames={DI:"_closeIconClass",Vl:"_openIconClass"};(function (reflectionData) {
+;init.mangledNames={gB:"length",gDb:"_cachedDeclarations",gEI:"prefix",gF1:"isolate",gFF:"source",gFJ:"__$cls",gFT:"__$instruction",gFU:"_cachedMethodsMap",gG1:"message",gH8:"_fieldsDescriptor",gHt:"_fieldsMetadata",gKM:"$",gLA:"src",gLf:"__$field",gLy:"_cachedSetters",gM2:"_cachedVariables",gMj:"function",gNI:"instruction",gNl:"script",gO3:"url",gOk:"_cachedMetadata",gP:"value",gP2:"_collapsed",gPw:"__$isolate",gPy:"__$error",gQG:"app",gRu:"cls",gT1:"_cachedGetters",gTn:"json",gTx:"_jsConstructorOrInterceptor",gUF:"_cachedTypeVariables",gUz:"__$script",gV4:"__$trace",gVA:"__$displayValue",gVB:"error_obj",gWL:"_mangledName",gXB:"_message",gXJ:"lines",gXR:"scripts",gXf:"__$iconClass",gXh:"__$instance",gZ6:"locationManager",gZw:"__$code",ga:"a",gai:"displayValue",gb:"b",gb0:"_cachedConstructors",gcC:"hash",geE:"__$msg",geV:"paddedLine",geb:"__$json",gfY:"kind",ghO:"__$error_obj",ghf:"instance",gi0:"__$name",gi2:"isolates",giI:"__$library",giK:"__$instance",gjO:"id",gjd:"_cachedMethods",gk5:"__$devtools",gkc:"error",gkf:"_count",gl7:"iconClass",glD:"currentHashUri",gle:"_metadata",glw:"requestManager",gn2:"responses",gnI:"isolateManager",gnz:"_owner",goc:"name",gpz:"_jsConstructorCache",gqN:"_superclass",gql:"__$function",gqm:"_cachedSuperinterfaces",grs:"msg",gt0:"field",gtB:"_cachedFields",gtD:"library",gtH:"__$app",gtN:"trace",gtT:"code",guA:"_cachedMembers",gvH:"index",gvX:"__$source",gvt:"__$field",gxj:"collapsed",gzd:"currentHash",gzj:"devtools"};init.mangledGlobalNames={DI:"_closeIconClass",Vl:"_openIconClass"};(function (reflectionData) {
function map(x){x={x:x};delete x.x;return x}
if (!init.libraries) init.libraries = [];
if (!init.mangledNames) init.mangledNames = map();
@@ -30076,14 +30134,38 @@
t:function(a,b){if(!J.xC(b,0))H.vh(P.N(b))
return this.zO},
"+[]:1:0":0,
-$isOd:true}}],["app_bootstrap","index_devtools.html_bootstrap.dart",,E,{E2:function(){$.x2=["package:observatory/src/observatory_elements/observatory_element.dart","package:observatory/src/observatory_elements/error_view.dart","package:observatory/src/observatory_elements/field_ref.dart","package:observatory/src/observatory_elements/instance_ref.dart","package:observatory/src/observatory_elements/class_view.dart","package:observatory/src/observatory_elements/disassembly_entry.dart","package:observatory/src/observatory_elements/code_view.dart","package:observatory/src/observatory_elements/collapsible_content.dart","package:observatory/src/observatory_elements/field_view.dart","package:observatory/src/observatory_elements/function_view.dart","package:observatory/src/observatory_elements/isolate_summary.dart","package:observatory/src/observatory_elements/isolate_list.dart","package:observatory/src/observatory_elements/instance_view.dart","package:observatory/src/observatory_elements/json_view.dart","package:observatory/src/observatory_elements/library_view.dart","package:observatory/src/observatory_elements/source_view.dart","package:observatory/src/observatory_elements/script_view.dart","package:observatory/src/observatory_elements/stack_trace.dart","package:observatory/src/observatory_elements/message_viewer.dart","package:observatory/src/observatory_elements/navigation_bar.dart","package:observatory/src/observatory_elements/response_viewer.dart","package:observatory/src/observatory_elements/observatory_application.dart","index_devtools.html.0.dart"]
+$isOd:true}}],["app_bootstrap","index_devtools.html_bootstrap.dart",,E,{E2:function(){$.x2=["package:observatory/src/observatory_elements/observatory_element.dart","package:observatory/src/observatory_elements/breakpoint_list.dart","package:observatory/src/observatory_elements/error_view.dart","package:observatory/src/observatory_elements/field_ref.dart","package:observatory/src/observatory_elements/instance_ref.dart","package:observatory/src/observatory_elements/class_view.dart","package:observatory/src/observatory_elements/disassembly_entry.dart","package:observatory/src/observatory_elements/code_view.dart","package:observatory/src/observatory_elements/collapsible_content.dart","package:observatory/src/observatory_elements/field_view.dart","package:observatory/src/observatory_elements/function_view.dart","package:observatory/src/observatory_elements/isolate_summary.dart","package:observatory/src/observatory_elements/isolate_list.dart","package:observatory/src/observatory_elements/instance_view.dart","package:observatory/src/observatory_elements/json_view.dart","package:observatory/src/observatory_elements/library_view.dart","package:observatory/src/observatory_elements/source_view.dart","package:observatory/src/observatory_elements/script_view.dart","package:observatory/src/observatory_elements/stack_trace.dart","package:observatory/src/observatory_elements/message_viewer.dart","package:observatory/src/observatory_elements/navigation_bar.dart","package:observatory/src/observatory_elements/response_viewer.dart","package:observatory/src/observatory_elements/observatory_application.dart","index_devtools.html.0.dart"]
$.uP=!1
-A.Ok()}},1],["class_view_element","package:observatory/src/observatory_elements/class_view.dart",,Z,{aC:{"":["Vf;FJ%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+A.Ok()}},1],["breakpoint_list_element","package:observatory/src/observatory_elements/breakpoint_list.dart",,B,{G6:{"":["Vf;eE%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+grs:function(a){return a.eE
+"38,39,40"},
+"+msg":1,
+srs:function(a,b){a.eE=this.pD(a,C.Ry,a.eE,b)
+"41,32,38,39"},
+"+msg=":1,
+"@":function(){return[C.PT]},
+static:{Dw:function(a){var z,y,x,w,v,u
+z=H.B7([],P.L5(null,null,null,null,null))
+z=R.Jk(z)
+y=$.Nd()
+x=P.Py(null,null,null,J.O,W.I0)
+w=J.O
+v=W.cv
+u=new V.br(P.Py(null,null,null,w,v),null,null)
+H.VM(u,[w,v])
+a.eE=z
+a.Ye=y
+a.mT=x
+a.KM=u
+C.J0.ZL(a)
+C.J0.FH(a)
+return a
+"9"},"+new BreakpointListElement$created:0:0":1}},"+BreakpointListElement": [42],Vf:{"":"uL+Pi;",$isd3:true}}],["class_view_element","package:observatory/src/observatory_elements/class_view.dart",,Z,{aC:{"":["tu;FJ%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gRu:function(a){return a.FJ
-"37,38,39"},
+"38,39,40"},
"+cls":1,
sRu:function(a,b){a.FJ=this.pD(a,C.XA,a.FJ,b)
-"40,31,37,38"},
+"41,32,38,39"},
"+cls=":1,
"@":function(){return[C.aQ]},
static:{zg:function(a){var z,y,x,w,v
@@ -30099,12 +30181,12 @@
C.kk.ZL(a)
C.kk.FH(a)
return a
-"9"},"+new ClassViewElement$created:0:0":1}},"+ClassViewElement": [41],Vf:{"":"uL+Pi;",$isd3:true}}],["code_view_element","package:observatory/src/observatory_elements/code_view.dart",,F,{Be:{"":["tu;Zw%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"10"},"+new ClassViewElement$created:0:0":1}},"+ClassViewElement": [43],tu:{"":"uL+Pi;",$isd3:true}}],["code_view_element","package:observatory/src/observatory_elements/code_view.dart",,F,{Be:{"":["Vc;Zw%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gtT:function(a){return a.Zw
-"37,38,39"},
+"38,39,40"},
"+code":1,
stT:function(a,b){a.Zw=this.pD(a,C.b1,a.Zw,b)
-"40,31,37,38"},
+"41,32,38,39"},
"+code=":1,
grK:function(a){var z=a.Zw
if(z!=null&&J.UQ(z,"is_optimized")!=null)return"panel panel-success"
@@ -30128,41 +30210,41 @@
C.YD.ZL(a)
C.YD.FH(a)
return a
-"10"},"+new CodeViewElement$created:0:0":1}},"+CodeViewElement": [42],tu:{"":"uL+Pi;",$isd3:true}}],["collapsible_content_element","package:observatory/src/observatory_elements/collapsible_content.dart",,R,{i6:{"":["Vc;Xf%-,VA%-,P2%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"11"},"+new CodeViewElement$created:0:0":1}},"+CodeViewElement": [44],Vc:{"":"uL+Pi;",$isd3:true}}],["collapsible_content_element","package:observatory/src/observatory_elements/collapsible_content.dart",,R,{i6:{"":["WZ;Xf%-,VA%-,P2%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gl7:function(a){return a.Xf
-"8,38,43"},
+"8,39,45"},
"+iconClass":1,
sl7:function(a,b){a.Xf=this.pD(a,C.Di,a.Xf,b)
-"40,31,8,38"},
+"41,32,8,39"},
"+iconClass=":1,
gai:function(a){return a.VA
-"8,38,43"},
+"8,39,45"},
"+displayValue":1,
sai:function(a,b){a.VA=this.pD(a,C.Jw,a.VA,b)
-"40,31,8,38"},
+"41,32,8,39"},
"+displayValue=":1,
gxj:function(a){return a.P2
-"44"},
+"46"},
"+collapsed":1,
sxj:function(a,b){a.P2=b
this.dR(a)
-"40,45,44"},
+"41,47,46"},
"+collapsed=":1,
i4:function(a){Z.uL.prototype.i4.call(this,a)
this.dR(a)
-"40"},
+"41"},
"+enteredView:0:0":1,
rS:function(a,b,c,d){a.P2=a.P2!==!0
this.dR(a)
this.dR(a)
-"40,46,47,48,40,49,50"},
+"41,48,49,50,41,51,52"},
"+toggleDisplay:3:0":1,
dR:function(a){var z,y
z=a.P2
y=a.Xf
if(z===!0){a.Xf=this.pD(a,C.Di,y,"glyphicon glyphicon-chevron-down")
a.VA=this.pD(a,C.Jw,a.VA,"none")}else{a.Xf=this.pD(a,C.Di,y,"glyphicon glyphicon-chevron-up")
-a.VA=this.pD(a,C.Jw,a.VA,"block")}"40"},
+a.VA=this.pD(a,C.Jw,a.VA,"block")}"41"},
"+_refresh:0:0":1,
"@":function(){return[C.Gu]},
static:{"":"Vl<-,DI<-",IT:function(a){var z,y,x,w,v
@@ -30181,7 +30263,7 @@
C.j8.ZL(a)
C.j8.FH(a)
return a
-"11"},"+new CollapsibleContentElement$created:0:0":1}},"+CollapsibleContentElement": [51],Vc:{"":"uL+Pi;",$isd3:true}}],["custom_element.polyfill","package:custom_element/polyfill.dart",,B,{G9:function(){if($.LX()==null)return!0
+"12"},"+new CollapsibleContentElement$created:0:0":1}},"+CollapsibleContentElement": [53],WZ:{"":"uL+Pi;",$isd3:true}}],["custom_element.polyfill","package:custom_element/polyfill.dart",,B,{G9:function(){if($.LX()==null)return!0
var z=J.UQ($.LX(),"CustomElements")
if(z==null)return"register" in document
return J.xC(J.UQ(z,"ready"),!0)},zO:{"":"Tp;",
@@ -30749,7 +30831,7 @@
if(typeof y==="object"&&y!==null&&!!z.$isZk)if(!("$reflectable" in y.dl))H.Hz(J.Z0(a))
return H.vn(y.qj(b,c))},
"+invoke:3:0":0,
-"*invoke":[40],
+"*invoke":[41],
CI:function(a,b){return this.F2(a,b,null)},
"+invoke:2:0":0,
Z0:function(a){return $[a]},
@@ -30889,7 +30971,7 @@
"+declarations":0,
F2:function(a,b,c){throw H.b(P.lr(this,a,b,c,null))},
"+invoke:3:0":0,
-"*invoke":[40],
+"*invoke":[41],
CI:function(a,b){return this.F2(a,b,null)},
"+invoke:2:0":0,
rN:function(a){throw H.b(P.lr(this,a,null,null,null))},
@@ -30911,7 +30993,7 @@
y=z+":"+b.length+":0"
return this.tu(a,0,y,b)},
"+invoke:3:0":0,
-"*invoke":[40],
+"*invoke":[41],
CI:function(a,b){return this.F2(a,b,null)},
"+invoke:2:0":0,
tu:function(a,b,c,d){var z,y,x,w,v,u,t,s
@@ -31038,7 +31120,7 @@
return z},
F2:function(a,b,c){return this.NK.F2(a,b,c)},
"+invoke:3:0":0,
-"*invoke":[40],
+"*invoke":[41],
CI:function(a,b){return this.F2(a,b,null)},
"+invoke:2:0":0,
gHA:function(){return!1},
@@ -31090,7 +31172,7 @@
y=J.x(z)
if(typeof z==="object"&&z!==null&&!!y.$isGv)return z.constructor
else return z
-"40"},
+"41"},
"+_jsConstructor":1,
gDI:function(){var z=this.b0
if(z!=null)return z
@@ -31098,7 +31180,7 @@
H.VM(z,[P.wv,P.RS])
this.b0=z
return z
-"52"},
+"54"},
"+constructors":1,
ly:function(a){var z,y,x,w,v,u,t,s,r,q,p,o,n,m,l,k
z=this.gaB().prototype
@@ -31143,14 +31225,14 @@
l=!1}s=H.Sd(k,o,!l,l)
x.push(s)
s.nz=a}return x
-"53,54,55"},
+"55,56,57"},
"+_getMethodsWithOwner:1:0":1,
gEO:function(){var z=this.jd
if(z!=null)return z
z=this.ly(this)
this.jd=z
return z
-"53"},
+"55"},
"+_methods":1,
ws:function(a){var z,y,x,w
z=[]
@@ -31164,14 +31246,14 @@
w=init.statics[this.WL]
if(w!=null)H.jw(a,w[""],!0,z)
return z
-"56,57,55"},
+"58,59,57"},
"+_getFieldsWithOwner:1:0":1,
gKn:function(){var z=this.tB
if(z!=null)return z
z=this.ws(this)
this.tB=z
return z
-"56"},
+"58"},
"+_fields":1,
gtx:function(){var z=this.FU
if(z!=null)return z
@@ -31179,7 +31261,7 @@
H.VM(z,[P.wv,P.RS])
this.FU=z
return z
-"52"},
+"54"},
"+methods":1,
gZ3:function(){var z,y,x
z=this.M2
@@ -31190,7 +31272,7 @@
H.VM(z,[P.wv,P.RY])
this.M2=z
return z
-"58"},
+"60"},
"+variables":1,
glc:function(a){var z=this.uA
if(z!=null)return z
@@ -31198,7 +31280,7 @@
H.VM(z,[P.wv,P.QF])
this.uA=z
return z
-"59"},
+"61"},
"+members":1,
gYK:function(){var z,y
z=this.Db
@@ -31212,7 +31294,7 @@
H.VM(z,[P.wv,P.NL])
this.Db=z
return z
-"60"},
+"62"},
"+declarations":1,
PU:function(a,b){var z,y
z=J.UQ(this.gZ3(),a)
@@ -31220,7 +31302,7 @@
if(!(y in $))throw H.b(H.Pa("Cannot find \""+y+"\" in current isolate."))
$[y]=b
return H.vn(b)}throw H.b(P.lr(this,H.X7(a),[b],null,null))
-"61,62,63,64,0"},
+"63,64,65,66,0"},
"+setField:2:0":1,
rN:function(a){var z,y
z=J.UQ(this.gZ3(),a)
@@ -31228,7 +31310,7 @@
if(!(y in $))throw H.b(H.Pa("Cannot find \""+y+"\" in current isolate."))
if(y in init.lazies)return H.vn($[init.lazies[y]]())
else return H.vn($[y])}throw H.b(P.lr(this,a,null,null,null))
-"61,62,63"},
+"63,64,65"},
"+getField:1:0":1,
gh7:function(){var z,y,x,w,v,u,t
if(this.nz==null){z=this.Tx
@@ -31247,7 +31329,7 @@
z=new H.MH(null,y,z.ew)
z.$builtinTypeInfo=[u,t]
for(;z.G();)for(y=J.GP(z.mD);y.G();)J.pP(y.gl())}if(this.nz==null)throw H.b(new P.lj("Class \""+H.d(J.Z0(this.If))+"\" has no owner"))}return this.nz
-"65"},
+"67"},
"+owner":1,
gc9:function(){var z=this.Ok
if(z!=null)return z
@@ -31256,7 +31338,7 @@
H.VM(z,[P.vr])
this.Ok=z
return z
-"66"},
+"68"},
"+metadata":1,
gAY:function(){var z,y,x,w,v,u
if(this.qN==null){z=init.typeInformation[this.WL]
@@ -31270,7 +31352,7 @@
u=v.length
if(u>1){if(u!==2)throw H.b(H.Pa("Strange mixin: "+H.d(y)))
this.qN=H.jO(v[0])}else this.qN=x.n(w,"")?this:H.jO(w)}}return J.xC(this.qN,this)?null:this.qN
-"67"},
+"69"},
"+superclass":1,
F2:function(a,b,c){var z
if(c!=null&&J.FN(c)!==!0)throw H.b(P.f("Named arguments are not implemented."))
@@ -31278,16 +31360,16 @@
if(z==null||!z.gFo())throw H.b(P.lr(this,a,b,c,null))
if(!z.yR())H.Hz(J.Z0(a))
return H.vn(z.qj(b,c))
-"61,68,63,69,70,71,72"},
+"63,70,65,71,72,73,74"},
"+invoke:3:0":1,
-"*invoke":[40],
+"*invoke":[41],
CI:function(a,b){return this.F2(a,b,null)},
"+invoke:2:0":1,
gHA:function(){return!0
-"44"},
+"46"},
"+isOriginalDeclaration":1,
gJi:function(){return this
-"67"},
+"69"},
"+originalDeclaration":1,
MR:function(a){var z,y,x
z=init.typeInformation[this.WL]
@@ -31297,14 +31379,14 @@
y=new P.Yp(x)
H.VM(y,[P.Ms])
return y
-"73,74,55"},
+"75,76,57"},
"+_getSuperinterfacesWithOwner:1:0":1,
gkZ:function(){var z=this.qm
if(z!=null)return z
z=this.MR(this)
this.qm=z
return z
-"73"},
+"75"},
"+superinterfaces":1,
gNy:function(){var z,y,x,w,v
z=this.UF
@@ -31317,34 +31399,34 @@
H.VM(z,[null])
this.UF=z
return z
-"75"},
+"77"},
"+typeVariables":1,
gw8:function(){return C.hU
-"76"},
+"78"},
"+typeArguments":1,
$isWf:true,
$isMs:true,
$isQF:true,
$isL9u:true,
-$isNL:true},"+JsClassMirror": [77, 67],Un:{"":"EE+M2;",$isQF:true},Ei:{"":"Tp;a-",
+$isNL:true},"+JsClassMirror": [79, 69],Un:{"":"EE+M2;",$isQF:true},Ei:{"":"Tp;a-",
call$2:function(a,b){J.kW(this.a,a,b)
-"40,78,63,31,79"},
+"41,80,65,32,81"},
"+call:2:0":1,
$isEH:true,
-$is_bh:true},"+JsClassMirror_declarations_addToResult": [80],U7:{"":"Tp;b-",
+$is_bh:true},"+JsClassMirror_declarations_addToResult": [82],U7:{"":"Tp;b-",
call$1:function(a){J.kW(this.b,a.gIf(),a)
return a
-"40,81,40"},
+"41,83,41"},
"+call:1:0":1,
$isEH:true,
$is_HB:true,
-$is_Dv:true},"+JsClassMirror_declarations_closure": [80],t0:{"":"Tp;a-",
+$is_Dv:true},"+JsClassMirror_declarations_closure": [82],t0:{"":"Tp;a-",
call$1:function(a){return H.Jf(this.a,init.metadata[a])
-"67,82,30"},
+"69,84,31"},
"+call:1:0":1,
$isEH:true,
$is_HB:true,
-$is_Dv:true},"+JsClassMirror__getSuperinterfacesWithOwner_lookupType": [80],Ld:{"":"am;ao<,V5<,Fo<,n6,nz,le,If",
+$is_Dv:true},"+JsClassMirror__getSuperinterfacesWithOwner_lookupType": [82],Ld:{"":"am;ao<,V5<,Fo<,n6,nz,le,If",
gOO:function(){return"VariableMirror"},
"+_prettyName":0,
gr9:function(a){return $.Cr()},
@@ -32011,7 +32093,7 @@
$is_Dv:true},dm:{"":"Tp;b",
call$2:function(a,b){this.b.K5(a,b)},
"+call:2:0":0,
-"*call":[40],
+"*call":[41],
call$1:function(a){return this.call$2(a,null)},
"+call:1:0":0,
$isEH:true,
@@ -32080,7 +32162,7 @@
if(typeof y!=="object"||y===null||!x.$isvs){z.a=P.Dt(null)
z.a.E6(a,b)}P.HZ(z.a,this.h)},
"+call:2:0":0,
-"*call":[40],
+"*call":[41],
call$1:function(a){return this.call$2(a,null)},
"+call:1:0":0,
$isEH:true,
@@ -35230,7 +35312,7 @@
gor:function(a){return J.pO(this.iY)},
"+isNotEmpty":0,
$isL8:true}}],["dart.dom.html","dart:html",,W,{lq:function(){return window
-"12"},"+window":1,UE:function(a){if(P.F7()===!0)return"webkitTransitionEnd"
+"13"},"+window":1,UE:function(a){if(P.F7()===!0)return"webkitTransitionEnd"
else if(P.dg()===!0)return"oTransitionEnd"
return"transitionend"},r3:function(a,b){return document.createElement(a)},It:function(a,b,c){return W.lt(a,null,null,b,null,null,null,c).ml(new W.Kx())},lt:function(a,b,c,d,e,f,g,h){var z,y,x,w
z=W.fJ
@@ -35301,7 +35383,7 @@
q={prototype: s}
if(!J.xC(w,"HTMLElement"))if(!v)q.extends=e
b.register(c,q)},aF:function(a){if(J.xC($.X3,C.NU))return a
-return $.X3.oj(a,!0)},qE:{"":"cv;","%":"HTMLAppletElement|HTMLBRElement|HTMLBaseFontElement|HTMLBodyElement|HTMLCanvasElement|HTMLContentElement|HTMLDListElement|HTMLDataListElement|HTMLDetailsElement|HTMLDialogElement|HTMLDirectoryElement|HTMLDivElement|HTMLFontElement|HTMLFrameElement|HTMLFrameSetElement|HTMLHRElement|HTMLHeadElement|HTMLHeadingElement|HTMLHtmlElement|HTMLMarqueeElement|HTMLMenuElement|HTMLModElement|HTMLOptGroupElement|HTMLParagraphElement|HTMLPreElement|HTMLQuoteElement|HTMLShadowElement|HTMLSpanElement|HTMLTableCaptionElement|HTMLTableCellElement|HTMLTableColElement|HTMLTableDataCellElement|HTMLTableElement|HTMLTableHeaderCellElement|HTMLTableRowElement|HTMLTableSectionElement|HTMLTitleElement|HTMLUListElement|HTMLUnknownElement;HTMLElement;Sa|GN|ir|Nr|uL|Vf|aC|tu|Be|Vc|i6|WZ|Fv|pv|I3|Vfx|qr|Dsd|Gk|tuj|Ds|Vct|pR|D13|hx|u7|WZq|St|pva|vj|cda|CX|Nh|ih|waa|F1|XP|NQ|V0|fI|V4|kK|V6|uw"},Yy:{"":"Gv;",$isList:true,
+return $.X3.oj(a,!0)},qE:{"":"cv;","%":"HTMLAppletElement|HTMLBRElement|HTMLBaseFontElement|HTMLBodyElement|HTMLCanvasElement|HTMLContentElement|HTMLDListElement|HTMLDataListElement|HTMLDetailsElement|HTMLDialogElement|HTMLDirectoryElement|HTMLDivElement|HTMLFontElement|HTMLFrameElement|HTMLFrameSetElement|HTMLHRElement|HTMLHeadElement|HTMLHeadingElement|HTMLHtmlElement|HTMLMarqueeElement|HTMLMenuElement|HTMLModElement|HTMLOptGroupElement|HTMLParagraphElement|HTMLPreElement|HTMLQuoteElement|HTMLShadowElement|HTMLSpanElement|HTMLTableCaptionElement|HTMLTableCellElement|HTMLTableColElement|HTMLTableDataCellElement|HTMLTableElement|HTMLTableHeaderCellElement|HTMLTableRowElement|HTMLTableSectionElement|HTMLTitleElement|HTMLUListElement|HTMLUnknownElement;HTMLElement;Sa|GN|ir|Nr|uL|Vf|G6|tu|aC|Vc|Be|WZ|i6|pv|Fv|Vfx|I3|Dsd|qr|tuj|Gk|Vct|Ds|D13|pR|WZq|hx|u7|pva|St|cda|vj|waa|CX|Nh|ih|V0|F1|XP|NQ|V4|fI|V6|kK|V8|uw"},Yy:{"":"Gv;",$isList:true,
$asWO:function(){return[W.M5]},
$isqC:true,
$iscX:true,
@@ -36335,12 +36417,12 @@
$iscX:true,
$ascX:function(){return[J.im]},
$isXj:true,
-static:{"":"U9",}}}],["disassembly_entry_element","package:observatory/src/observatory_elements/disassembly_entry.dart",,E,{Fv:{"":["WZ;FT%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+static:{"":"U9",}}}],["disassembly_entry_element","package:observatory/src/observatory_elements/disassembly_entry.dart",,E,{Fv:{"":["pv;FT%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gNI:function(a){return a.FT
-"37,38,39"},
+"38,39,40"},
"+instruction":1,
sNI:function(a,b){a.FT=this.pD(a,C.eJ,a.FT,b)
-"40,31,37,38"},
+"41,32,38,39"},
"+instruction=":1,
"@":function(){return[C.Vy]},
static:{AH:function(a){var z,y,x,w,v,u
@@ -36359,18 +36441,18 @@
C.Tl.ZL(a)
C.Tl.FH(a)
return a
-"13"},"+new DisassemblyEntryElement$created:0:0":1}},"+DisassemblyEntryElement": [83],WZ:{"":"uL+Pi;",$isd3:true}}],["error_view_element","package:observatory/src/observatory_elements/error_view.dart",,F,{I3:{"":["pv;Py%-,hO%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"14"},"+new DisassemblyEntryElement$created:0:0":1}},"+DisassemblyEntryElement": [85],pv:{"":"uL+Pi;",$isd3:true}}],["error_view_element","package:observatory/src/observatory_elements/error_view.dart",,F,{I3:{"":["Vfx;Py%-,hO%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gkc:function(a){return a.Py
-"8,38,39"},
+"8,39,40"},
"+error":1,
skc:function(a,b){a.Py=this.pD(a,C.YU,a.Py,b)
-"40,31,8,38"},
+"41,32,8,39"},
"+error=":1,
gVB:function(a){return a.hO
-"40,38,39"},
+"41,39,40"},
"+error_obj":1,
sVB:function(a,b){a.hO=this.pD(a,C.Yn,a.hO,b)
-"40,31,40,38"},
+"41,32,41,39"},
"+error_obj=":1,
"@":function(){return[C.uW]},
static:{TW:function(a){var z,y,x,w,v
@@ -36387,12 +36469,12 @@
C.OD.ZL(a)
C.OD.FH(a)
return a
-"14"},"+new ErrorViewElement$created:0:0":1}},"+ErrorViewElement": [84],pv:{"":"uL+Pi;",$isd3:true}}],["field_ref_element","package:observatory/src/observatory_elements/field_ref.dart",,D,{qr:{"":["Vfx;Lf%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"15"},"+new ErrorViewElement$created:0:0":1}},"+ErrorViewElement": [86],Vfx:{"":"uL+Pi;",$isd3:true}}],["field_ref_element","package:observatory/src/observatory_elements/field_ref.dart",,D,{qr:{"":["Dsd;Lf%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gt0:function(a){return a.Lf
-"37,38,39"},
+"38,39,40"},
"+field":1,
st0:function(a,b){a.Lf=this.pD(a,C.WQ,a.Lf,b)
-"40,31,37,38"},
+"41,32,38,39"},
"+field=":1,
"@":function(){return[C.ht]},
static:{ip:function(a){var z,y,x,w,v
@@ -36408,12 +36490,12 @@
C.WR.ZL(a)
C.WR.FH(a)
return a
-"15"},"+new FieldRefElement$created:0:0":1}},"+FieldRefElement": [85],Vfx:{"":"uL+Pi;",$isd3:true}}],["field_view_element","package:observatory/src/observatory_elements/field_view.dart",,A,{Gk:{"":["Dsd;vt%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"16"},"+new FieldRefElement$created:0:0":1}},"+FieldRefElement": [87],Dsd:{"":"uL+Pi;",$isd3:true}}],["field_view_element","package:observatory/src/observatory_elements/field_view.dart",,A,{Gk:{"":["tuj;vt%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gt0:function(a){return a.vt
-"37,38,39"},
+"38,39,40"},
"+field":1,
st0:function(a,b){a.vt=this.pD(a,C.WQ,a.vt,b)
-"40,31,37,38"},
+"41,32,38,39"},
"+field=":1,
"@":function(){return[C.Tq]},
static:{cY:function(a){var z,y,x,w,v
@@ -36429,12 +36511,12 @@
C.lS.ZL(a)
C.lS.FH(a)
return a
-"16"},"+new FieldViewElement$created:0:0":1}},"+FieldViewElement": [86],Dsd:{"":"uL+Pi;",$isd3:true}}],["function_view_element","package:observatory/src/observatory_elements/function_view.dart",,N,{Ds:{"":["tuj;ql%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"17"},"+new FieldViewElement$created:0:0":1}},"+FieldViewElement": [88],tuj:{"":"uL+Pi;",$isd3:true}}],["function_view_element","package:observatory/src/observatory_elements/function_view.dart",,N,{Ds:{"":["Vct;ql%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gMj:function(a){return a.ql
-"37,38,39"},
+"38,39,40"},
"+function":1,
sMj:function(a,b){a.ql=this.pD(a,C.nf,a.ql,b)
-"40,31,37,38"},
+"41,32,38,39"},
"+function=":1,
"@":function(){return[C.Uc]},
static:{p7:function(a){var z,y,x,w,v
@@ -36450,7 +36532,7 @@
C.PJ.ZL(a)
C.PJ.FH(a)
return a
-"17"},"+new FunctionViewElement$created:0:0":1}},"+FunctionViewElement": [87],tuj:{"":"uL+Pi;",$isd3:true}}],["html_common","dart:html_common",,P,{jD:function(a){return P.Wu(a.getTime(),!0)},bL:function(a){var z,y
+"18"},"+new FunctionViewElement$created:0:0":1}},"+FunctionViewElement": [89],Vct:{"":"uL+Pi;",$isd3:true}}],["html_common","dart:html_common",,P,{jD:function(a){return P.Wu(a.getTime(),!0)},bL:function(a){var z,y
z=[]
y=new P.Tm(new P.aI([],z),new P.rG(z),new P.yh(z)).call$1(a)
new P.wO().call$0()
@@ -36638,12 +36720,12 @@
"+call:1:0":0,
$isEH:true,
$is_HB:true,
-$is_Dv:true}}],["instance_ref_element","package:observatory/src/observatory_elements/instance_ref.dart",,B,{pR:{"":["Vct;iK%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+$is_Dv:true}}],["instance_ref_element","package:observatory/src/observatory_elements/instance_ref.dart",,B,{pR:{"":["D13;iK%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
ghf:function(a){return a.iK
-"37,38,39"},
+"38,39,40"},
"+instance":1,
shf:function(a,b){a.iK=this.pD(a,C.fn,a.iK,b)
-"40,31,37,38"},
+"41,32,38,39"},
"+instance=":1,
"@":function(){return[C.ay]},
static:{lu:function(a){var z,y,x,w,v
@@ -36659,12 +36741,12 @@
C.cp.ZL(a)
C.cp.FH(a)
return a
-"18"},"+new InstanceRefElement$created:0:0":1}},"+InstanceRefElement": [88],Vct:{"":"uL+Pi;",$isd3:true}}],["instance_view_element","package:observatory/src/observatory_elements/instance_view.dart",,Z,{hx:{"":["D13;Xh%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"19"},"+new InstanceRefElement$created:0:0":1}},"+InstanceRefElement": [90],D13:{"":"uL+Pi;",$isd3:true}}],["instance_view_element","package:observatory/src/observatory_elements/instance_view.dart",,Z,{hx:{"":["WZq;Xh%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
ghf:function(a){return a.Xh
-"37,38,39"},
+"38,39,40"},
"+instance":1,
shf:function(a,b){a.Xh=this.pD(a,C.fn,a.Xh,b)
-"40,31,37,38"},
+"41,32,38,39"},
"+instance=":1,
"@":function(){return[C.ql]},
static:{HC:function(a){var z,y,x,w,v
@@ -36680,7 +36762,7 @@
C.yK.ZL(a)
C.yK.FH(a)
return a
-"19"},"+new InstanceViewElement$created:0:0":1}},"+InstanceViewElement": [89],D13:{"":"uL+Pi;",$isd3:true}}],["isolate_list_element","package:observatory/src/observatory_elements/isolate_list.dart",,L,{u7:{"":["uL;tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"20"},"+new InstanceViewElement$created:0:0":1}},"+InstanceViewElement": [91],WZq:{"":"uL+Pi;",$isd3:true}}],["isolate_list_element","package:observatory/src/observatory_elements/isolate_list.dart",,L,{u7:{"":["uL;tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
"@":function(){return[C.jF]},
static:{Tt:function(a){var z,y,x,w,v
z=$.Nd()
@@ -36695,18 +36777,18 @@
C.Dh.ZL(a)
C.Dh.FH(a)
return a
-"20"},"+new IsolateListElement$created:0:0":1}},"+IsolateListElement": [27]}],["isolate_summary_element","package:observatory/src/observatory_elements/isolate_summary.dart",,D,{St:{"":["WZq;Pw%-,i0%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"21"},"+new IsolateListElement$created:0:0":1}},"+IsolateListElement": [28]}],["isolate_summary_element","package:observatory/src/observatory_elements/isolate_summary.dart",,D,{St:{"":["pva;Pw%-,i0%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gF1:function(a){return a.Pw
-"30,38,39"},
+"31,39,40"},
"+isolate":1,
sF1:function(a,b){a.Pw=this.pD(a,C.Y2,a.Pw,b)
-"40,31,30,38"},
+"41,32,31,39"},
"+isolate=":1,
goc:function(a){return a.i0
-"8,38,39"},
+"8,39,40"},
"+name":1,
soc:function(a,b){a.i0=this.pD(a,C.YS,a.i0,b)
-"40,31,8,38"},
+"41,32,8,39"},
"+name=":1,
"@":function(){return[C.aM]},
static:{N5:function(a){var z,y,x,w,v
@@ -36723,19 +36805,19 @@
C.nM.ZL(a)
C.nM.FH(a)
return a
-"21"},"+new IsolateSummaryElement$created:0:0":1}},"+IsolateSummaryElement": [90],WZq:{"":"uL+Pi;",$isd3:true}}],["json_view_element","package:observatory/src/observatory_elements/json_view.dart",,Z,{vj:{"":["pva;eb%-,kf%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"22"},"+new IsolateSummaryElement$created:0:0":1}},"+IsolateSummaryElement": [92],pva:{"":"uL+Pi;",$isd3:true}}],["json_view_element","package:observatory/src/observatory_elements/json_view.dart",,Z,{vj:{"":["cda;eb%-,kf%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gTn:function(a){return a.eb
-"40,38,39"},
+"41,39,40"},
"+json":1,
sTn:function(a,b){a.eb=this.pD(a,C.Gd,a.eb,b)
-"40,31,40,38"},
+"41,32,41,39"},
"+json=":1,
i4:function(a){Z.uL.prototype.i4.call(this,a)
a.kf=0
-"40"},
+"41"},
"+enteredView:0:0":1,
yC:function(a,b){this.pD(a,C.eR,"a","b")
-"40,91,40"},
+"41,93,41"},
"+jsonChanged:1:0":1,
gE8:function(a){return J.AG(a.eb)
"8"},
@@ -36751,24 +36833,24 @@
gFe:function(a){var z=a.kf
a.kf=J.WB(z,1)
return z
-"30"},
+"31"},
"+counter":1,
gqC:function(a){var z,y
z=a.eb
y=J.x(z)
if(typeof z==="object"&&z!==null&&(z.constructor===Array||!!y.$isList))return z
return[]
-"70"},
+"72"},
"+list":1,
gvc:function(a){var z,y
z=a.eb
y=J.RE(z)
if(typeof z==="object"&&z!==null&&!!y.$isL8)return J.qA(y.gvc(z))
return[]
-"70"},
+"72"},
"+keys":1,
r6:function(a,b){return J.UQ(a.eb,b)
-"40,78,8"},
+"41,80,8"},
"+value:1:0":1,
gP:function(a){return new P.C7(this,Z.vj.prototype.r6,a,"r6")},
"@":function(){return[C.HN]},
@@ -36787,12 +36869,12 @@
C.GB.ZL(a)
C.GB.FH(a)
return a
-"22"},"+new JsonViewElement$created:0:0":1}},"+JsonViewElement": [92],pva:{"":"uL+Pi;",$isd3:true}}],["library_view_element","package:observatory/src/observatory_elements/library_view.dart",,M,{CX:{"":["cda;iI%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"23"},"+new JsonViewElement$created:0:0":1}},"+JsonViewElement": [94],cda:{"":"uL+Pi;",$isd3:true}}],["library_view_element","package:observatory/src/observatory_elements/library_view.dart",,M,{CX:{"":["waa;iI%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gtD:function(a){return a.iI
-"37,38,39"},
+"38,39,40"},
"+library":1,
stD:function(a,b){a.iI=this.pD(a,C.EV,a.iI,b)
-"40,31,37,38"},
+"41,32,38,39"},
"+library=":1,
"@":function(){return[C.Oy]},
static:{SP:function(a){var z,y,x,w,v,u
@@ -36811,7 +36893,7 @@
C.MG.ZL(a)
C.MG.FH(a)
return a
-"23"},"+new LibraryViewElement$created:0:0":1}},"+LibraryViewElement": [93],cda:{"":"uL+Pi;",$isd3:true}}],["logging","package:logging/logging.dart",,N,{TJ:{"":"a;oc>,eT>,yz,Cj>,wd,Gs",
+"24"},"+new LibraryViewElement$created:0:0":1}},"+LibraryViewElement": [95],waa:{"":"uL+Pi;",$isd3:true}}],["logging","package:logging/logging.dart",,N,{TJ:{"":"a;oc>,eT>,yz,Cj>,wd,Gs",
gB8:function(){var z,y,x
z=this.eT
y=z==null||J.xC(J.DA(z),"")
@@ -36879,26 +36961,27 @@
giO:function(a){return this.P},
bu:function(a){return this.oc},
$isNg:true,
-static:{"":"bR,tm,EL,X8,IQ,Fn,Eb,AN,JY,bo",}},HV:{"":"a;OR<,G1>,iJ,Fl,O0,kc>,I4<",
+static:{"":"bR,tm,EL,X8,IQ,Fn,Eb,AN,JY,ac",}},HV:{"":"a;OR<,G1>,iJ,Fl,O0,kc>,I4<",
bu:function(a){return"["+this.OR.oc+"] "+this.iJ+": "+this.G1},
static:{"":"xO",}}}],["message_viewer_element","package:observatory/src/observatory_elements/message_viewer.dart",,L,{Nh:{"":["uL;XB%-,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gG1:function(a){return a.XB
-"37,39"},
+"38,40"},
"+message":1,
sG1:function(a,b){a.XB=b
this.pD(a,C.KY,"",this.gQW(a))
this.pD(a,C.wt,[],this.glc(a))
-"40,94,37,39"},
+"41,96,38,40"},
"+message=":1,
gQW:function(a){var z=a.XB
if(z==null||J.UQ(z,"type")==null)return"Error"
+P.JS("Received message of type '"+H.d(J.UQ(a.XB,"type"))+"' :\n"+H.d(a.XB))
return J.UQ(a.XB,"type")
"8"},
"+messageType":1,
glc:function(a){var z=a.XB
if(z==null||J.UQ(z,"members")==null)return[]
return J.UQ(a.XB,"members")
-"95"},
+"97"},
"+members":1,
"@":function(){return[C.c0]},
static:{rJ:function(a){var z,y,x,w,v
@@ -36914,7 +36997,7 @@
C.Wp.ZL(a)
C.Wp.FH(a)
return a
-"24"},"+new MessageViewerElement$created:0:0":1}},"+MessageViewerElement": [27]}],["metadata","../../../../../../../../../dart/dart-sdk/lib/html/html_common/metadata.dart",,B,{fA:{"":"a;Kr,Jt",static:{"":"Xd,en,yS,PZ,xa",}},tz:{"":"a;"},jR:{"":"a;oc>"},PO:{"":"a;"},c5:{"":"a;"}}],["navigation_bar_element","package:observatory/src/observatory_elements/navigation_bar.dart",,Q,{ih:{"":["uL;tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"25"},"+new MessageViewerElement$created:0:0":1}},"+MessageViewerElement": [28]}],["metadata","../../../../../../../../../dart/dart-sdk/lib/html/html_common/metadata.dart",,B,{fA:{"":"a;Kr,Jt",static:{"":"Xd,en,yS,PZ,xa",}},tz:{"":"a;"},jR:{"":"a;oc>"},PO:{"":"a;"},c5:{"":"a;"}}],["navigation_bar_element","package:observatory/src/observatory_elements/navigation_bar.dart",,Q,{ih:{"":["uL;tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
"@":function(){return[C.KG]},
static:{BW:function(a){var z,y,x,w,v
z=$.Nd()
@@ -36929,7 +37012,7 @@
C.Xg.ZL(a)
C.Xg.FH(a)
return a
-"25"},"+new NavigationBarElement$created:0:0":1}},"+NavigationBarElement": [27]}],["observatory","package:observatory/observatory.dart",,L,{mL:{"":["Pi;Z6<-,lw<-,nI<-,VJ,Ai",function(){return[C.mI]},function(){return[C.mI]},function(){return[C.mI]},null,null],
+"26"},"+new NavigationBarElement$created:0:0":1}},"+NavigationBarElement": [28]}],["observatory","package:observatory/observatory.dart",,L,{mL:{"":["Pi;Z6<-,lw<-,nI<-,VJ,Ai",function(){return[C.mI]},function(){return[C.mI]},function(){return[C.mI]},null,null],
Ey:function(){var z,y,x
z=this.Z6
z.sJR(this)
@@ -36963,16 +37046,16 @@
y.US()
return y}}},bv:{"":["Pi;nk,SS,XR<-,VJ,Ai",null,null,function(){return[C.mI]},null,null],
gjO:function(a){return this.nk
-"30,38,43"},
+"31,39,45"},
"+id":1,
sjO:function(a,b){this.nk=F.Wi(this,C.EN,this.nk,b)
-"40,31,30,38"},
+"41,32,31,39"},
"+id=":1,
goc:function(a){return this.SS
-"8,38,43"},
+"8,39,45"},
"+name":1,
soc:function(a,b){this.SS=F.Wi(this,C.YS,this.SS,b)
-"40,31,8,38"},
+"41,32,8,39"},
"+name=":1,
bu:function(a){return H.d(this.nk)+" "+H.d(this.SS)},
$isbv:true},pt:{"":["Pi;JR?,i2<-,VJ,Ai",null,function(){return[C.mI]},null,null],
@@ -37025,16 +37108,16 @@
$is_HB:true,
$is_Dv:true},dZ:{"":"Pi;JR?,IT,Jj,VJ,Ai",
gzd:function(){return this.IT
-"8,38,43"},
+"8,39,45"},
"+currentHash":1,
szd:function(a){this.IT=F.Wi(this,C.h1,this.IT,a)
-"40,31,8,38"},
+"41,32,8,39"},
"+currentHash=":1,
glD:function(){return this.Jj
-"96,38,43"},
+"98,39,45"},
"+currentHashUri":1,
slD:function(a){this.Jj=F.Wi(this,C.tv,this.Jj,a)
-"40,31,96,38"},
+"41,32,98,39"},
"+currentHashUri=":1,
kI:function(){var z,y
z=C.PP.aM(window)
@@ -37076,35 +37159,35 @@
PI:function(a){var z=this.R6()
if(J.xC(z,0))return"#/isolates/"
return"#/isolates/"+H.d(z)+"/"+H.d(a)
-"8,97,8,43"},
+"8,99,8,45"},
"+currentIsolateRelativeLink:1:0":1,
Ao:function(a){var z=this.R6()
if(J.xC(z,0))return"#/isolates/"
return"#/isolates/"+H.d(z)+"/objects/"+H.d(a)
-"8,98,30,43"},
+"8,100,31,45"},
"+currentIsolateObjectLink:1:0":1,
dL:function(a){var z=this.R6()
if(J.xC(z,0))return"#/isolates/"
return"#/isolates/"+H.d(z)+"/classes/"+H.d(a)
-"8,99,30,43"},
+"8,101,31,45"},
"+currentIsolateClassLink:1:0":1,
WW:function(a,b){var z=this.R6()
if(J.xC(z,0))return"#/isolates/"
return this.yX(z,a,b)
-"8,98,30,7,8,43"},
+"8,100,31,7,8,45"},
"+currentIsolateScriptLink:2:0":1,
r4:function(a,b){return"#/isolates/"+H.d(a)+"/"+H.d(b)
-"8,100,30,97,8,43"},
+"8,102,31,99,8,45"},
"+relativeLink:2:0":1,
Dd:function(a,b){return"#/isolates/"+H.d(a)+"/objects/"+H.d(b)
-"8,100,30,98,30,43"},
+"8,102,31,100,31,45"},
"+objectLink:2:0":1,
bD:function(a,b){return"#/isolates/"+H.d(a)+"/classes/"+H.d(b)
-"8,100,30,99,30,43"},
+"8,102,31,101,31,45"},
"+classLink:2:0":1,
yX:function(a,b,c){var z=P.jW(C.kg,c,!0)
return"#/isolates/"+H.d(a)+"/objects/"+H.d(b)+"?type=Script&name="+z
-"8,100,30,98,30,7,8,43"},
+"8,102,31,100,31,7,8,45"},
"+scriptLink:3:0":1,
static:{"":"kx,K3D,qY",}},Qe:{"":"Tp;a",
call$1:function(a){var z=this.a
@@ -37116,16 +37199,16 @@
$is_Dv:true},Nu:{"":"Pi;JR?,e0?",
pG:function(){return this.e0.call$0()},
gEI:function(){return this.oJ
-"8,38,43"},
+"8,39,45"},
"+prefix":1,
sEI:function(a){this.oJ=F.Wi(this,C.qb,this.oJ,a)
-"40,31,8,38"},
+"41,32,8,39"},
"+prefix=":1,
gn2:function(){return this.vm
-"95,38,43"},
+"97,39,45"},
"+responses":1,
sn2:function(a){this.vm=F.Wi(this,C.wH,this.vm,a)
-"40,31,95,38"},
+"41,32,97,39"},
"+responses=":1,
Qn:function(a){var z,y
z=C.lM.kV(a)
@@ -37212,13 +37295,13 @@
J.Ih(W.uV(window.parent),C.lM.KP(y),"*")
return w.MM}},Zw:{"":["Pi;Rd,n7,LA>-,Vg,VJ,Ai",null,null,function(){return[C.mI]},null,null,null],
geV:function(){return this.Vg
-"8,38,43"},
+"8,39,45"},
"+paddedLine":1,
seV:function(a){var z=this.Vg
if(this.gUV(this)&&!J.xC(z,a)){z=new T.qI(this,C.X9,z,a)
z.$builtinTypeInfo=[null]
this.SZ(this,z)}this.Vg=a
-"40,31,8,38"},
+"41,32,8,39"},
"+paddedLine=":1,
QQ:function(a,b,c){var z,y,x,w,v
z=""+this.Rd
@@ -37232,22 +37315,22 @@
z.QQ(a,b,c)
return z}}},Pf:{"":"Pi;WF,uM,ZQ,VJ,Ai",
gfY:function(a){return this.WF
-"8,38,43"},
+"8,39,45"},
"+kind":1,
sfY:function(a,b){this.WF=F.Wi(this,C.fy,this.WF,b)
-"40,31,8,38"},
+"41,32,8,39"},
"+kind=":1,
gO3:function(a){return this.uM
-"8,38,43"},
+"8,39,45"},
"+url":1,
sO3:function(a,b){this.uM=F.Wi(this,C.Fh,this.uM,b)
-"40,31,8,38"},
+"41,32,8,39"},
"+url=":1,
gXJ:function(){return this.ZQ
-"101,38,43"},
+"103,39,45"},
"+lines":1,
sXJ:function(a){this.ZQ=F.Wi(this,C.Cv,this.ZQ,a)
-"40,31,101,38"},
+"41,32,103,39"},
"+lines=":1,
Cn:function(a){var z,y,x,w,v
z=J.uH(a,"\n")
@@ -37267,17 +37350,17 @@
static:{Sp:function(a){var z=R.Jk([])
z=new L.Pf("","",z,null,null)
z.EQ(a)
-return z}}}}],["observatory_application_element","package:observatory/src/observatory_elements/observatory_application.dart",,V,{F1:{"":["waa;k5%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+return z}}}}],["observatory_application_element","package:observatory/src/observatory_elements/observatory_application.dart",,V,{F1:{"":["V0;k5%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gzj:function(a){return a.k5
-"44,38,39"},
+"46,39,40"},
"+devtools":1,
szj:function(a,b){a.k5=this.pD(a,C.Na,a.k5,b)
-"40,31,44,38"},
+"41,32,46,39"},
"+devtools=":1,
ZB:function(a){var z
if(a.k5===!0){z=L.WS()
a.tH=this.pD(a,C.wh,a.tH,z)}else{z=L.AK()
-a.tH=this.pD(a,C.wh,a.tH,z)}"40"},
+a.tH=this.pD(a,C.wh,a.tH,z)}"41"},
"@":function(){return[C.bd]},
static:{fv:function(a){var z,y,x,w,v
z=$.Nd()
@@ -37294,23 +37377,23 @@
C.k0.FH(a)
C.k0.ZB(a)
return a
-"26"},"+new ObservatoryApplicationElement$created:0:0":1}},"+ObservatoryApplicationElement": [102],waa:{"":"uL+Pi;",$isd3:true}}],["observatory_element","package:observatory/src/observatory_elements/observatory_element.dart",,Z,{uL:{"":["Nr;tH%-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"27"},"+new ObservatoryApplicationElement$created:0:0":1}},"+ObservatoryApplicationElement": [104],V0:{"":"uL+Pi;",$isd3:true}}],["observatory_element","package:observatory/src/observatory_elements/observatory_element.dart",,Z,{uL:{"":["Nr;tH%-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
i4:function(a){A.dM.prototype.i4.call(this,a)
-"40"},
+"41"},
"+enteredView:0:0":1,
Nz:function(a){A.dM.prototype.Nz.call(this,a)
-"40"},
+"41"},
"+leftView:0:0":1,
gQG:function(a){return a.tH
-"103,38,39"},
+"105,39,40"},
"+app":1,
sQG:function(a,b){a.tH=this.pD(a,C.wh,a.tH,b)
-"40,31,103,38"},
+"41,32,105,39"},
"+app=":1,
gpQ:function(a){return!0
-"44"},
+"46"},
"+applyAuthorStyles":1,
-"@":function(){return[C.J0]},
+"@":function(){return[C.Br]},
static:{Hx:function(a){var z,y,x,w,v
z=$.Nd()
y=P.Py(null,null,null,J.O,W.I0)
@@ -37324,7 +37407,7 @@
C.mk.ZL(a)
C.mk.FH(a)
return a
-"27"},"+new ObservatoryElement$created:0:0":1}},"+ObservatoryElement": [104],Nr:{"":"ir+Pi;",$isd3:true}}],["observe.src.change_notifier","package:observe/src/change_notifier.dart",,O,{Pi:{"":"a;",
+"28"},"+new ObservatoryElement$created:0:0":1}},"+ObservatoryElement": [106],Nr:{"":"ir+Pi;",$isd3:true}}],["observe.src.change_notifier","package:observe/src/change_notifier.dart",,O,{Pi:{"":"a;",
gqh:function(a){var z,y
if(a.VJ==null){z=this.gqw(a)
a.VJ=P.bK(this.gl1(a),z,!0,null)}z=a.VJ
@@ -37368,7 +37451,7 @@
gB:function(a){return this.b9.length},
"+length":0,
gP:function(a){return this.Sv
-"40,38"},
+"41,39"},
"+value":1,
r6:function(a,b){return this.gP(a).call$1(b)},
wE:function(a){var z,y,x,w
@@ -37693,11 +37776,11 @@
$isEH:true,
$is_bh:true}}],["observe.src.observable_box","package:observe/src/observable_box.dart",,A,{xh:{"":"Pi;",
gP:function(a){return this.L1
-"105,38"},
+"107,39"},
"+value":1,
r6:function(a,b){return this.gP(a).call$1(b)},
sP:function(a,b){this.L1=F.Wi(this,C.ls,this.L1,b)
-"40,106,105,38"},
+"41,108,107,39"},
"+value=":1,
bu:function(a){return"#<"+H.d(new H.cu(H.dJ(this),null))+" value: "+H.d(this.L1)+">"}}}],["observe.src.observable_list","package:observe/src/observable_list.dart",,Q,{wn:{"":"uF;b3,xg,h3,VJ,Ai",
gRT:function(){var z,y
@@ -37708,7 +37791,7 @@
H.VM(y,[H.W8(z,"WV",0)])
return y},
gB:function(a){return this.h3.length
-"30,38"},
+"31,39"},
"+length":1,
sB:function(a,b){var z,y,x,w,v,u,t
z=this.h3
@@ -37737,12 +37820,12 @@
w=new P.Yp(t)
w.$builtinTypeInfo=[null]
this.iH(new G.W4(this,w,t,y,x))}}C.Nm.sB(z,b)
-"40,31,30,38"},
+"41,32,31,39"},
"+length=":1,
t:function(a,b){var z=this.h3
if(b>>>0!==b||b>=z.length)throw H.e(z,b)
return z[b]
-"107,29,30,38"},
+"109,30,31,39"},
"+[]:1:0":1,
u:function(a,b,c){var z,y,x,w
z=this.h3
@@ -37756,7 +37839,7 @@
w.$builtinTypeInfo=[null]
this.iH(new G.W4(this,w,x,b,1))}if(b>=z.length)throw H.e(z,b)
z[b]=c
-"40,29,30,31,107,38"},
+"41,30,31,32,109,39"},
"+[]=:2:0":1,
h:function(a,b){var z,y,x,w
z=this.h3
@@ -37845,33 +37928,33 @@
$isHA:true},br:{"":"Pi;Zp,VJ,Ai",
gvc:function(a){var z=this.Zp
return z.gvc(z)
-"108,38"},
+"110,39"},
"+keys":1,
gUQ:function(a){var z=this.Zp
return z.gUQ(z)
-"109,38"},
+"111,39"},
"+values":1,
gB:function(a){var z=this.Zp
return z.gB(z)
-"30,38"},
+"31,39"},
"+length":1,
gl0:function(a){var z=this.Zp
return z.gB(z)===0
-"44,38"},
+"46,39"},
"+isEmpty":1,
gor:function(a){var z=this.Zp
return z.gB(z)!==0
-"44,38"},
+"46,39"},
"+isNotEmpty":1,
PF:function(a){return this.Zp.PF(a)
-"44,31,0,38"},
+"46,32,0,39"},
"+containsValue:1:0":1,
x4:function(a){return this.Zp.x4(a)
-"44,78,0,38"},
+"46,80,0,39"},
"+containsKey:1:0":1,
t:function(a,b){var z=this.Zp
return z.t(z,b)
-"110,78,0,38"},
+"112,80,0,39"},
"+[]:1:0":1,
u:function(a,b,c){var z,y,x,w,v
z=this.Zp
@@ -37888,7 +37971,7 @@
z.$builtinTypeInfo=[null,null]
this.SZ(this,z)}else if(!J.xC(x,c)){z=new V.HA(b,x,c,!1,!1)
z.$builtinTypeInfo=[null,null]
-this.SZ(this,z)}"40,78,111,31,110,38"},
+this.SZ(this,z)}"41,80,113,32,112,39"},
"+[]=:2:0":1,
Ay:function(a,b){b.aN(b,new V.zT(this))},
Rz:function(a,b){var z,y,x,w,v
@@ -37999,7 +38082,7 @@
z=y==null?z!=null:y!==z}else z=!1
if(!z)this.ov()
return C.Nm.grZ(this.kN)
-"40,38"},
+"41,39"},
"+value":1,
r6:function(a,b){return this.gP(a).call$1(b)},
sP:function(a,b){var z,y,x,w
@@ -38017,7 +38100,7 @@
if(w>=z.length)throw H.e(z,w)
if(L.h6(x,z[w],b)){z=this.kN
if(y>=z.length)throw H.e(z,y)
-z[y]=b}"40,106,0,38"},
+z[y]=b}"41,108,0,39"},
"+value=":1,
w3:function(a){O.Pi.prototype.w3.call(this,this)
this.ov()
@@ -39179,7 +39262,7 @@
y=typeof z==="object"&&z!==null&&!!y.$isEZ}else y=!1}else y=!1
if(y)return
return new T.Xy(this,b,z)},
-gca:function(){return new T.Dw(this,T.e9.prototype.yt,null,"yt")},
+gca:function(){return new T.PD(this,T.e9.prototype.yt,null,"yt")},
A5:function(a){return new T.uK(this)}},Xy:{"":"Tp;a,b,c",
call$2:function(a,b){var z=J.x(a)
if(typeof a!=="object"||a===null||!z.$isz6)a=new K.z6(null,a,V.WF(this.a.nF,null,null),null)
@@ -39206,14 +39289,14 @@
F.Wi(this,C.ls,z,this.uK)},
gnc:function(){return new H.Pm(this,T.mY.prototype.vr,null,"vr")},
gP:function(a){return this.uK
-"40,38"},
+"41,39"},
"+value":1,
r6:function(a,b){return this.gP(a).call$1(b)},
sP:function(a,b){var z,y,x,w
try{K.jX(this.jf,b,this.qc)}catch(y){x=H.Ru(y)
w=J.x(x)
if(typeof x==="object"&&x!==null&&!!w.$isB0){z=x
-$.IS().A3("Error evaluating expression '"+H.d(this.jf)+"': "+J.z2(z))}else throw y}"40,112,40,38"},
+$.IS().A3("Error evaluating expression '"+H.d(this.jf)+"': "+J.z2(z))}else throw y}"41,114,41,39"},
"+value=":1,
Va:function(a,b,c){var z,y,x,w,v
y=this.jf
@@ -39675,7 +39758,7 @@
return 536870911&a+((16383&a)<<15>>>0)},Fq:{"":"a;",
F2:function(a,b,c){return new U.RW(a,b,c)},
"+invoke:3:0":0,
-"*invoke":[40],
+"*invoke":[41],
CI:function(a,b){return this.F2(a,b,null)},
"+invoke:2:0":0},hw:{"":"a;",$ishw:true},EZ:{"":"hw;",
RR:function(a,b){return b.W9(this)},
@@ -39969,7 +40052,7 @@
static:{i0:function(a,b,c){var z=new K.Ae(a,b)
H.VM(z,[c])
return z
-"28,29,30,31,32"},"+new IndexedValue:2:0":1}},"+IndexedValue": [0],Bt:{"":"mW;YR",
+"29,30,31,32,33"},"+new IndexedValue:2:0":1}},"+IndexedValue": [0],Bt:{"":"mW;YR",
gA:function(a){var z=J.GP(this.YR)
z=new K.vR(z,0,null)
H.VM(z,[H.W8(this,"Bt",0)])
@@ -40163,15 +40246,15 @@
C.Cc.ZL(a)
C.Cc.FH(a)
return a
-"33"},"+new ResponseViewerElement$created:0:0":1}},"+ResponseViewerElement": [27]}],["script_view_element","package:observatory/src/observatory_elements/script_view.dart",,U,{fI:{"":["V0;Uz%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"34"},"+new ResponseViewerElement$created:0:0":1}},"+ResponseViewerElement": [28]}],["script_view_element","package:observatory/src/observatory_elements/script_view.dart",,U,{fI:{"":["V4;Uz%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gNl:function(a){return a.Uz
-"37,38,39"},
+"38,39,40"},
"+script":1,
sNl:function(a,b){a.Uz=this.pD(a,C.fX,a.Uz,b)
-"40,31,37,38"},
+"41,32,38,39"},
"+script=":1,
"@":function(){return[C.Er]},
-static:{Ry:function(a){var z,y,x,w,v
+static:{kL:function(a){var z,y,x,w,v
z=$.Nd()
y=P.Py(null,null,null,J.O,W.I0)
x=J.O
@@ -40184,12 +40267,12 @@
C.cJ.ZL(a)
C.cJ.FH(a)
return a
-"34"},"+new ScriptViewElement$created:0:0":1}},"+ScriptViewElement": [113],V0:{"":"uL+Pi;",$isd3:true}}],["source_view_element","package:observatory/src/observatory_elements/source_view.dart",,X,{kK:{"":["V4;vX%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"35"},"+new ScriptViewElement$created:0:0":1}},"+ScriptViewElement": [115],V4:{"":"uL+Pi;",$isd3:true}}],["source_view_element","package:observatory/src/observatory_elements/source_view.dart",,X,{kK:{"":["V6;vX%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gFF:function(a){return a.vX
-"114,38,39"},
+"116,39,40"},
"+source":1,
sFF:function(a,b){a.vX=this.pD(a,C.hn,a.vX,b)
-"40,31,114,38"},
+"41,32,116,39"},
"+source=":1,
"@":function(){return[C.H8]},
static:{HO:function(a){var z,y,x,w,v
@@ -40205,12 +40288,12 @@
C.Ks.ZL(a)
C.Ks.FH(a)
return a
-"35"},"+new SourceViewElement$created:0:0":1}},"+SourceViewElement": [115],V4:{"":"uL+Pi;",$isd3:true}}],["stack_trace_element","package:observatory/src/observatory_elements/stack_trace.dart",,X,{uw:{"":["V6;V4%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
+"36"},"+new SourceViewElement$created:0:0":1}},"+SourceViewElement": [117],V6:{"":"uL+Pi;",$isd3:true}}],["stack_trace_element","package:observatory/src/observatory_elements/stack_trace.dart",,X,{uw:{"":["V8;V4%-,VJ,Ai,tH-,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM-",null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,function(){return[C.nJ]}],
gtN:function(a){return a.V4
-"37,38,39"},
+"38,39,40"},
"+trace":1,
stN:function(a,b){a.V4=this.pD(a,C.kw,a.V4,b)
-"40,31,37,38"},
+"41,32,38,39"},
"+trace=":1,
"@":function(){return[C.js]},
static:{bV:function(a){var z,y,x,w,v,u
@@ -40229,7 +40312,7 @@
C.bg.ZL(a)
C.bg.FH(a)
return a
-"36"},"+new StackTraceElement$created:0:0":1}},"+StackTraceElement": [116],V6:{"":"uL+Pi;",$isd3:true}}],["template_binding","package:template_binding/template_binding.dart",,M,{IP:function(a){var z=J.RE(a)
+"37"},"+new StackTraceElement$created:0:0":1}},"+StackTraceElement": [118],V8:{"":"uL+Pi;",$isd3:true}}],["template_binding","package:template_binding/template_binding.dart",,M,{IP:function(a){var z=J.RE(a)
if(typeof a==="object"&&a!==null&&!!z.$isQl)return C.io.f0(a)
switch(z.gr9(a)){case"checkbox":return $.FF().aM(a)
case"radio":case"select-multiple":case"select-one":return z.gEr(a)
@@ -41309,6 +41392,7 @@
if(typeof a!="object")return a
if(a instanceof P.a)return a
return J.ks(a)}
+C.J0=B.G6.prototype
C.OL=new U.EZ()
C.Gw=new H.SJ()
C.E3=new J.Q()
@@ -41329,7 +41413,7 @@
C.YD=F.Be.prototype
C.j8=R.i6.prototype
C.Vy=new A.V3("disassembly-entry")
-C.J0=new A.V3("observatory-element")
+C.Br=new A.V3("observatory-element")
C.Er=new A.V3("script-view")
C.ht=new A.V3("field-ref")
C.aM=new A.V3("isolate-summary")
@@ -41341,6 +41425,7 @@
C.c0=new A.V3("message-viewer")
C.js=new A.V3("stack-trace")
C.jF=new A.V3("isolate-list")
+C.PT=new A.V3("breakpoint-list")
C.KG=new A.V3("navigation-bar")
C.ay=new A.V3("instance-ref")
C.Gu=new A.V3("collapsible-content")
@@ -41574,6 +41659,7 @@
C.PC=new H.GD("dart.core.int")
C.wt=new H.GD("members")
C.KY=new H.GD("messageType")
+C.Ry=new H.GD("msg")
C.YS=new H.GD("name")
C.OV=new H.GD("noSuchMethod")
C.Ws=new H.GD("operatingSystem")
@@ -41601,14 +41687,15 @@
C.Ti=H.mm('wn')
C.Mt=new H.Lm(C.Ti,"E",0)
C.Ye=H.mm('hx')
-C.G6=H.mm('F1')
+C.bD=H.mm('F1')
C.NM=H.mm('Nh')
+C.z7=H.mm('G6')
C.nY=H.mm('a')
C.Yc=H.mm('iP')
C.LN=H.mm('Be')
C.Qa=H.mm('u7')
C.xS=H.mm('UZ')
-C.PT=H.mm('CX')
+C.mA=H.mm('CX')
C.Op=H.mm('G8')
C.xF=H.mm('NQ')
C.b4=H.mm('ih')
@@ -41813,8 +41900,8 @@
J.z2=function(a){return J.RE(a).gG1(a)}
J.zZ=function(a,b){return J.RE(a).Yv(a,b)}
J.zj=function(a){return J.RE(a).gvH(a)}
-$.Dq=["Ay","BN","BT","Ba","C","C0","C8","Ch","D","D3","D6","Dh","E","Ec","F","FH","Fr","GB","HG","Hn","Id","Ih","Im","Is","J","J3","JP","JT","JV","Ja","Jk","Kb","LV","Md","Mi","Mu","Nj","Nz","O","On","PM","Pa","Pk","Pv","R3","R4","RB","RR","Rz","SZ","T","T2","TH","TP","TW","Tc","Td","U","UD","UH","UZ","Uc","V","V1","Vr","Vy","W","W3","W4","WO","WZ","Wt","Wz","X6","XG","XU","Xl","Y9","YU","YW","Ys","Yv","Z","Z1","Z2","ZB","ZF","ZL","ZP","Zv","aC","aN","aq","bA","bS","br","bu","cO","cn","d0","dR","dd","du","eR","ea","er","es","ev","ez","f6","fd","fj","fk","fm","g","gA","gB","gBb","gCd","gCj","gDD","gDg","gE8","gEX","gEr","gF1","gFF","gFJ","gFT","gFV","gFe","gG0","gG1","gG3","gGL","gHs","gI","gIi","gJS","gJf","gKE","gKM","gKV","gLA","gLU","gLf","gLm","gM0","gMB","gMj","gN","gNI","gNl","gO3","gP","gP1","gP2","gPp","gPu","gPw","gPy","gQ0","gQG","gQW","gQg","gRn","gRu","gT8","gTM","gTn","gTq","gUQ","gUV","gUz","gV4","gVA","gVB","gVl","gXB","gXf","gXh","gXt","gZw","gai","gbP","gbx","gcC","geT","geb","gey","gfY","ghO","ghf","ghr","gi0","giC","giI","giK","giO","gig","gjL","gjO","gjU","gjb","gk5","gkU","gkc","gkf","gkp","gl0","gl7","glc","gmW","gmm","gn4","goc","gor","gpQ","gpo","gq6","gqC","gqh","gql","gr3","gr9","grK","grZ","gt0","gtD","gtH","gtN","gtT","guD","gvH","gvX","gvc","gvt","gxj","gxr","gyT","gys","gzP","gzZ","gzj","h","h8","hV","hc","i","i4","iA","iM","iw","j","jT","jx","kO","l5","l8","lj","m","mK","mv","n","nB","nC","nH","nP","ni","oB","oW","od","oo","oq","pD","pZ","pl","pr","qZ","r6","rJ","rS","sB","sF1","sFF","sFJ","sFT","sG1","sIt","sLA","sLf","sMj","sNI","sNl","sO3","sP","sP2","sPw","sPy","sQG","sRu","sTn","sTq","sUz","sV4","sVA","sVB","sXB","sXf","sXh","sZw","sa4","sai","scC","seb","sfY","shO","shf","si0","siI","siK","sig","sjO","sk5","skc","skf","sl7","soc","sql","sr9","st0","stD","stH","stN","stT","svX","svt","sxj","sxr","szZ","szj","t","tZ","tg","tt","u","u5","u8","uG","vs","w3","wE","wL","wR","wg","x3","xI","xc","xe","y0","yC","yc","ym","yn","yq","yu","yx","yy","z2","zV"]
-$.Au=[C.Ye,Z.hx,{created:Z.HC},C.G6,V.F1,{created:V.fv},C.NM,L.Nh,{created:L.rJ},C.LN,F.Be,{created:F.Fe},C.Qa,L.u7,{created:L.Tt},C.xS,P.UZ,{},C.PT,M.CX,{created:M.SP},C.Op,P.G8,{},C.xF,Q.NQ,{created:Q.Zo},C.b4,Q.ih,{created:Q.BW},C.Ob,X.kK,{created:X.HO},C.hG,A.ir,{created:A.oa},C.aj,U.fI,{created:U.Ry},C.mo,E.Fv,{created:E.AH},C.xE,Z.aC,{created:Z.zg},C.vuj,X.uw,{created:X.bV},C.j6,D.qr,{created:D.ip},C.C6,Z.vj,{created:Z.un},C.CT,D.St,{created:D.N5},C.Q4,Z.uL,{created:Z.Hx},C.yg,F.I3,{created:F.TW},C.XU,R.i6,{created:R.IT},C.Bm,A.XP,{created:A.XL},C.Wz,B.pR,{created:B.lu},C.mnH,N.Ds,{created:N.p7},C.XK,A.Gk,{created:A.cY}]
+$.Dq=["Ay","BN","BT","Ba","C","C0","C8","Ch","D","D3","D6","Dh","E","Ec","F","FH","Fr","GB","HG","Hn","Id","Ih","Im","Is","J","J3","JP","JT","JV","Ja","Jk","Kb","LV","Md","Mi","Mu","Nj","Nz","O","On","PM","Pa","Pk","Pv","R3","R4","RB","RR","Rz","SZ","T","T2","TH","TP","TW","Tc","Td","U","UD","UH","UZ","Uc","V","V1","Vr","Vy","W","W3","W4","WO","WZ","Wt","Wz","X6","XG","XU","Xl","Y9","YU","YW","Ys","Yv","Z","Z1","Z2","ZB","ZF","ZL","ZP","Zv","aC","aN","aq","bA","bS","br","bu","cO","cn","d0","dR","dd","du","eR","ea","er","es","ev","ez","f6","fd","fj","fk","fm","g","gA","gB","gBb","gCd","gCj","gDD","gDg","gE8","gEX","gEr","gF1","gFF","gFJ","gFT","gFV","gFe","gG0","gG1","gG3","gGL","gHs","gI","gIi","gJS","gJf","gKE","gKM","gKV","gLA","gLU","gLf","gLm","gM0","gMB","gMj","gN","gNI","gNl","gO3","gP","gP1","gP2","gPp","gPu","gPw","gPy","gQ0","gQG","gQW","gQg","gRn","gRu","gT8","gTM","gTn","gTq","gUQ","gUV","gUz","gV4","gVA","gVB","gVl","gXB","gXf","gXh","gXt","gZw","gai","gbP","gbx","gcC","geE","geT","geb","gey","gfY","ghO","ghf","ghr","gi0","giC","giI","giK","giO","gig","gjL","gjO","gjU","gjb","gk5","gkU","gkc","gkf","gkp","gl0","gl7","glc","gmW","gmm","gn4","goc","gor","gpQ","gpo","gq6","gqC","gqh","gql","gr3","gr9","grK","grZ","grs","gt0","gtD","gtH","gtN","gtT","guD","gvH","gvX","gvc","gvt","gxj","gxr","gyT","gys","gzP","gzZ","gzj","h","h8","hV","hc","i","i4","iA","iM","iw","j","jT","jx","kO","l5","l8","lj","m","mK","mv","n","nB","nC","nH","nP","ni","oB","oW","od","oo","oq","pD","pZ","pl","pr","qZ","r6","rJ","rS","sB","sF1","sFF","sFJ","sFT","sG1","sIt","sLA","sLf","sMj","sNI","sNl","sO3","sP","sP2","sPw","sPy","sQG","sRu","sTn","sTq","sUz","sV4","sVA","sVB","sXB","sXf","sXh","sZw","sa4","sai","scC","seE","seb","sfY","shO","shf","si0","siI","siK","sig","sjO","sk5","skc","skf","sl7","soc","sql","sr9","srs","st0","stD","stH","stN","stT","svX","svt","sxj","sxr","szZ","szj","t","tZ","tg","tt","u","u5","u8","uG","vs","w3","wE","wL","wR","wg","x3","xI","xc","xe","y0","yC","yc","ym","yn","yq","yu","yx","yy","z2","zV"]
+$.Au=[C.Ye,Z.hx,{created:Z.HC},C.bD,V.F1,{created:V.fv},C.NM,L.Nh,{created:L.rJ},C.z7,B.G6,{created:B.Dw},C.LN,F.Be,{created:F.Fe},C.Qa,L.u7,{created:L.Tt},C.xS,P.UZ,{},C.mA,M.CX,{created:M.SP},C.Op,P.G8,{},C.xF,Q.NQ,{created:Q.Zo},C.b4,Q.ih,{created:Q.BW},C.Ob,X.kK,{created:X.HO},C.hG,A.ir,{created:A.oa},C.aj,U.fI,{created:U.kL},C.mo,E.Fv,{created:E.AH},C.xE,Z.aC,{created:Z.zg},C.vuj,X.uw,{created:X.bV},C.j6,D.qr,{created:D.ip},C.C6,Z.vj,{created:Z.un},C.CT,D.St,{created:D.N5},C.Q4,Z.uL,{created:Z.Hx},C.yg,F.I3,{created:F.TW},C.XU,R.i6,{created:R.IT},C.Bm,A.XP,{created:A.XL},C.Wz,B.pR,{created:B.lu},C.mnH,N.Ds,{created:N.p7},C.XK,A.Gk,{created:A.cY}]
I.$lazy($,"globalThis","DX","jk",function(){return function() { return this; }()})
I.$lazy($,"globalWindow","pG","Qm",function(){return $.jk().window})
I.$lazy($,"globalWorker","zA","Nl",function(){return $.jk().Worker})
@@ -41914,7 +42001,7 @@
return z})
init.functionAliases={}
-init.metadata=[P.a,C.wK,C.wa,C.WX,C.Mt,C.wW,P.uq,"name",J.O,Z.aC,F.Be,R.i6,W.K5,E.Fv,F.I3,D.qr,A.Gk,N.Ds,B.pR,Z.hx,L.u7,D.St,Z.vj,M.CX,L.Nh,Q.ih,V.F1,Z.uL,[K.Ae,3],"index",J.im,"value",3,Q.NQ,U.fI,X.kK,X.uw,P.L8,C.nJ,C.Us,,Z.Vf,F.tu,C.mI,J.kn,"r","e",W.ea,"detail","target",W.KV,R.Vc,[P.L8,P.wv,P.RS],[J.Q,H.Zk],"methodOwner",P.NL,[J.Q,P.RY],"fieldOwner",[P.L8,P.wv,P.RY],[P.L8,P.wv,P.QF],[P.L8,P.wv,P.NL],P.vr,"fieldName",P.wv,"arg",H.Uz,[J.Q,P.vr],P.Ms,"memberName","positionalArguments",J.Q,"namedArguments",[P.L8,P.wv,null],[J.Q,P.Ms],"owner",[J.Q,P.Fw],[J.Q,P.L9u],H.Un,"key",P.QF,H.Tp,"tv","i",E.WZ,F.pv,D.Vfx,A.Dsd,N.tuj,B.Vct,Z.D13,D.WZq,"oldValue",Z.pva,M.cda,"m",[J.Q,P.L8],P.iD,"l","objectId","cid","isolateId",[J.Q,L.Zw],V.waa,L.mL,Z.Nr,5,"newValue",4,[P.cX,1],[P.cX,2],2,1,"v",U.V0,L.Pf,X.V4,X.V6,];$=null
+init.metadata=[P.a,C.wK,C.wa,C.WX,C.Mt,C.wW,P.uq,"name",J.O,B.G6,Z.aC,F.Be,R.i6,W.K5,E.Fv,F.I3,D.qr,A.Gk,N.Ds,B.pR,Z.hx,L.u7,D.St,Z.vj,M.CX,L.Nh,Q.ih,V.F1,Z.uL,[K.Ae,3],"index",J.im,"value",3,Q.NQ,U.fI,X.kK,X.uw,P.L8,C.nJ,C.Us,,B.Vf,Z.tu,F.Vc,C.mI,J.kn,"r","e",W.ea,"detail","target",W.KV,R.WZ,[P.L8,P.wv,P.RS],[J.Q,H.Zk],"methodOwner",P.NL,[J.Q,P.RY],"fieldOwner",[P.L8,P.wv,P.RY],[P.L8,P.wv,P.QF],[P.L8,P.wv,P.NL],P.vr,"fieldName",P.wv,"arg",H.Uz,[J.Q,P.vr],P.Ms,"memberName","positionalArguments",J.Q,"namedArguments",[P.L8,P.wv,null],[J.Q,P.Ms],"owner",[J.Q,P.Fw],[J.Q,P.L9u],H.Un,"key",P.QF,H.Tp,"tv","i",E.pv,F.Vfx,D.Dsd,A.tuj,N.Vct,B.D13,Z.WZq,D.pva,"oldValue",Z.cda,M.waa,"m",[J.Q,P.L8],P.iD,"l","objectId","cid","isolateId",[J.Q,L.Zw],V.V0,L.mL,Z.Nr,5,"newValue",4,[P.cX,1],[P.cX,2],2,1,"v",U.V4,L.Pf,X.V6,X.V8,];$=null
I = I.$finishIsolateConstructor(I)
$=new I()
function convertToFastObject(properties) {
@@ -44215,6 +44302,35 @@
$desc=$collectedClasses.tQ
if($desc instanceof Array)$desc=$desc[1]
tQ.prototype=$desc
+function G6(eE,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.eE=eE
+this.VJ=VJ
+this.Ai=Ai
+this.tH=tH
+this.VJ=VJ
+this.Ai=Ai
+this.VJ=VJ
+this.Ai=Ai
+this.ZI=ZI
+this.uN=uN
+this.z3=z3
+this.TQ=TQ
+this.Vk=Vk
+this.Ye=Ye
+this.mT=mT
+this.KM=KM}G6.builtin$cls="G6"
+if(!"name" in G6)G6.name="G6"
+$desc=$collectedClasses.G6
+if($desc instanceof Array)$desc=$desc[1]
+G6.prototype=$desc
+G6.prototype.geE=function(receiver){return receiver.eE}
+G6.prototype.geE.$reflectable=1
+G6.prototype.seE=function(receiver,v){return receiver.eE=v}
+G6.prototype.seE.$reflectable=1
+function Vf(){}Vf.builtin$cls="Vf"
+if(!"name" in Vf)Vf.name="Vf"
+$desc=$collectedClasses.Vf
+if($desc instanceof Array)$desc=$desc[1]
+Vf.prototype=$desc
function aC(FJ,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.FJ=FJ
this.VJ=VJ
this.Ai=Ai
@@ -44239,11 +44355,11 @@
aC.prototype.gFJ.$reflectable=1
aC.prototype.sFJ=function(receiver,v){return receiver.FJ=v}
aC.prototype.sFJ.$reflectable=1
-function Vf(){}Vf.builtin$cls="Vf"
-if(!"name" in Vf)Vf.name="Vf"
-$desc=$collectedClasses.Vf
+function tu(){}tu.builtin$cls="tu"
+if(!"name" in tu)tu.name="tu"
+$desc=$collectedClasses.tu
if($desc instanceof Array)$desc=$desc[1]
-Vf.prototype=$desc
+tu.prototype=$desc
function Be(Zw,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.Zw=Zw
this.VJ=VJ
this.Ai=Ai
@@ -44268,11 +44384,11 @@
Be.prototype.gZw.$reflectable=1
Be.prototype.sZw=function(receiver,v){return receiver.Zw=v}
Be.prototype.sZw.$reflectable=1
-function tu(){}tu.builtin$cls="tu"
-if(!"name" in tu)tu.name="tu"
-$desc=$collectedClasses.tu
+function Vc(){}Vc.builtin$cls="Vc"
+if(!"name" in Vc)Vc.name="Vc"
+$desc=$collectedClasses.Vc
if($desc instanceof Array)$desc=$desc[1]
-tu.prototype=$desc
+Vc.prototype=$desc
function i6(Xf,VA,P2,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.Xf=Xf
this.VA=VA
this.P2=P2
@@ -44307,11 +44423,11 @@
i6.prototype.gP2.$reflectable=1
i6.prototype.sP2=function(receiver,v){return receiver.P2=v}
i6.prototype.sP2.$reflectable=1
-function Vc(){}Vc.builtin$cls="Vc"
-if(!"name" in Vc)Vc.name="Vc"
-$desc=$collectedClasses.Vc
+function WZ(){}WZ.builtin$cls="WZ"
+if(!"name" in WZ)WZ.name="WZ"
+$desc=$collectedClasses.WZ
if($desc instanceof Array)$desc=$desc[1]
-Vc.prototype=$desc
+WZ.prototype=$desc
function zO(){}zO.builtin$cls="zO"
if(!"name" in zO)zO.name="zO"
$desc=$collectedClasses.zO
@@ -46768,11 +46884,11 @@
Fv.prototype.gFT.$reflectable=1
Fv.prototype.sFT=function(receiver,v){return receiver.FT=v}
Fv.prototype.sFT.$reflectable=1
-function WZ(){}WZ.builtin$cls="WZ"
-if(!"name" in WZ)WZ.name="WZ"
-$desc=$collectedClasses.WZ
+function pv(){}pv.builtin$cls="pv"
+if(!"name" in pv)pv.name="pv"
+$desc=$collectedClasses.pv
if($desc instanceof Array)$desc=$desc[1]
-WZ.prototype=$desc
+pv.prototype=$desc
function I3(Py,hO,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.Py=Py
this.hO=hO
this.VJ=VJ
@@ -46802,11 +46918,11 @@
I3.prototype.ghO.$reflectable=1
I3.prototype.shO=function(receiver,v){return receiver.hO=v}
I3.prototype.shO.$reflectable=1
-function pv(){}pv.builtin$cls="pv"
-if(!"name" in pv)pv.name="pv"
-$desc=$collectedClasses.pv
+function Vfx(){}Vfx.builtin$cls="Vfx"
+if(!"name" in Vfx)Vfx.name="Vfx"
+$desc=$collectedClasses.Vfx
if($desc instanceof Array)$desc=$desc[1]
-pv.prototype=$desc
+Vfx.prototype=$desc
function qr(Lf,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.Lf=Lf
this.VJ=VJ
this.Ai=Ai
@@ -46831,11 +46947,11 @@
qr.prototype.gLf.$reflectable=1
qr.prototype.sLf=function(receiver,v){return receiver.Lf=v}
qr.prototype.sLf.$reflectable=1
-function Vfx(){}Vfx.builtin$cls="Vfx"
-if(!"name" in Vfx)Vfx.name="Vfx"
-$desc=$collectedClasses.Vfx
+function Dsd(){}Dsd.builtin$cls="Dsd"
+if(!"name" in Dsd)Dsd.name="Dsd"
+$desc=$collectedClasses.Dsd
if($desc instanceof Array)$desc=$desc[1]
-Vfx.prototype=$desc
+Dsd.prototype=$desc
function Gk(vt,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.vt=vt
this.VJ=VJ
this.Ai=Ai
@@ -46860,11 +46976,11 @@
Gk.prototype.gvt.$reflectable=1
Gk.prototype.svt=function(receiver,v){return receiver.vt=v}
Gk.prototype.svt.$reflectable=1
-function Dsd(){}Dsd.builtin$cls="Dsd"
-if(!"name" in Dsd)Dsd.name="Dsd"
-$desc=$collectedClasses.Dsd
+function tuj(){}tuj.builtin$cls="tuj"
+if(!"name" in tuj)tuj.name="tuj"
+$desc=$collectedClasses.tuj
if($desc instanceof Array)$desc=$desc[1]
-Dsd.prototype=$desc
+tuj.prototype=$desc
function Ds(ql,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.ql=ql
this.VJ=VJ
this.Ai=Ai
@@ -46889,11 +47005,11 @@
Ds.prototype.gql.$reflectable=1
Ds.prototype.sql=function(receiver,v){return receiver.ql=v}
Ds.prototype.sql.$reflectable=1
-function tuj(){}tuj.builtin$cls="tuj"
-if(!"name" in tuj)tuj.name="tuj"
-$desc=$collectedClasses.tuj
+function Vct(){}Vct.builtin$cls="Vct"
+if(!"name" in Vct)Vct.name="Vct"
+$desc=$collectedClasses.Vct
if($desc instanceof Array)$desc=$desc[1]
-tuj.prototype=$desc
+Vct.prototype=$desc
function aI(b,c){this.b=b
this.c=c}aI.builtin$cls="aI"
if(!"name" in aI)aI.name="aI"
@@ -46986,11 +47102,11 @@
pR.prototype.giK.$reflectable=1
pR.prototype.siK=function(receiver,v){return receiver.iK=v}
pR.prototype.siK.$reflectable=1
-function Vct(){}Vct.builtin$cls="Vct"
-if(!"name" in Vct)Vct.name="Vct"
-$desc=$collectedClasses.Vct
+function D13(){}D13.builtin$cls="D13"
+if(!"name" in D13)D13.name="D13"
+$desc=$collectedClasses.D13
if($desc instanceof Array)$desc=$desc[1]
-Vct.prototype=$desc
+D13.prototype=$desc
function hx(Xh,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.Xh=Xh
this.VJ=VJ
this.Ai=Ai
@@ -47015,11 +47131,11 @@
hx.prototype.gXh.$reflectable=1
hx.prototype.sXh=function(receiver,v){return receiver.Xh=v}
hx.prototype.sXh.$reflectable=1
-function D13(){}D13.builtin$cls="D13"
-if(!"name" in D13)D13.name="D13"
-$desc=$collectedClasses.D13
+function WZq(){}WZq.builtin$cls="WZq"
+if(!"name" in WZq)WZq.name="WZq"
+$desc=$collectedClasses.WZq
if($desc instanceof Array)$desc=$desc[1]
-D13.prototype=$desc
+WZq.prototype=$desc
function u7(tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.tH=tH
this.VJ=VJ
this.Ai=Ai
@@ -47066,11 +47182,11 @@
St.prototype.gi0.$reflectable=1
St.prototype.si0=function(receiver,v){return receiver.i0=v}
St.prototype.si0.$reflectable=1
-function WZq(){}WZq.builtin$cls="WZq"
-if(!"name" in WZq)WZq.name="WZq"
-$desc=$collectedClasses.WZq
+function pva(){}pva.builtin$cls="pva"
+if(!"name" in pva)pva.name="pva"
+$desc=$collectedClasses.pva
if($desc instanceof Array)$desc=$desc[1]
-WZq.prototype=$desc
+pva.prototype=$desc
function vj(eb,kf,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.eb=eb
this.kf=kf
this.VJ=VJ
@@ -47100,11 +47216,11 @@
vj.prototype.gkf.$reflectable=1
vj.prototype.skf=function(receiver,v){return receiver.kf=v}
vj.prototype.skf.$reflectable=1
-function pva(){}pva.builtin$cls="pva"
-if(!"name" in pva)pva.name="pva"
-$desc=$collectedClasses.pva
+function cda(){}cda.builtin$cls="cda"
+if(!"name" in cda)cda.name="cda"
+$desc=$collectedClasses.cda
if($desc instanceof Array)$desc=$desc[1]
-pva.prototype=$desc
+cda.prototype=$desc
function CX(iI,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.iI=iI
this.VJ=VJ
this.Ai=Ai
@@ -47129,11 +47245,11 @@
CX.prototype.giI.$reflectable=1
CX.prototype.siI=function(receiver,v){return receiver.iI=v}
CX.prototype.siI.$reflectable=1
-function cda(){}cda.builtin$cls="cda"
-if(!"name" in cda)cda.name="cda"
-$desc=$collectedClasses.cda
+function waa(){}waa.builtin$cls="waa"
+if(!"name" in waa)waa.name="waa"
+$desc=$collectedClasses.waa
if($desc instanceof Array)$desc=$desc[1]
-cda.prototype=$desc
+waa.prototype=$desc
function TJ(oc,eT,yz,Cj,wd,Gs){this.oc=oc
this.eT=eT
this.yz=yz
@@ -47421,11 +47537,11 @@
F1.prototype.gk5.$reflectable=1
F1.prototype.sk5=function(receiver,v){return receiver.k5=v}
F1.prototype.sk5.$reflectable=1
-function waa(){}waa.builtin$cls="waa"
-if(!"name" in waa)waa.name="waa"
-$desc=$collectedClasses.waa
+function V0(){}V0.builtin$cls="V0"
+if(!"name" in V0)V0.name="V0"
+$desc=$collectedClasses.V0
if($desc instanceof Array)$desc=$desc[1]
-waa.prototype=$desc
+V0.prototype=$desc
function uL(tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.tH=tH
this.VJ=VJ
this.Ai=Ai
@@ -48035,13 +48151,13 @@
$desc=$collectedClasses.e9
if($desc instanceof Array)$desc=$desc[1]
e9.prototype=$desc
-function Dw(wc,nn,lv,Pp){this.wc=wc
+function PD(wc,nn,lv,Pp){this.wc=wc
this.nn=nn
this.lv=lv
-this.Pp=Pp}Dw.builtin$cls="Dw"
-$desc=$collectedClasses.Dw
+this.Pp=Pp}PD.builtin$cls="PD"
+$desc=$collectedClasses.PD
if($desc instanceof Array)$desc=$desc[1]
-Dw.prototype=$desc
+PD.prototype=$desc
function Xy(a,b,c){this.a=a
this.b=b
this.c=c}Xy.builtin$cls="Xy"
@@ -48576,11 +48692,11 @@
fI.prototype.gUz.$reflectable=1
fI.prototype.sUz=function(receiver,v){return receiver.Uz=v}
fI.prototype.sUz.$reflectable=1
-function V0(){}V0.builtin$cls="V0"
-if(!"name" in V0)V0.name="V0"
-$desc=$collectedClasses.V0
+function V4(){}V4.builtin$cls="V4"
+if(!"name" in V4)V4.name="V4"
+$desc=$collectedClasses.V4
if($desc instanceof Array)$desc=$desc[1]
-V0.prototype=$desc
+V4.prototype=$desc
function kK(vX,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.vX=vX
this.VJ=VJ
this.Ai=Ai
@@ -48605,11 +48721,11 @@
kK.prototype.gvX.$reflectable=1
kK.prototype.svX=function(receiver,v){return receiver.vX=v}
kK.prototype.svX.$reflectable=1
-function V4(){}V4.builtin$cls="V4"
-if(!"name" in V4)V4.name="V4"
-$desc=$collectedClasses.V4
+function V6(){}V6.builtin$cls="V6"
+if(!"name" in V6)V6.name="V6"
+$desc=$collectedClasses.V6
if($desc instanceof Array)$desc=$desc[1]
-V4.prototype=$desc
+V6.prototype=$desc
function uw(V4,VJ,Ai,tH,VJ,Ai,VJ,Ai,ZI,uN,z3,TQ,Vk,Ye,mT,KM){this.V4=V4
this.VJ=VJ
this.Ai=Ai
@@ -48634,11 +48750,11 @@
uw.prototype.gV4.$reflectable=1
uw.prototype.sV4=function(receiver,v){return receiver.V4=v}
uw.prototype.sV4.$reflectable=1
-function V6(){}V6.builtin$cls="V6"
-if(!"name" in V6)V6.name="V6"
-$desc=$collectedClasses.V6
+function V8(){}V8.builtin$cls="V8"
+if(!"name" in V8)V8.name="V8"
+$desc=$collectedClasses.V8
if($desc instanceof Array)$desc=$desc[1]
-V6.prototype=$desc
+V8.prototype=$desc
function V2(N1,bn,Ck){this.N1=N1
this.bn=bn
this.Ck=Ck}V2.builtin$cls="V2"
@@ -48976,4 +49092,4 @@
$desc=$collectedClasses.PW
if($desc instanceof Array)$desc=$desc[1]
PW.prototype=$desc
-return[qE,Yy,Ps,rK,fY,Mr,zx,ct,nB,i3,it,Az,QP,QW,n6,Ny,OM,QQ,MA,y4,d7,na,oJ,DG,mN,vH,hh,Em,Sb,rV,Wy,YN,bA,Wq,rv,BK,wj,cv,Fs,SX,ea,D0,as,T5,Aa,u5,Yu,iG,jP,U2,tA,xn,Vb,QH,ST,X2,fJ,Vi,tX,Sg,pA,Mi,Gt,In,Gx,eP,AL,Og,cS,M6,El,zm,SV,aB,ku,KM,cW,DK,qm,ZY,cx,la,Vn,PG,xe,Hw,bn,Im,oB,Aj,oU,qT,KV,BH,mh,G7,wq,Ql,Xp,bP,mX,SN,HD,ni,p3,qj,qW,KR,ew,fs,bX,BL,MC,Mx,j2,yz,lp,pD,I0,QR,Cp,ua,zD,Ul,G0,wb,fq,h4,qk,GI,Tb,tV,BT,yY,kJ,AE,xV,FH,y6,RH,pU,Lq,Mf,BR,r4,aG,J6,K5,UM,UL,rq,nK,kc,ij,ty,Nf,Nc,rj,rh,Zv,Q7,hF,OF,HB,ZJ,mU,eZ,Fl,y5,nV,Zc,ui,D6,DQ,Sm,dx,es,eG,lv,pf,NV,W1,zo,wf,TU,bb,VE,lc,Xu,qM,tk,me,qN,nh,d4,MI,ca,xX,eW,um,Fu,OE,l6,BA,zp,rE,CC,PQ,uz,Yd,U0,AD,Gr,tc,GH,lo,NJ,nd,vt,rQ,EU,LR,MB,hy,r8,aS,CG,qF,MT,Rk,Eo,Dn,UD,ZD,NE,wD,BD,vRT,Fi,Qr,mj,cB,uY,yR,AX,xJ,l4,Et,NC,nb,By,xt,tG,P0,Jq,Xr,qD,Cf,I2,AS,Kq,oI,mJ,rF,vi,ZX,ycx,nE,zt,F0,Lt,Gv,kn,PE,QI,FP,is,Q,jx,ZC,Jt,P,im,Pp,O,PK,JO,O2,aX,cC,RA,IY,JH,jl,Iy,JM,Ua,JG,ns,wd,TA,YP,yc,I9,Bj,NO,II,aJ,X1,HU,Pm,oo,OW,Dd,AP,yH,FA,Av,oH,LP,c2,WT,p8,XR,LI,A2,F3,u8,Gi,t2,Zr,ZQ,az,vV,Hk,XO,dr,TL,KX,uZ,OQ,Tp,v,Z3,D2,GT,Pe,Eq,cu,Lm,dC,wN,VX,VR,EK,KW,Pb,tQ,aC,Vf,Be,tu,i6,Vc,zO,aL,nH,a7,i1,xy,MH,A8,U5,SO,zs,rR,AM,d5,U1,SJ,SU,Tv,XC,iK,GD,Sn,nI,jU,Lj,mb,am,cw,EE,Uz,uh,Kv,oP,YX,BI,y1,M2,iu,mg,zE,bl,Ef,Oo,Tc,Ax,Wf,Un,Ei,U7,t0,Ld,Sz,Zk,fu,ng,Ar,jB,ye,Gj,Zz,Xh,Ca,Ik,JI,Ip,WV,C7,CQ,dz,tK,OR,Bg,DL,b8,j7,oV,TP,Zf,vs,da,xw,dm,rH,ZL,mi,jb,wB,Pu,qh,QC,Yl,Rv,YJ,jv,LB,DO,lz,Rl,Jb,M4,Jp,h7,pr,eN,B5,PI,j4,i9,VV,Dy,lU,xp,UH,Z5,ii,ib,MO,ms,UO,Bc,vp,lk,Gh,XB,ly,cK,O9,yU,nP,KA,Vo,qB,ez,lx,LV,DS,dp,B3,CR,ny,dR,uR,QX,YR,fB,bq,nO,t3,dq,dX,aY,wJ,e4,JB,Id,fZ,TF,Xz,Cg,Hs,uo,pK,eM,Ue,W5,R8,k6,oi,ce,o2,jG,fG,EQ,YB,iX,ou,S9,ey,xd,v6,db,Cm,N6,jg,YO,oz,b6,ef,zQ,Yp,u3,mW,ar,lD,W0,Sw,o0,a1,jp,Xt,Ba,An,LD,YI,OG,ro,DN,ZM,HW,JC,f1,Uk,wI,ob,Ud,K8,by,dI,QM,Sh,tF,z0,Vx,Rw,GY,jZ,h0,CL,uA,a2,fR,iP,MF,Rq,Hn,Zl,pl,a6,P7,DW,Ge,LK,AT,bJ,mp,ub,ds,lj,UV,VS,t7,HG,aE,kM,EH,cX,eL,L8,c8,a,Od,mE,WU,Rn,wv,uq,iD,hb,XX,Kd,yZ,Gs,pm,Tw,wm,FB,Lk,XZ,qz,hQ,Nw,kZ,JT,d9,rI,dD,QZ,BV,E1,wz,B1,M5,Jn,DM,zL,ec,Kx,iO,bU,e7,nj,rl,RAp,ma,cf,E9,nF,FK,Si,vf,Fc,hD,I4,e0,RO,eu,ie,Ea,pu,i2,b0,Ov,qO,RX,kG,Gm,W9,vZ,dW,PA,H2,O7,HI,E4,r7,Tz,Wk,DV,Hp,Nz,Jd,QS,QF,NL,vr,D4,L9u,Ms,Fw,RS,RY,Ys,vg,xG,Vj,VW,RK,DH,ZK,Th,Vju,KB,RKu,xGn,TkQ,VWk,ZKG,DHb,w6W,Hna,z9g,G8,UZ,Fv,WZ,I3,pv,qr,Vfx,Gk,Dsd,Ds,tuj,aI,rG,yh,wO,Tm,rz,CA,YL,KC,xL,As,GE,pR,Vct,hx,D13,u7,St,WZq,vj,pva,CX,cda,TJ,dG,Ng,HV,Nh,fA,tz,jR,PO,c5,ih,mL,bv,pt,Zd,dY,vY,dS,ZW,dZ,Qe,Nu,pF,Ha,nu,be,Pg,jI,Rb,Zw,Pf,F1,waa,uL,Nr,Pi,yj,qI,J3,E5,o5,b5,zI,Zb,id,iV,W4,Fa,x9,d3,X6,xh,wn,uF,cj,HA,br,zT,D7,qL,C4,l9,lP,km,Qt,Dk,A0,rm,eY,OO,BE,Qb,xI,q1,Zj,XP,q6,CK,BO,ZG,Oc,MX,w12,fTP,yL,dM,Y7,WC,Xi,TV,Mq,Oa,n1,xf,L6,Rs,uJ,hm,Ji,Bf,ir,Sa,GN,k8,HJ,S0,V3,Bl,pM,Mh,Md,Lf,fT,pp,Nq,nl,mf,ej,HK,w13,o8,GL,e9,Dw,Xy,uK,mY,fE,mB,XF,iH,wJY,zOQ,W6o,MdQ,YJG,DOe,lPa,Ufa,Raa,w0,w4,w5,w7,w9,w10,w11,c4,z6,Ay,Ed,G1,Os,Dl,Wh,x5,ev,ID,jV,ek,OC,Xm,Jy,ky,fa,WW,vQ,a9,jh,e3,VA,J1,fk,wL,B0,Fq,hw,EZ,no,kB,ae,Iq,w6,jK,uk,K9,RW,xs,FX,Ae,Bt,vR,Pn,hc,hA,fr,a0,NQ,fI,V0,kK,V4,uw,V6,V2,D8,jY,ll,Uf,ik,LfS,NP,Vh,r0,jz,SA,zV,nv,ee,XI,hs,yp,ug,DT,OB,Ra,N9,NW,HS,TG,ts,Kj,VU,Ya,XT,ic,VT,T4,TR,VD,Oh,zy,Nb,Fy,eU,ADW,Ri,kq,Ag,PW]}
\ No newline at end of file
+return[qE,Yy,Ps,rK,fY,Mr,zx,ct,nB,i3,it,Az,QP,QW,n6,Ny,OM,QQ,MA,y4,d7,na,oJ,DG,mN,vH,hh,Em,Sb,rV,Wy,YN,bA,Wq,rv,BK,wj,cv,Fs,SX,ea,D0,as,T5,Aa,u5,Yu,iG,jP,U2,tA,xn,Vb,QH,ST,X2,fJ,Vi,tX,Sg,pA,Mi,Gt,In,Gx,eP,AL,Og,cS,M6,El,zm,SV,aB,ku,KM,cW,DK,qm,ZY,cx,la,Vn,PG,xe,Hw,bn,Im,oB,Aj,oU,qT,KV,BH,mh,G7,wq,Ql,Xp,bP,mX,SN,HD,ni,p3,qj,qW,KR,ew,fs,bX,BL,MC,Mx,j2,yz,lp,pD,I0,QR,Cp,ua,zD,Ul,G0,wb,fq,h4,qk,GI,Tb,tV,BT,yY,kJ,AE,xV,FH,y6,RH,pU,Lq,Mf,BR,r4,aG,J6,K5,UM,UL,rq,nK,kc,ij,ty,Nf,Nc,rj,rh,Zv,Q7,hF,OF,HB,ZJ,mU,eZ,Fl,y5,nV,Zc,ui,D6,DQ,Sm,dx,es,eG,lv,pf,NV,W1,zo,wf,TU,bb,VE,lc,Xu,qM,tk,me,qN,nh,d4,MI,ca,xX,eW,um,Fu,OE,l6,BA,zp,rE,CC,PQ,uz,Yd,U0,AD,Gr,tc,GH,lo,NJ,nd,vt,rQ,EU,LR,MB,hy,r8,aS,CG,qF,MT,Rk,Eo,Dn,UD,ZD,NE,wD,BD,vRT,Fi,Qr,mj,cB,uY,yR,AX,xJ,l4,Et,NC,nb,By,xt,tG,P0,Jq,Xr,qD,Cf,I2,AS,Kq,oI,mJ,rF,vi,ZX,ycx,nE,zt,F0,Lt,Gv,kn,PE,QI,FP,is,Q,jx,ZC,Jt,P,im,Pp,O,PK,JO,O2,aX,cC,RA,IY,JH,jl,Iy,JM,Ua,JG,ns,wd,TA,YP,yc,I9,Bj,NO,II,aJ,X1,HU,Pm,oo,OW,Dd,AP,yH,FA,Av,oH,LP,c2,WT,p8,XR,LI,A2,F3,u8,Gi,t2,Zr,ZQ,az,vV,Hk,XO,dr,TL,KX,uZ,OQ,Tp,v,Z3,D2,GT,Pe,Eq,cu,Lm,dC,wN,VX,VR,EK,KW,Pb,tQ,G6,Vf,aC,tu,Be,Vc,i6,WZ,zO,aL,nH,a7,i1,xy,MH,A8,U5,SO,zs,rR,AM,d5,U1,SJ,SU,Tv,XC,iK,GD,Sn,nI,jU,Lj,mb,am,cw,EE,Uz,uh,Kv,oP,YX,BI,y1,M2,iu,mg,zE,bl,Ef,Oo,Tc,Ax,Wf,Un,Ei,U7,t0,Ld,Sz,Zk,fu,ng,Ar,jB,ye,Gj,Zz,Xh,Ca,Ik,JI,Ip,WV,C7,CQ,dz,tK,OR,Bg,DL,b8,j7,oV,TP,Zf,vs,da,xw,dm,rH,ZL,mi,jb,wB,Pu,qh,QC,Yl,Rv,YJ,jv,LB,DO,lz,Rl,Jb,M4,Jp,h7,pr,eN,B5,PI,j4,i9,VV,Dy,lU,xp,UH,Z5,ii,ib,MO,ms,UO,Bc,vp,lk,Gh,XB,ly,cK,O9,yU,nP,KA,Vo,qB,ez,lx,LV,DS,dp,B3,CR,ny,dR,uR,QX,YR,fB,bq,nO,t3,dq,dX,aY,wJ,e4,JB,Id,fZ,TF,Xz,Cg,Hs,uo,pK,eM,Ue,W5,R8,k6,oi,ce,o2,jG,fG,EQ,YB,iX,ou,S9,ey,xd,v6,db,Cm,N6,jg,YO,oz,b6,ef,zQ,Yp,u3,mW,ar,lD,W0,Sw,o0,a1,jp,Xt,Ba,An,LD,YI,OG,ro,DN,ZM,HW,JC,f1,Uk,wI,ob,Ud,K8,by,dI,QM,Sh,tF,z0,Vx,Rw,GY,jZ,h0,CL,uA,a2,fR,iP,MF,Rq,Hn,Zl,pl,a6,P7,DW,Ge,LK,AT,bJ,mp,ub,ds,lj,UV,VS,t7,HG,aE,kM,EH,cX,eL,L8,c8,a,Od,mE,WU,Rn,wv,uq,iD,hb,XX,Kd,yZ,Gs,pm,Tw,wm,FB,Lk,XZ,qz,hQ,Nw,kZ,JT,d9,rI,dD,QZ,BV,E1,wz,B1,M5,Jn,DM,zL,ec,Kx,iO,bU,e7,nj,rl,RAp,ma,cf,E9,nF,FK,Si,vf,Fc,hD,I4,e0,RO,eu,ie,Ea,pu,i2,b0,Ov,qO,RX,kG,Gm,W9,vZ,dW,PA,H2,O7,HI,E4,r7,Tz,Wk,DV,Hp,Nz,Jd,QS,QF,NL,vr,D4,L9u,Ms,Fw,RS,RY,Ys,vg,xG,Vj,VW,RK,DH,ZK,Th,Vju,KB,RKu,xGn,TkQ,VWk,ZKG,DHb,w6W,Hna,z9g,G8,UZ,Fv,pv,I3,Vfx,qr,Dsd,Gk,tuj,Ds,Vct,aI,rG,yh,wO,Tm,rz,CA,YL,KC,xL,As,GE,pR,D13,hx,WZq,u7,St,pva,vj,cda,CX,waa,TJ,dG,Ng,HV,Nh,fA,tz,jR,PO,c5,ih,mL,bv,pt,Zd,dY,vY,dS,ZW,dZ,Qe,Nu,pF,Ha,nu,be,Pg,jI,Rb,Zw,Pf,F1,V0,uL,Nr,Pi,yj,qI,J3,E5,o5,b5,zI,Zb,id,iV,W4,Fa,x9,d3,X6,xh,wn,uF,cj,HA,br,zT,D7,qL,C4,l9,lP,km,Qt,Dk,A0,rm,eY,OO,BE,Qb,xI,q1,Zj,XP,q6,CK,BO,ZG,Oc,MX,w12,fTP,yL,dM,Y7,WC,Xi,TV,Mq,Oa,n1,xf,L6,Rs,uJ,hm,Ji,Bf,ir,Sa,GN,k8,HJ,S0,V3,Bl,pM,Mh,Md,Lf,fT,pp,Nq,nl,mf,ej,HK,w13,o8,GL,e9,PD,Xy,uK,mY,fE,mB,XF,iH,wJY,zOQ,W6o,MdQ,YJG,DOe,lPa,Ufa,Raa,w0,w4,w5,w7,w9,w10,w11,c4,z6,Ay,Ed,G1,Os,Dl,Wh,x5,ev,ID,jV,ek,OC,Xm,Jy,ky,fa,WW,vQ,a9,jh,e3,VA,J1,fk,wL,B0,Fq,hw,EZ,no,kB,ae,Iq,w6,jK,uk,K9,RW,xs,FX,Ae,Bt,vR,Pn,hc,hA,fr,a0,NQ,fI,V4,kK,V6,uw,V8,V2,D8,jY,ll,Uf,ik,LfS,NP,Vh,r0,jz,SA,zV,nv,ee,XI,hs,yp,ug,DT,OB,Ra,N9,NW,HS,TG,ts,Kj,VU,Ya,XT,ic,VT,T4,TR,VD,Oh,zy,Nb,Fy,eU,ADW,Ri,kq,Ag,PW]}
\ No newline at end of file
diff --git a/runtime/bin/vmservice/client/lib/observatory_elements.dart b/runtime/bin/vmservice/client/lib/observatory_elements.dart
index 0f50949..c483042 100644
--- a/runtime/bin/vmservice/client/lib/observatory_elements.dart
+++ b/runtime/bin/vmservice/client/lib/observatory_elements.dart
@@ -1,6 +1,7 @@
library observatory_elements;
// Export elements.
+export 'package:observatory/src/observatory_elements/breakpoint_list.dart';
export 'package:observatory/src/observatory_elements/class_view.dart';
export 'package:observatory/src/observatory_elements/code_view.dart';
export 'package:observatory/src/observatory_elements/collapsible_content.dart';
diff --git a/runtime/bin/vmservice/client/lib/observatory_elements.html b/runtime/bin/vmservice/client/lib/observatory_elements.html
index ae96d66..0342b45 100644
--- a/runtime/bin/vmservice/client/lib/observatory_elements.html
+++ b/runtime/bin/vmservice/client/lib/observatory_elements.html
@@ -1,6 +1,7 @@
<!DOCTYPE html>
<html>
<head>
+ <link rel="import" href="src/observatory_elements/breakpoint_list.html">
<link rel="import" href="src/observatory_elements/class_view.html">
<link rel="import" href="src/observatory_elements/code_view.html">
<link rel="import" href="src/observatory_elements/collapsible_content.html">
diff --git a/runtime/bin/vmservice/client/lib/src/observatory_elements/breakpoint_list.dart b/runtime/bin/vmservice/client/lib/src/observatory_elements/breakpoint_list.dart
new file mode 100644
index 0000000..deab7a2
--- /dev/null
+++ b/runtime/bin/vmservice/client/lib/src/observatory_elements/breakpoint_list.dart
@@ -0,0 +1,15 @@
+// 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 breakpoint_list_element;
+
+import 'observatory_element.dart';
+import 'package:polymer/polymer.dart';
+
+@CustomTag('breakpoint-list')
+class BreakpointListElement extends ObservatoryElement {
+ @published Map msg = toObservable({});
+
+ BreakpointListElement.created() : super.created();
+}
\ No newline at end of file
diff --git a/runtime/bin/vmservice/client/lib/src/observatory_elements/breakpoint_list.html b/runtime/bin/vmservice/client/lib/src/observatory_elements/breakpoint_list.html
new file mode 100644
index 0000000..8496dd2
--- /dev/null
+++ b/runtime/bin/vmservice/client/lib/src/observatory_elements/breakpoint_list.html
@@ -0,0 +1,22 @@
+<head>
+ <link rel="import" href="observatory_element.html">
+</head>
+<polymer-element name="breakpoint-list" extends="observatory-element">
+ <template>
+ <template if="{{ msg['breakpoints'].isEmpty }}">
+ <div class="panel panel-warning">
+ <div class="panel-body">No breakpoints</div>
+ </div>
+ </template>
+ <template if="{{ msg['breakpoints'].isNotEmpty }}">
+ <ul class="list-group">
+ <template repeat="{{ bpt in msg['breakpoints'] }}">
+ <li class="list-group-item">
+ {{ bpt }}
+ </li>
+ </template>
+ </ul>
+ </template>
+ </template>
+ <script type="application/dart" src="breakpoint_list.dart"></script>
+</polymer-element>
\ No newline at end of file
diff --git a/runtime/bin/vmservice/client/lib/src/observatory_elements/isolate_summary.html b/runtime/bin/vmservice/client/lib/src/observatory_elements/isolate_summary.html
index 10b6a0d..dc54b34 100644
--- a/runtime/bin/vmservice/client/lib/src/observatory_elements/isolate_summary.html
+++ b/runtime/bin/vmservice/client/lib/src/observatory_elements/isolate_summary.html
@@ -18,6 +18,9 @@
<div class="col-md-1">
<a href="{{ app.locationManager.relativeLink(isolate, 'library') }}">Library</a>
</div>
+ <div class="col-md-1">
+ <a href="{{ app.locationManager.relativeLink(isolate, 'debug/breakpoints') }}">Breakpoints</a>
+ </div>
<div class="col-md-8"></div>
</div>
</template>
diff --git a/runtime/bin/vmservice/client/lib/src/observatory_elements/message_viewer.dart b/runtime/bin/vmservice/client/lib/src/observatory_elements/message_viewer.dart
index 10342aa..641d11f 100644
--- a/runtime/bin/vmservice/client/lib/src/observatory_elements/message_viewer.dart
+++ b/runtime/bin/vmservice/client/lib/src/observatory_elements/message_viewer.dart
@@ -24,6 +24,7 @@
if (message == null || message['type'] == null) {
return 'Error';
}
+ print("Received message of type '${message['type']}' :\n$message");
return message['type'];
}
diff --git a/runtime/bin/vmservice/client/lib/src/observatory_elements/message_viewer.html b/runtime/bin/vmservice/client/lib/src/observatory_elements/message_viewer.html
index 3bd2aff..f66a3fa 100644
--- a/runtime/bin/vmservice/client/lib/src/observatory_elements/message_viewer.html
+++ b/runtime/bin/vmservice/client/lib/src/observatory_elements/message_viewer.html
@@ -1,4 +1,5 @@
<head>
+ <link rel="import" href="breakpoint_list.html">
<link rel="import" href="class_view.html">
<link rel="import" href="code_view.html">
<link rel="import" href="error_view.html">
@@ -26,6 +27,9 @@
<template if="{{ messageType == 'StackTrace' }}">
<stack-trace app="{{ app }}" trace="{{ message }}"></stack-trace>
</template>
+ <template if="{{ messageType == 'BreakpointList' }}">
+ <breakpoint-list app="{{ app }}" msg="{{ message }}"></breakpoint-list>
+ </template>
<!-- If the message type is a RequestError -->
<template if="{{ messageType == 'RequestError' }}">
<error-view app="{{ app }}" error="{{ message['error'] }}"></error-view>
diff --git a/runtime/bin/vmservice/message.dart b/runtime/bin/vmservice/message.dart
new file mode 100644
index 0000000..9dce2a1
--- /dev/null
+++ b/runtime/bin/vmservice/message.dart
@@ -0,0 +1,82 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of vmservice;
+
+class Message {
+ final Completer _completer = new Completer.sync();
+ bool get completed => _completer.isCompleted;
+ /// Future of response.
+ Future<String> get response => _completer.future;
+ /// Path.
+ final List<String> path = new List<String>();
+ /// Options.
+ final Map<String, String> options = new Map<String, String>();
+
+ void _setPath(List<String> pathSegments) {
+ if (pathSegments == null) {
+ return;
+ }
+ pathSegments.forEach((String segment) {
+ if (segment == null || segment == '') {
+ return;
+ }
+ path.add(segment);
+ });
+ }
+
+ Message.fromUri(Uri uri) {
+ var split = uri.path.split('/');
+ if (split.length == 0) {
+ setErrorResponse('Invalid uri: $uri.');
+ return;
+ }
+ _setPath(split);
+ options.addAll(uri.queryParameters);
+ }
+
+ Message.fromMap(Map map) {
+ _setPath(map['path']);
+ if (map['options'] != null) {
+ options.addAll(map['options']);
+ }
+ }
+
+ dynamic toJson() {
+ return {
+ 'path': path,
+ 'options': options
+ };
+ }
+
+ Future<String> send(SendPort sendPort) {
+ final receivePort = new RawReceivePort();
+ receivePort.handler = (value) {
+ receivePort.close();
+ if (value is Exception) {
+ _completer.completeError(value);
+ } else {
+ _completer.complete(value);
+ }
+ };
+ var keys = options.keys.toList();
+ var values = options.values.toList();
+ var request = [receivePort.sendPort, path, keys, values];
+ sendServiceMessage(sendPort, request);
+ return _completer.future;
+ }
+
+ void setResponse(String response) {
+ _completer.complete(response);
+ }
+
+ void setErrorResponse(String error) {
+ _completer.complete(JSON.encode({
+ 'type': 'Error',
+ 'msg': error,
+ 'path': path,
+ 'options': options
+ }));
+ }
+}
diff --git a/runtime/bin/vmservice/service_request_router.dart b/runtime/bin/vmservice/message_router.dart
similarity index 75%
rename from runtime/bin/vmservice/service_request_router.dart
rename to runtime/bin/vmservice/message_router.dart
index c889c85..6f8a1ea 100644
--- a/runtime/bin/vmservice/service_request_router.dart
+++ b/runtime/bin/vmservice/message_router.dart
@@ -4,6 +4,6 @@
part of vmservice;
-abstract class ServiceRequestRouter {
- Future route(ServiceRequest request);
+abstract class MessageRouter {
+ Future<String> route(Message message);
}
diff --git a/runtime/bin/vmservice/running_isolate.dart b/runtime/bin/vmservice/running_isolate.dart
index cf726c8..3dd4839 100644
--- a/runtime/bin/vmservice/running_isolate.dart
+++ b/runtime/bin/vmservice/running_isolate.dart
@@ -4,34 +4,15 @@
part of vmservice;
-class RunningIsolate implements ServiceRequestRouter {
+class RunningIsolate implements MessageRouter {
final int portId;
final SendPort sendPort;
final String name;
RunningIsolate(this.portId, this.sendPort, this.name);
- Future sendMessage(List request) {
- final completer = new Completer.sync();
- final receivePort = new RawReceivePort();
- sendServiceMessage(sendPort, receivePort, request);
- receivePort.handler = (value) {
- receivePort.close();
- if (value is Exception) {
- completer.completeError(value);
- } else {
- completer.complete(value);
- }
- };
- return completer.future;
- }
-
- Future route(ServiceRequest request) {
+ Future<String> route(Message message) {
// Send message to isolate.
- var message = request.toServiceCallMessage();
- return sendMessage(message).then((response) {
- request.setResponse(response);
- return new Future.value(request);
- });
+ return message.send(sendPort);
}
}
diff --git a/runtime/bin/vmservice/running_isolates.dart b/runtime/bin/vmservice/running_isolates.dart
index 547b9b5..36a0c484 100644
--- a/runtime/bin/vmservice/running_isolates.dart
+++ b/runtime/bin/vmservice/running_isolates.dart
@@ -4,7 +4,7 @@
part of vmservice;
-class RunningIsolates implements ServiceRequestRouter {
+class RunningIsolates implements MessageRouter {
final Map<int, RunningIsolate> isolates = new Map<int, RunningIsolate>();
RunningIsolates();
@@ -24,7 +24,7 @@
isolates.remove(portId);
}
- void _isolateCollectionRequest(ServiceRequest request) {
+ void _isolateCollectionRequest(Message message) {
var members = [];
var result = {};
isolates.forEach((portId, runningIsolate) {
@@ -35,42 +35,42 @@
});
result['type'] = 'IsolateList';
result['members'] = members;
- request.setResponse(JSON.encode(result));
+ message.setResponse(JSON.encode(result));
}
- Future route(ServiceRequest request) {
- if (request.pathSegments.length == 0) {
- request.setErrorResponse('No path.');
- return new Future.value(request);
+ Future<String> route(Message message) {
+ if (message.path.length == 0) {
+ message.setErrorResponse('No path.');
+ return message.response;
}
- if (request.pathSegments[0] != 'isolates') {
- request.setErrorResponse('Path must begin with /isolates/.');
- return new Future.value(request);
+ if (message.path[0] != 'isolates') {
+ message.setErrorResponse('Path must begin with /isolates/.');
+ return message.response;
}
- if (request.pathSegments.length == 1) {
+ if (message.path.length == 1) {
// Requesting list of running isolates.
- _isolateCollectionRequest(request);
- return new Future.value(request);
+ _isolateCollectionRequest(message);
+ return message.response;
}
var isolateId;
try {
- isolateId = int.parse(request.pathSegments[1]);
+ isolateId = int.parse(message.path[1]);
} catch (e) {
- request.setErrorResponse('Could not parse isolate id: $e');
- return new Future.value(request);
+ message.setErrorResponse('Could not parse isolate id: $e');
+ return message.response;
}
var isolate = isolates[isolateId];
if (isolate == null) {
- request.setErrorResponse('Cannot find isolate id: $isolateId');
- return new Future.value(request);
+ message.setErrorResponse('Cannot find isolate id: $isolateId');
+ return message.response;
}
// Consume '/isolates/isolateId'
- request.pathSegments.removeRange(0, 2);
- if (request.pathSegments.length == 0) {
- // The request is now empty.
- request.setErrorResponse('No request for isolate: /isolates/$isolateId');
- return new Future.value(request);
+ message.path.removeRange(0, 2);
+ if (message.path.length == 0) {
+ // The message now has an empty path.
+ message.setErrorResponse('Empty path for isolate: /isolates/$isolateId');
+ return message.response;
}
- return isolate.route(request);
+ return isolate.route(message);
}
}
diff --git a/runtime/bin/vmservice/server.dart b/runtime/bin/vmservice/server.dart
index 19490a1..6467b7d 100644
--- a/runtime/bin/vmservice/server.dart
+++ b/runtime/bin/vmservice/server.dart
@@ -4,26 +4,95 @@
part of vmservice_io;
-class Server {
- int port;
+class WebSocketClient extends Client {
+ static const int PARSE_ERROR_CODE = 4000;
+ static const int BINARY_MESSAGE_ERROR_CODE = 4001;
+ static const int NOT_MAP_ERROR_CODE = 4002;
+ final WebSocket socket;
+
+ WebSocketClient(this.socket, service) : super(service) {
+ socket.listen((message) => onWebSocketMessage(message));
+ socket.done.then((_) => close());
+ }
+
+ void onWebSocketMessage(message) {
+ if (message is String) {
+ var map;
+ try {
+ map = JSON.decode(message);
+ } catch (e) {
+ socket.close(PARSE_ERROR_CODE, 'Message parse error: $e');
+ return;
+ }
+ if (map is! Map) {
+ socket.close(NOT_MAP_ERROR_CODE, 'Message must be a JSON map.');
+ return;
+ }
+ var seq = map['seq'];
+ onMessage(seq, new Message.fromMap(map));
+ } else {
+ socket.close(BINARY_MESSAGE_ERROR_CODE, 'message must be a string.');
+ }
+ }
+
+ void post(var seq, String response) {
+ try {
+ Map map = {
+ 'seq': seq,
+ 'response': response
+ };
+ socket.add(JSON.encode(map));
+ } catch (_) {
+ // Error posting over WebSocket.
+ }
+ }
+
+ dynamic toJson() {
+ Map map = super.toJson();
+ map['type'] = 'WebSocketClient';
+ map['socket'] = '$socket';
+ return map;
+ }
+}
+
+
+class HttpRequestClient extends Client {
static ContentType jsonContentType = ContentType.parse('application/json');
- final VmService service;
- HttpServer _server;
+ final HttpRequest request;
- Server(this.service, this.port);
+ HttpRequestClient(this.request, service) : super(service);
- void _sendResponse(HttpRequest request, String response) {
+ void post(var seq, String response) {
request.response..headers.contentType = jsonContentType
..write(response)
..close();
+ close();
}
+ dynamic toJson() {
+ Map map = super.toJson();
+ map['type'] = 'HttpRequestClient';
+ map['request'] = '$request';
+ return map;
+ }
+}
+
+class Server {
+ static const WEBSOCKET_PATH = '/ws';
+ String defaultPath = '/index.html';
+ int port;
+
+ final VMService service;
+ HttpServer _server;
+
+ Server(this.service, this.port);
+
void _requestHandler(HttpRequest request) {
// Allow cross origin requests.
request.response.headers.add('Access-Control-Allow-Origin', '*');
final String path =
- request.uri.path == '/' ? '/index.html' : request.uri.path;
+ request.uri.path == '/' ? defaultPath : request.uri.path;
var resource = Resource.resources[path];
if (resource != null) {
@@ -35,19 +104,16 @@
return;
}
- var serviceRequest = new ServiceRequest();
- var r = serviceRequest.parse(request.uri);
- if (r) {
- var f = service.runningIsolates.route(serviceRequest);
- assert(f != null);
- f.then((_) {
- _sendResponse(request, serviceRequest.response);
- }).catchError((e) {
- // Error replying over HTTP.
+ if (path == WEBSOCKET_PATH) {
+ WebSocketTransformer.upgrade(request).then((WebSocket webSocket) {
+ new WebSocketClient(webSocket, service);
});
return;
}
- _sendResponse(request, serviceRequest.response);
+
+ var message = new Message.fromUri(request.uri);
+ var client = new HttpRequestClient(request, service);
+ client.onMessage(null, message);
}
Future startServer() {
@@ -59,7 +125,7 @@
_server = s;
_server.listen(_requestHandler);
if (display_message) {
- print('VmService listening on port $port');
+ print('VMService listening on port $port');
}
return s;
});
diff --git a/runtime/bin/vmservice/service_request.dart b/runtime/bin/vmservice/service_request.dart
deleted file mode 100644
index 8d7eb52..0000000
--- a/runtime/bin/vmservice/service_request.dart
+++ /dev/null
@@ -1,52 +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.
-
-part of vmservice;
-
-class ServiceRequest {
- final List<String> pathSegments = new List<String>();
- final Map<String, String> parameters = new Map<String, String>();
- String _response;
- String get response => _response;
-
- ServiceRequest();
-
- bool parse(Uri uri) {
- var path = uri.path;
- var split = path.split('/');
- if (split.length == 0) {
- setErrorResponse('Invalid request uri: ${request.uri}');
- return false;
- }
- for (int i = 0; i < split.length; i++) {
- var pathSegment = split[i];
- if (pathSegment == '') {
- continue;
- }
- pathSegments.add(pathSegment);
- }
- uri.queryParameters.forEach((k, v) {
- parameters[k] = v;
- });
- return true;
- }
-
- List toServiceCallMessage() {
- return [pathSegments, parameters.keys.toList(), parameters.values.toList()];
- }
-
- void setErrorResponse(String error) {
- _response = JSON.encode({
- 'type': 'Error',
- 'msg': error,
- 'pathSegments': pathSegments,
- 'parameters': parameters
- });
- }
-
- void setResponse(String response) {
- _response = response;
- }
-
-}
diff --git a/runtime/bin/vmservice/vmservice.dart b/runtime/bin/vmservice/vmservice.dart
index 309399f..5532428 100644
--- a/runtime/bin/vmservice/vmservice.dart
+++ b/runtime/bin/vmservice/vmservice.dart
@@ -9,16 +9,21 @@
import 'dart:isolate';
import 'dart:typed_data';
+part 'client.dart';
part 'constants.dart';
part 'resources.dart';
part 'running_isolate.dart';
part 'running_isolates.dart';
-part 'service_request.dart';
-part 'service_request_router.dart';
+part 'message.dart';
+part 'message_router.dart';
-class VMService {
+class VMService extends MessageRouter {
static VMService _instance;
+ /// Collection of currently connected clients.
+ final Set<Client> clients = new Set<Client>();
+ /// Collection of currently running isolates.
RunningIsolates runningIsolates = new RunningIsolates();
+ /// Isolate startup and shutdown messages are sent on this port.
final RawReceivePort receivePort;
void controlMessageHandler(int code, int port_id, SendPort sp, String name) {
@@ -32,6 +37,14 @@
}
}
+ void _addClient(Client client) {
+ clients.add(client);
+ }
+
+ void _removeClient(Client client) {
+ clients.remove(client);
+ }
+
void messageHandler(message) {
assert(message is List);
assert(message.length == 4);
@@ -50,7 +63,29 @@
}
return _instance;
}
+
+ void _clientCollection(Message message) {
+ var members = [];
+ var result = {};
+ clients.forEach((client) {
+ members.add(client.toJson());
+ });
+ result['type'] = 'ClientList';
+ result['members'] = members;
+ message.setResponse(JSON.encode(result));
+ }
+
+ Future<String> route(Message message) {
+ if (message.completed) {
+ return message.response;
+ }
+ if ((message.path.length == 1) && (message.path[0] == 'clients')) {
+ _clientCollection(message);
+ return message.response;
+ }
+ return runningIsolates.route(message);
+ }
}
-void sendServiceMessage(SendPort sp, ReceivePort rp, Object m)
+void sendServiceMessage(SendPort sp, Object m)
native "VMService_SendServiceMessage";
diff --git a/runtime/bin/vmservice/vmservice_dartium.dart b/runtime/bin/vmservice/vmservice_dartium.dart
index 249455d..99f04fa 100644
--- a/runtime/bin/vmservice/vmservice_dartium.dart
+++ b/runtime/bin/vmservice/vmservice_dartium.dart
@@ -15,41 +15,44 @@
// The native method that is called to post the response back to DevTools.
void postResponse(String response, int cookie) native "VMService_PostResponse";
-void handleRequest(service, String uri, cookie) {
- var serviceRequest = new ServiceRequest();
- var r = serviceRequest.parse(Uri.parse(uri));
- if (r) {
- var f = service.runningIsolates.route(serviceRequest);
- assert(f != null);
- f.then((_) {
- postResponse(serviceRequest.response, cookie);
- }).catchError((e) {
- // Error posting response back to Dartium.
+/// Dartium recieves messages through the _requestPort and posts
+/// responses via postResponse. It has a single persistent client.
+class DartiumClient extends Client {
+ DartiumClient(port, service) : super(service) {
+ port.handler = ((message) {
+ if (message == null) {
+ return;
+ }
+ if (message is! List) {
+ return;
+ }
+ if (message.length != 2) {
+ return;
+ }
+ if (message[0] is! String) {
+ return;
+ }
+ var uri = Uri.parse(message[0]);
+ var cookie = message[1];
+ onMessage(cookie, new Message.fromUri(uri));
});
- return;
}
- postResponse(serviceRequest.response, cookie);
+
+ void post(var seq, String response) {
+ postResponse(response, seq);
+ }
+
+ dynamic toJson() {
+ var map = super.toJson();
+ map['type'] = 'DartiumClient';
+ }
}
+
main() {
// Create VmService.
var service = new VMService();
_receivePort = service.receivePort;
- _requestPort = new RawReceivePort((message) {
- if (message == null) {
- return;
- }
- if (message is! List) {
- return;
- }
- if (message.length != 2) {
- return;
- }
- var uri = message[0];
- if (uri is! String) {
- return;
- }
- var cookie = message[1];
- handleRequest(service, uri, cookie);
- });
+ _requestPort = new RawReceivePort();
+ new DartiumClient(_requestPort, service);
}
diff --git a/runtime/bin/vmservice/vmservice_io.dart b/runtime/bin/vmservice/vmservice_io.dart
index d4590ce..fd7b785 100644
--- a/runtime/bin/vmservice/vmservice_io.dart
+++ b/runtime/bin/vmservice/vmservice_io.dart
@@ -4,6 +4,7 @@
library vmservice_io;
+import 'dart:convert';
import 'dart:io';
import 'vmservice.dart';
diff --git a/runtime/bin/vmservice_impl.cc b/runtime/bin/vmservice_impl.cc
index 74fb836..9e738cd 100644
--- a/runtime/bin/vmservice_impl.cc
+++ b/runtime/bin/vmservice_impl.cc
@@ -60,7 +60,8 @@
static Dart_NativeFunction VmServiceNativeResolver(Dart_Handle name,
- int num_arguments);
+ int num_arguments,
+ bool* auto_setup_scope);
bool VmService::Start(intptr_t server_port) {
@@ -491,8 +492,7 @@
StackZone zone(isolate);
HANDLESCOPE(isolate);
GET_NON_NULL_NATIVE_ARGUMENT(Instance, sp, arguments->NativeArgAt(0));
- GET_NON_NULL_NATIVE_ARGUMENT(Instance, rp, arguments->NativeArgAt(1));
- GET_NON_NULL_NATIVE_ARGUMENT(Instance, message, arguments->NativeArgAt(2));
+ GET_NON_NULL_NATIVE_ARGUMENT(Instance, message, arguments->NativeArgAt(1));
// Extract SendPort port id.
const Object& sp_id_obj = Object::Handle(DartLibraryCalls::PortGetId(sp));
@@ -502,19 +502,7 @@
Integer& id = Integer::Handle();
id ^= sp_id_obj.raw();
Dart_Port sp_id = static_cast<Dart_Port>(id.AsInt64Value());
-
- // Extract ReceivePort port id.
- const Object& rp_id_obj = Object::Handle(DartLibraryCalls::PortGetId(rp));
- if (rp_id_obj.IsError()) {
- Exceptions::PropagateError(Error::Cast(rp_id_obj));
- }
- ASSERT(rp_id_obj.IsSmi() || rp_id_obj.IsMint());
- id ^= rp_id_obj.raw();
- Dart_Port rp_id = static_cast<Dart_Port>(id.AsInt64Value());
-
- // Both are valid ports.
ASSERT(sp_id != ILLEGAL_PORT);
- ASSERT(rp_id != ILLEGAL_PORT);
// Serialize message.
uint8_t* data = NULL;
@@ -522,7 +510,7 @@
writer.WriteMessage(message);
// TODO(turnidge): Throw an exception when the return value is false?
- PortMap::PostMessage(new Message(sp_id, rp_id, data, writer.BytesWritten(),
+ PortMap::PostMessage(new Message(sp_id, data, writer.BytesWritten(),
Message::kOOBPriority));
}
@@ -535,18 +523,21 @@
static VmServiceNativeEntry _VmServiceNativeEntries[] = {
- {"VMService_SendServiceMessage", 3, SendServiceMessage}
+ {"VMService_SendServiceMessage", 2, SendServiceMessage}
};
static Dart_NativeFunction VmServiceNativeResolver(Dart_Handle name,
- int num_arguments) {
+ int num_arguments,
+ bool* auto_setup_scope) {
const Object& obj = Object::Handle(Api::UnwrapHandle(name));
if (!obj.IsString()) {
return NULL;
}
const char* function_name = obj.ToCString();
ASSERT(function_name != NULL);
+ ASSERT(auto_setup_scope != NULL);
+ *auto_setup_scope = true;
intptr_t n =
sizeof(_VmServiceNativeEntries) / sizeof(_VmServiceNativeEntries[0]);
for (intptr_t i = 0; i < n; i++) {
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index feb3819..8698bd6 100755
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -983,6 +983,18 @@
DART_EXPORT Dart_Handle Dart_HandleMessage();
/**
+ * Handles any pending messages for the vm service for the current
+ * isolate.
+ *
+ * This function may be used by an embedder at a breakpoint to avoid
+ * pausing the vm service.
+ *
+ * \return true if the vm service requests the program resume
+ * execution, false otherwise
+ */
+DART_EXPORT bool Dart_HandleServiceMessages();
+
+/**
* Processes any incoming messages for the current isolate.
*
* This function may only be used when the embedder has not provided
@@ -2110,7 +2122,8 @@
* See Dart_SetNativeResolver.
*/
typedef Dart_NativeFunction (*Dart_NativeEntryResolver)(Dart_Handle name,
- int num_of_arguments);
+ int num_of_arguments,
+ bool* auto_setup_scope);
/* TODO(turnidge): Consider renaming to NativeFunctionResolver or
* NativeResolver. */
diff --git a/runtime/include/dart_debugger_api.h b/runtime/include/dart_debugger_api.h
index c2c5aaa..5f3f234 100755
--- a/runtime/include/dart_debugger_api.h
+++ b/runtime/include/dart_debugger_api.h
@@ -679,25 +679,33 @@
/**
-* Returns the url of the library \library_id.
-*
-* Requires there to be a current isolate.
-*
-* \return A string handle containing the URL of the library.
-*/
+ * Returns the url of the library \library_id.
+ *
+ * Requires there to be a current isolate.
+ *
+ * \return A string handle containing the URL of the library.
+ */
DART_EXPORT Dart_Handle Dart_GetLibraryURL(intptr_t library_id);
/**
-* Returns the isolate object corresponding to the isolate id.
-*
-* \return The Dart_Isolate object corresponding to the isolate id.
-* If the specified id is invalid NULL is returned.
-*/
+ * Returns the isolate object corresponding to the isolate id.
+ *
+ * \return The Dart_Isolate object corresponding to the isolate id.
+ * If the specified id is invalid NULL is returned.
+ */
DART_EXPORT Dart_Isolate Dart_GetIsolate(Dart_IsolateId isolate_id);
/**
+ * Returns the isolate id for an isolate.
+ *
+ * \return The Dart_IsolateId value corresponding to the isolate.
+ */
+DART_EXPORT Dart_IsolateId Dart_GetIsolateId(Dart_Isolate isolate);
+
+
+/**
* Returns VM status information. VM status is implemented using a
* different status plug-in for each type of status; for example, there
* might be an "isolate" plug-in that returns information about the
diff --git a/runtime/lib/array.dart b/runtime/lib/array.dart
index a0fb5f9..2369b4c 100644
--- a/runtime/lib/array.dart
+++ b/runtime/lib/array.dart
@@ -78,7 +78,7 @@
_copyFromObjectArray(iterable, skipCount, start, length);
} else {
if (iterable is List) {
- Arrays.copy(iterable, skipCount, this, start, length);
+ Lists.copy(iterable, skipCount, this, start, length);
} else {
Iterator it = iterable.iterator;
while (skipCount > 0) {
@@ -108,13 +108,13 @@
}
List<E> sublist(int start, [int end]) {
- Arrays.indicesCheck(this, start, end);
+ Lists.indicesCheck(this, start, end);
if (end == null) end = this.length;
int length = end - start;
if (start == end) return [];
List list = new _GrowableList<E>.withCapacity(length);
list.length = length;
- Arrays.copy(this, start, list, 0, length);
+ Lists.copy(this, start, list, 0, length);
return list;
}
@@ -209,12 +209,12 @@
}
int indexOf(Object element, [int start = 0]) {
- return Arrays.indexOf(this, element, start, this.length);
+ return Lists.indexOf(this, element, start, this.length);
}
int lastIndexOf(Object element, [int start = null]) {
if (start == null) start = length - 1;
- return Arrays.lastIndexOf(this, element, start);
+ return Lists.lastIndexOf(this, element, start);
}
Iterator<E> get iterator {
@@ -361,13 +361,13 @@
}
List<E> sublist(int start, [int end]) {
- Arrays.indicesCheck(this, start, end);
+ Lists.indicesCheck(this, start, end);
if (end == null) end = this.length;
int length = end - start;
if (start == end) return [];
List list = new List<E>();
list.length = length;
- Arrays.copy(this, start, list, 0, length);
+ Lists.copy(this, start, list, 0, length);
return list;
}
@@ -472,12 +472,12 @@
}
int indexOf(Object element, [int start = 0]) {
- return Arrays.indexOf(this, element, start, this.length);
+ return Lists.indexOf(this, element, start, this.length);
}
int lastIndexOf(Object element, [int start = null]) {
if (start == null) start = length - 1;
- return Arrays.lastIndexOf(this, element, start);
+ return Lists.lastIndexOf(this, element, start);
}
Iterator<E> get iterator {
diff --git a/runtime/lib/corelib_sources.gypi b/runtime/lib/corelib_sources.gypi
index dde6721..1b94b04 100644
--- a/runtime/lib/corelib_sources.gypi
+++ b/runtime/lib/corelib_sources.gypi
@@ -32,7 +32,6 @@
'integers.cc',
'integers.dart',
'integers_patch.dart',
- 'invocation_mirror.cc',
'invocation_mirror.h',
'invocation_mirror_patch.dart',
'map_patch.dart',
diff --git a/runtime/lib/double.dart b/runtime/lib/double.dart
index c5b2c38..8efe789 100644
--- a/runtime/lib/double.dart
+++ b/runtime/lib/double.dart
@@ -104,6 +104,12 @@
return this < 0.0 ? -this : this;
}
+ double get sign {
+ if (this > 0.0) return 1.0;
+ if (this < 0.0) return -1.0;
+ return this; // +/-0.0 or NaN.
+ }
+
int round() => roundToDouble().toInt();
int floor() => floorToDouble().toInt();
int ceil () => ceilToDouble().toInt();
diff --git a/runtime/lib/growable_array.dart b/runtime/lib/growable_array.dart
index c3e6204..e9c1082 100644
--- a/runtime/lib/growable_array.dart
+++ b/runtime/lib/growable_array.dart
@@ -19,7 +19,7 @@
// (with a length that has been increased, but without a new element).
if (index is! int) throw new ArgumentError(index);
this.length++;
- Arrays.copy(this,
+ Lists.copy(this,
index,
this,
index + 1,
@@ -31,7 +31,7 @@
if (index is! int) throw new ArgumentError(index);
T result = this[index];
int newLength = this.length - 1;
- Arrays.copy(this,
+ Lists.copy(this,
index + 1,
this,
index,
@@ -95,8 +95,8 @@
}
void removeRange(int start, int end) {
- Arrays.indicesCheck(this, start, end);
- Arrays.copy(this,
+ Lists.indicesCheck(this, start, end);
+ Lists.copy(this,
end,
this,
start,
@@ -113,13 +113,13 @@
}
List<T> sublist(int start, [int end]) {
- Arrays.indicesCheck(this, start, end);
+ Lists.indicesCheck(this, start, end);
if (end == null) end = this.length;
int length = end - start;
if (start == end) return <T>[];
List list = new _GrowableList<T>.withCapacity(length);
list.length = length;
- Arrays.copy(this, start, list, 0, length);
+ Lists.copy(this, start, list, 0, length);
return list;
}
diff --git a/runtime/lib/integers.dart b/runtime/lib/integers.dart
index 7f7fc90..9c503c4 100644
--- a/runtime/lib/integers.dart
+++ b/runtime/lib/integers.dart
@@ -92,6 +92,9 @@
int abs() {
return this < 0 ? -this : this;
}
+ int get sign {
+ return (this > 0) ? 1 : (this < 0) ? -1 : 0;
+ }
bool get isEven => ((this & 1) == 0);
bool get isOdd => !isEven;
bool get isNaN => false;
diff --git a/runtime/lib/invocation_mirror.cc b/runtime/lib/invocation_mirror.cc
deleted file mode 100644
index 913dcf4..0000000
--- a/runtime/lib/invocation_mirror.cc
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#include "vm/bootstrap_natives.h"
-
-#include "vm/compiler.h"
-#include "vm/dart_entry.h"
-#include "vm/exceptions.h"
-#include "vm/native_entry.h"
-#include "vm/object_store.h"
-#include "vm/resolver.h"
-#include "vm/symbols.h"
-
-namespace dart {
-
-DEFINE_NATIVE_ENTRY(InvocationMirror_invoke, 4) {
- const Instance& receiver = Instance::CheckedHandle(arguments->NativeArgAt(0));
- const String& fun_name = String::CheckedHandle(arguments->NativeArgAt(1));
- const Array& fun_args_desc = Array::CheckedHandle(arguments->NativeArgAt(2));
- const Array& fun_arguments = Array::CheckedHandle(arguments->NativeArgAt(3));
-
- // Allocate a fixed-length array duplicating the original function arguments
- // and replace the receiver.
- const int num_arguments = fun_arguments.Length();
- const Array& invoke_arguments = Array::Handle(Array::New(num_arguments));
- invoke_arguments.SetAt(0, receiver);
- Object& arg = Object::Handle();
- for (int i = 1; i < num_arguments; i++) {
- arg = fun_arguments.At(i);
- invoke_arguments.SetAt(i, arg);
- }
- // Resolve dynamic function given by name.
- const ArgumentsDescriptor args_desc(fun_args_desc);
- const Function& function = Function::Handle(
- Resolver::ResolveDynamic(receiver,
- fun_name,
- args_desc));
- Object& result = Object::Handle();
- if (function.IsNull()) {
- result = DartEntry::InvokeNoSuchMethod(receiver,
- fun_name,
- invoke_arguments,
- fun_args_desc);
- } else {
- result = DartEntry::InvokeFunction(function,
- invoke_arguments,
- fun_args_desc);
- }
- if (result.IsError()) {
- Exceptions::PropagateError(Error::Cast(result));
- }
- return result.raw();
-}
-
-} // namespace dart
diff --git a/runtime/lib/invocation_mirror_patch.dart b/runtime/lib/invocation_mirror_patch.dart
index 4c2e7e5..3f76e4e 100644
--- a/runtime/lib/invocation_mirror_patch.dart
+++ b/runtime/lib/invocation_mirror_patch.dart
@@ -133,18 +133,4 @@
arguments,
isSuperInvocation);
}
-
- static _invoke(Object receiver,
- String functionName,
- List argumentsDescriptor,
- List arguments)
- native "InvocationMirror_invoke";
-
- _invokeOn(Object receiver) {
- return _invoke(receiver, _functionName, _argumentsDescriptor, _arguments);
- }
-
- // TODO(ahe): This is a hack. See _LocalInstanceMirrorImpl.delegate
- // in mirrors_impl.dart
- static final _invokeOnClosure = (x, y) => y._invokeOn(x);
}
diff --git a/runtime/lib/isolate.cc b/runtime/lib/isolate.cc
index 0f7da54..4e78b26 100644
--- a/runtime/lib/isolate.cc
+++ b/runtime/lib/isolate.cc
@@ -105,7 +105,7 @@
writer.WriteMessage(obj);
// TODO(turnidge): Throw an exception when the return value is false?
- PortMap::PostMessage(new Message(send_id.Value(), Message::kIllegalPort,
+ PortMap::PostMessage(new Message(send_id.Value(),
data, writer.BytesWritten(),
Message::kNormalPriority));
return Object::null();
diff --git a/runtime/lib/isolate_patch.dart b/runtime/lib/isolate_patch.dart
index 3792a5b..80e830b 100644
--- a/runtime/lib/isolate_patch.dart
+++ b/runtime/lib/isolate_patch.dart
@@ -107,8 +107,7 @@
}
// Called from the VM to dispatch to the handler.
- static void _handleMessage(
- _RawReceivePortImpl port, int replyId, var message) {
+ static void _handleMessage(_RawReceivePortImpl port, var message) {
assert(port != null);
// TODO(floitsch): this relies on the fact that any exception aborts the
// VM. Once we have non-fatal global exceptions we need to catch errors
@@ -229,40 +228,39 @@
patch class Isolate {
/* patch */ static Future<Isolate> spawn(
void entryPoint(message), var message) {
- Completer completer = new Completer<Isolate>.sync();
try {
// The VM will invoke [_startIsolate] with entryPoint as argument.
SendPort controlPort = _spawnFunction(entryPoint);
RawReceivePort readyPort = new RawReceivePort();
controlPort.send([readyPort.sendPort, message]);
+ Completer completer = new Completer<Isolate>.sync();
readyPort.handler = (readyMessage) {
assert(readyMessage == 'started');
readyPort.close();
completer.complete(new Isolate._fromControlPort(controlPort));
};
- } catch(e, st) {
- // TODO(14718): we want errors to go into the returned future.
- rethrow;
+ return completer.future;
+ } catch (e, st) {
+ return new Future<Isolate>.error(e, st);
};
- return completer.future;
}
/* patch */ static Future<Isolate> spawnUri(
Uri uri, List<String> args, var message) {
- Completer completer = new Completer<Isolate>.sync();
try {
// The VM will invoke [_startIsolate] and not `main`.
SendPort controlPort = _spawnUri(uri.toString());
RawReceivePort readyPort = new RawReceivePort();
controlPort.send([readyPort.sendPort, args, message]);
+ Completer completer = new Completer<Isolate>.sync();
readyPort.handler = (readyMessage) {
assert(readyMessage == 'started');
readyPort.close();
completer.complete(new Isolate._fromControlPort(controlPort));
};
- } catch(e, st) {
- // TODO(14718): we want errors to go into the returned future.
- rethrow;
+ return completer.future;
+ } catch (e, st) {
+ return new Future<Isolate>.error(e, st);
};
return completer.future;
}
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index 59d95bc..3d228cd 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -97,22 +97,6 @@
}
-DEFINE_NATIVE_ENTRY(Mirrors_isLocalPort, 1) {
- GET_NON_NULL_NATIVE_ARGUMENT(Instance, port, arguments->NativeArgAt(0));
-
- // Get the port id from the SendPort instance.
- const Object& id_obj = Object::Handle(DartLibraryCalls::PortGetId(port));
- if (id_obj.IsError()) {
- Exceptions::PropagateError(Error::Cast(id_obj));
- UNREACHABLE();
- }
- ASSERT(id_obj.IsSmi() || id_obj.IsMint());
- Integer& id = Integer::Handle();
- id ^= id_obj.raw();
- Dart_Port port_id = static_cast<Dart_Port>(id.AsInt64Value());
- return Bool::Get(PortMap::IsLocalPort(port_id)).raw();
-}
-
static void EnsureConstructorsAreCompiled(const Function& func) {
// Only generative constructors can have initializing formals.
if (!func.IsConstructor()) return;
@@ -1712,6 +1696,16 @@
UNREACHABLE();
}
+ if (klass.is_abstract() && !lookup_constructor.IsFactory()) {
+ const Array& error_args = Array::Handle(Array::New(3));
+ error_args.SetAt(0, klass_name);
+ // 1 = script url
+ // 2 = token position
+ Exceptions::ThrowByType(Exceptions::kAbstractClassInstantiation,
+ error_args);
+ UNREACHABLE();
+ }
+
ASSERT(!type.IsNull());
AbstractTypeArguments& type_arguments =
AbstractTypeArguments::Handle(type.arguments());
diff --git a/runtime/lib/mirrors_impl.dart b/runtime/lib/mirrors_impl.dart
index e057fd2..5f0983a 100644
--- a/runtime/lib/mirrors_impl.dart
+++ b/runtime/lib/mirrors_impl.dart
@@ -262,8 +262,6 @@
class _LocalInstanceMirror extends _LocalObjectMirror
implements InstanceMirror {
- // TODO(ahe): This is a hack, see delegate below.
- static Function _invokeOnClosure;
_LocalInstanceMirror(reflectee) : super(reflectee);
@@ -283,17 +281,22 @@
get reflectee => _reflectee;
delegate(Invocation invocation) {
- if (_invokeOnClosure == null) {
- // TODO(ahe): This is a total hack. We're using the mirror
- // system to access a private field in a different library. For
- // some reason, that works. On the other hand, calling a
- // private method does not work.
- ClassMirror invocationImplClass = reflect(invocation).type;
- Symbol fieldName = MirrorSystem.getSymbol('_invokeOnClosure',
- invocationImplClass.owner);
- _invokeOnClosure = invocationImplClass.getField(fieldName).reflectee;
+ if (invocation.isMethod) {
+ return this.invoke(invocation.memberName,
+ invocation.positionalArguments,
+ invocation.namedArguments).reflectee;
}
- return _invokeOnClosure(reflectee, invocation);
+ if (invocation.isGetter) {
+ return this.getField(invocation.memberName).reflectee;
+ }
+ if (invocation.isSetter) {
+ var unwrapped = _n(invocation.memberName);
+ var withoutEqual = _s(unwrapped.substring(0, unwrapped.length - 1));
+ var arg = invocation.positionalArguments[0];
+ this.setField(withoutEqual, arg).reflectee;
+ return arg;
+ }
+ throw "UNREACHABLE";
}
String toString() => 'InstanceMirror on ${Error.safeToString(_reflectee)}';
@@ -1072,11 +1075,34 @@
new _UnmodifiableMapView<Symbol, DeclarationMirror>(_members);
}
+
+ var _cachedTopLevelMembers;
Map<Symbol, MethodMirror> get topLevelMembers {
- throw new UnimplementedError(
- 'LibraryMirror.topLevelMembers is not implemented');
+ if (_cachedTopLevelMembers != null) return _cachedTopLevelMembers;
+ var result = new Map<Symbol, MethodMirror>();
+ declarations.values.forEach((decl) {
+ if (decl is MethodMirror && !decl.isAbstract) {
+ result[decl.simpleName] = decl;
+ }
+ if (decl is VariableMirror) {
+ var getterName = decl.simpleName;
+ result[getterName] =
+ new _SyntheticAccessor(this, getterName, true, true, true, decl);
+ if (!decl.isFinal) {
+ var setterName = _asSetter(decl.simpleName, this);
+ result[setterName] = new _SyntheticAccessor(
+ this, setterName, false, true, true, decl);
+ }
+ }
+ // if (decl is TypeMirror) {
+ // var getterName = decl.simpleName;
+ // result[getterName] = new _SyntheticTypeGetter(this, getterName, decl);
+ // }
+ });
+ return _cachedTopLevelMembers = result;
}
+
Map<Symbol, Mirror> _cachedMembers;
Map<Symbol, Mirror> get _members {
if (_cachedMembers == null) {
@@ -1414,9 +1440,6 @@
}
class _Mirrors {
- // Does a port refer to our local isolate?
- static bool isLocalPort(SendPort port) native 'Mirrors_isLocalPort';
-
static MirrorSystem _currentMirrorSystem = null;
// Creates a new local MirrorSystem.
diff --git a/runtime/lib/object.cc b/runtime/lib/object.cc
index 3774913..e040d9f 100644
--- a/runtime/lib/object.cc
+++ b/runtime/lib/object.cc
@@ -105,10 +105,7 @@
const Instance& instance = Instance::CheckedHandle(arguments->NativeArgAt(0));
// Special handling for following types outside this native.
ASSERT(!instance.IsString() && !instance.IsInteger() && !instance.IsDouble());
- const Type& type = Type::Handle(instance.GetType());
- // The static type of null is specified to be the bottom type, however, the
- // runtime type of null is the Null type, which we correctly return here.
- return type.Canonicalize();
+ return instance.GetType();
}
diff --git a/runtime/lib/print_patch.dart b/runtime/lib/print_patch.dart
index 186b4fb..539294a 100644
--- a/runtime/lib/print_patch.dart
+++ b/runtime/lib/print_patch.dart
@@ -2,13 +2,15 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-typedef void _PrintClosure(Object obj);
+// A print-closure gets a String that should be printed. In general the
+// string is a line, but it may contain "\n" characters.
+typedef void _PrintClosure(String line);
patch void printToConsole(String line) {
_printClosure(line);
}
-void _unsupportedPrint(Object obj) {
+void _unsupportedPrint(String line) {
throw new UnsupportedError("'print' is not supported");
}
diff --git a/runtime/platform/thread.h b/runtime/platform/thread.h
index 02ad51e..fb56a50 100644
--- a/runtime/platform/thread.h
+++ b/runtime/platform/thread.h
@@ -25,6 +25,7 @@
class Thread {
public:
static ThreadLocalKey kUnsetThreadLocalKey;
+ static ThreadId kInvalidThreadId;
typedef void (*ThreadStartFunction) (uword parameter);
@@ -41,6 +42,8 @@
static void SetThreadLocal(ThreadLocalKey key, uword value);
static intptr_t GetMaxStackSize();
static ThreadId GetCurrentThreadId();
+ static intptr_t ThreadIdToIntPtr(ThreadId id);
+ static bool Compare(ThreadId a, ThreadId b);
static void GetThreadCpuUsage(ThreadId thread_id, int64_t* cpu_usage);
};
@@ -91,58 +94,6 @@
};
-class ScopedMutex {
- public:
- explicit ScopedMutex(Mutex* mutex) : mutex_(mutex) {
- ASSERT(mutex_ != NULL);
- mutex_->Lock();
- }
-
- ~ScopedMutex() {
- mutex_->Unlock();
- }
-
- private:
- Mutex* const mutex_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedMutex);
-};
-
-
-class ScopedMonitor {
- public:
- explicit ScopedMonitor(Monitor* monitor) : monitor_(monitor) {
- ASSERT(monitor_ != NULL);
- monitor_->Enter();
- }
-
- ~ScopedMonitor() {
- monitor_->Exit();
- }
-
- Monitor::WaitResult Wait(int64_t millis = dart::Monitor::kNoTimeout) {
- return monitor_->Wait(millis);
- }
-
- Monitor::WaitResult WaitMicros(int64_t micros = dart::Monitor::kNoTimeout) {
- return monitor_->WaitMicros(micros);
- }
-
- void Notify() {
- monitor_->Notify();
- }
-
- void NotifyAll() {
- monitor_->NotifyAll();
- }
-
- private:
- Monitor* const monitor_;
-
- DISALLOW_COPY_AND_ASSIGN(ScopedMonitor);
-};
-
-
} // namespace dart
diff --git a/runtime/platform/thread_android.cc b/runtime/platform/thread_android.cc
index f29ffdb..ae68de6 100644
--- a/runtime/platform/thread_android.cc
+++ b/runtime/platform/thread_android.cc
@@ -113,7 +113,7 @@
ThreadLocalKey Thread::kUnsetThreadLocalKey = static_cast<pthread_key_t>(-1);
-
+ThreadId Thread::kInvalidThreadId = static_cast<ThreadId>(0);
ThreadLocalKey Thread::CreateThreadLocal() {
pthread_key_t key = kUnsetThreadLocalKey;
@@ -149,6 +149,17 @@
}
+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) {
ASSERT(thread_id == GetCurrentThreadId());
ASSERT(cpu_usage != NULL);
diff --git a/runtime/platform/thread_linux.cc b/runtime/platform/thread_linux.cc
index 36bcfe4..12ea1f9 100644
--- a/runtime/platform/thread_linux.cc
+++ b/runtime/platform/thread_linux.cc
@@ -114,7 +114,7 @@
ThreadLocalKey Thread::kUnsetThreadLocalKey = static_cast<pthread_key_t>(-1);
-
+ThreadId Thread::kInvalidThreadId = static_cast<ThreadId>(0);
ThreadLocalKey Thread::CreateThreadLocal() {
pthread_key_t key = kUnsetThreadLocalKey;
@@ -150,6 +150,17 @@
}
+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) {
ASSERT(thread_id == GetCurrentThreadId());
ASSERT(cpu_usage != NULL);
diff --git a/runtime/platform/thread_macos.cc b/runtime/platform/thread_macos.cc
index c4167d4..01c5c8c 100644
--- a/runtime/platform/thread_macos.cc
+++ b/runtime/platform/thread_macos.cc
@@ -106,7 +106,7 @@
ThreadLocalKey Thread::kUnsetThreadLocalKey = static_cast<pthread_key_t>(-1);
-
+ThreadId Thread::kInvalidThreadId = reinterpret_cast<ThreadId>(NULL);
ThreadLocalKey Thread::CreateThreadLocal() {
pthread_key_t key = kUnsetThreadLocalKey;
@@ -142,6 +142,17 @@
}
+intptr_t Thread::ThreadIdToIntPtr(ThreadId id) {
+ ASSERT(sizeof(id) == sizeof(intptr_t));
+ return reinterpret_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) {
ASSERT(thread_id == GetCurrentThreadId());
ASSERT(cpu_usage != NULL);
diff --git a/runtime/platform/thread_win.cc b/runtime/platform/thread_win.cc
index f4494ae..afbae8b 100644
--- a/runtime/platform/thread_win.cc
+++ b/runtime/platform/thread_win.cc
@@ -99,7 +99,8 @@
ThreadLocalKey ThreadInlineImpl::thread_id_key = Thread::kUnsetThreadLocalKey;
ThreadLocalKey Thread::kUnsetThreadLocalKey = TLS_OUT_OF_INDEXES;
-
+ThreadId Thread::kInvalidThreadId =
+ reinterpret_cast<ThreadId>(INVALID_HANDLE_VALUE);
ThreadLocalKey Thread::CreateThreadLocal() {
ThreadLocalKey key = TlsAlloc();
@@ -133,6 +134,17 @@
}
+intptr_t Thread::ThreadIdToIntPtr(ThreadId id) {
+ ASSERT(sizeof(id) == sizeof(intptr_t));
+ return reinterpret_cast<intptr_t>(id);
+}
+
+
+bool Thread::Compare(ThreadId a, ThreadId b) {
+ return a == b;
+}
+
+
void Thread::GetThreadCpuUsage(ThreadId thread_id, int64_t* cpu_usage) {
static const int64_t kTimeEpoc = 116444736000000000LL;
static const int64_t kTimeScaler = 10; // 100 ns to us.
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 07c7ffc..669168b 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -23,6 +23,19 @@
[ $system == windows ]
cc/Dart2JSCompileAll: Skip
cc/ExternalizeConstantStrings: Skip
+cc/ThreadInterrupterHigh: Skip
+cc/ThreadInterrupterMedium: Skip
+cc/ThreadInterrupterLow: Skip
+
+[ $system == macos ]
+cc/ThreadInterrupterHigh: Skip
+cc/ThreadInterrupterMedium: Skip
+cc/ThreadInterrupterLow: Skip
+
+[ $arch == simarm || $arch == simmips ]
+cc/ThreadInterrupterHigh: Skip
+cc/ThreadInterrupterMedium: Skip
+cc/ThreadInterrupterLow: Skip
[ $compiler == dart2js ]
dart/mirrored_compilation_error_test: Skip # VM-specific flag
diff --git a/runtime/vm/atomic.h b/runtime/vm/atomic.h
new file mode 100644
index 0000000..64defc0
--- /dev/null
+++ b/runtime/vm/atomic.h
@@ -0,0 +1,22 @@
+// 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.
+
+#ifndef VM_ATOMIC_H_
+#define VM_ATOMIC_H_
+
+#include "vm/allocation.h"
+
+namespace dart {
+
+class AtomicOperations : public AllStatic {
+ public:
+ // Atomically fetch the value at p and increment the value at p.
+ // Returns the original value at p.
+ static uintptr_t FetchAndIncrement(uintptr_t* p);
+};
+
+
+} // namespace dart
+
+#endif // VM_ATOMIC_H_
diff --git a/runtime/vm/atomic_android.cc b/runtime/vm/atomic_android.cc
new file mode 100644
index 0000000..d11a59d
--- /dev/null
+++ b/runtime/vm/atomic_android.cc
@@ -0,0 +1,20 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "platform/globals.h"
+#if defined(TARGET_OS_ANDROID)
+
+#include "vm/atomic.h"
+
+namespace dart {
+
+
+uintptr_t AtomicOperations::FetchAndIncrement(uintptr_t* p) {
+ return __sync_fetch_and_add(p, 1);
+}
+
+
+} // namespace dart
+
+#endif // defined(TARGET_OS_ANDROID)
diff --git a/runtime/vm/atomic_linux.cc b/runtime/vm/atomic_linux.cc
new file mode 100644
index 0000000..f5888b0
--- /dev/null
+++ b/runtime/vm/atomic_linux.cc
@@ -0,0 +1,21 @@
+// 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.
+
+#include "platform/globals.h"
+#if defined(TARGET_OS_LINUX)
+
+#include "vm/atomic.h"
+
+namespace dart {
+
+
+uintptr_t AtomicOperations::FetchAndIncrement(uintptr_t* p) {
+ return __sync_fetch_and_add(p, 1);
+}
+
+
+} // namespace dart
+
+
+#endif // defined(TARGET_OS_LINUX)
diff --git a/runtime/vm/atomic_macos.cc b/runtime/vm/atomic_macos.cc
new file mode 100644
index 0000000..213ccf4
--- /dev/null
+++ b/runtime/vm/atomic_macos.cc
@@ -0,0 +1,20 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "platform/globals.h"
+#if defined(TARGET_OS_MACOS)
+
+#include "vm/atomic.h"
+
+namespace dart {
+
+
+uintptr_t AtomicOperations::FetchAndIncrement(uintptr_t* p) {
+ return __sync_fetch_and_add(p, 1);
+}
+
+
+} // namespace dart
+
+#endif // defined(TARGET_OS_MACOS)
diff --git a/runtime/vm/atomic_win.cc b/runtime/vm/atomic_win.cc
new file mode 100644
index 0000000..78a3fd6
--- /dev/null
+++ b/runtime/vm/atomic_win.cc
@@ -0,0 +1,28 @@
+// 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.
+
+#include "platform/globals.h"
+#if defined(TARGET_OS_WINDOWS)
+
+#include "vm/atomic.h"
+
+namespace dart {
+
+
+uintptr_t AtomicOperations::FetchAndIncrement(uintptr_t* p) {
+#if defined(TARGET_ARCH_X64)
+ return static_cast<uintptr_t>(
+ InterlockedIncrement64(reinterpret_cast<LONGLONG*>(p))) - 1;
+#elif defined(TARGET_ARCH_IA32)
+ return static_cast<uintptr_t>(
+ InterlockedIncrement(reinterpret_cast<LONG*>(p))) - 1;
+#else
+ UNIMPLEMENTED();
+#endif
+}
+
+
+} // namespace dart
+
+#endif // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/vm/benchmark_test.cc b/runtime/vm/benchmark_test.cc
index ff4e164..2a07e64 100644
--- a/runtime/vm/benchmark_test.cc
+++ b/runtime/vm/benchmark_test.cc
@@ -134,7 +134,11 @@
}
-static Dart_NativeFunction bm_uda_lookup(Dart_Handle name, int argument_count) {
+static Dart_NativeFunction bm_uda_lookup(Dart_Handle name,
+ int argument_count,
+ bool* auto_setup_scope) {
+ ASSERT(auto_setup_scope != NULL);
+ *auto_setup_scope = false;
const char* cstr = NULL;
Dart_Handle result = Dart_StringToCString(name, &cstr);
EXPECT_VALID(result);
@@ -265,7 +269,10 @@
static Dart_NativeFunction NativeResolver(Dart_Handle name,
- int arg_count) {
+ int arg_count,
+ bool* auto_setup_scope) {
+ ASSERT(auto_setup_scope != NULL);
+ *auto_setup_scope = false;
return &func;
}
@@ -335,7 +342,10 @@
static Dart_NativeFunction StackFrameNativeResolver(Dart_Handle name,
- int arg_count) {
+ int arg_count,
+ bool* auto_setup_scope) {
+ ASSERT(auto_setup_scope != NULL);
+ *auto_setup_scope = false;
return &StackFrame_accessFrame;
}
diff --git a/runtime/vm/bootstrap_natives.cc b/runtime/vm/bootstrap_natives.cc
index a072563..a278799 100644
--- a/runtime/vm/bootstrap_natives.cc
+++ b/runtime/vm/bootstrap_natives.cc
@@ -31,11 +31,14 @@
Dart_NativeFunction BootstrapNatives::Lookup(Dart_Handle name,
- int argument_count) {
+ int argument_count,
+ bool* auto_setup_scope) {
const Object& obj = Object::Handle(Api::UnwrapHandle(name));
if (!obj.IsString()) {
return NULL;
}
+ ASSERT(auto_setup_scope);
+ *auto_setup_scope = false;
const char* function_name = obj.ToCString();
ASSERT(function_name != NULL);
int num_entries = sizeof(BootStrapEntries) / sizeof(struct NativeEntries);
diff --git a/runtime/vm/bootstrap_natives.h b/runtime/vm/bootstrap_natives.h
index 02729d4..5747777 100644
--- a/runtime/vm/bootstrap_natives.h
+++ b/runtime/vm/bootstrap_natives.h
@@ -25,7 +25,6 @@
V(Function_apply, 2) \
V(FunctionImpl_equals, 2) \
V(FunctionImpl_hashCode, 1) \
- V(InvocationMirror_invoke, 4) \
V(AbstractType_toString, 1) \
V(Identical_comparison, 2) \
V(Integer_bitAndFromInteger, 2) \
@@ -259,7 +258,6 @@
V(Isolate_mainPort, 0) \
V(Isolate_spawnFunction, 1) \
V(Isolate_spawnUri, 1) \
- V(Mirrors_isLocalPort, 1) \
V(Mirrors_makeLocalClassMirror, 1) \
V(Mirrors_makeLocalTypeMirror, 1) \
V(Mirrors_makeLocalMirrorSystem, 0) \
@@ -320,7 +318,9 @@
class BootstrapNatives : public AllStatic {
public:
- static Dart_NativeFunction Lookup(Dart_Handle name, int argument_count);
+ static Dart_NativeFunction Lookup(Dart_Handle name,
+ int argument_count,
+ bool* auto_setup_scope);
#define DECLARE_BOOTSTRAP_NATIVE(name, ignored) \
static void DN_##name(Dart_NativeArguments args);
diff --git a/runtime/vm/code_descriptors_test.cc b/runtime/vm/code_descriptors_test.cc
index 11536a9..5b2ccb0 100644
--- a/runtime/vm/code_descriptors_test.cc
+++ b/runtime/vm/code_descriptors_test.cc
@@ -194,7 +194,10 @@
static Dart_NativeFunction native_resolver(Dart_Handle name,
- int argument_count) {
+ int argument_count,
+ bool* auto_setup_scope) {
+ ASSERT(auto_setup_scope);
+ *auto_setup_scope = false;
return reinterpret_cast<Dart_NativeFunction>(&NativeFunc);
}
diff --git a/runtime/vm/code_generator.cc b/runtime/vm/code_generator.cc
index 44ddb3e..d838eff 100644
--- a/runtime/vm/code_generator.cc
+++ b/runtime/vm/code_generator.cc
@@ -1276,7 +1276,7 @@
return false;
}
}
- if (!function.is_optimizable()) {
+ if (!function.IsOptimizable()) {
if (FLAG_trace_failed_optimization_attempts) {
OS::PrintErr("Not Optimizable: %s\n", function.ToFullyQualifiedCString());
}
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index 90f22b4..288dc59 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -263,7 +263,7 @@
bool optimized,
intptr_t osr_id) {
const Function& function = parsed_function->function();
- if (optimized && !function.is_optimizable()) {
+ if (optimized && !function.IsOptimizable()) {
return false;
}
TimerScope timer(FLAG_compiler_stats, &CompilerStats::codegen_timer);
@@ -786,7 +786,7 @@
} else if (FLAG_trace_failed_optimization_attempts) {
OS::Print("Cannot optimize: %s\n", function.ToFullyQualifiedCString());
}
- function.set_is_optimizable(false);
+ function.SetIsOptimizable(false);
isolate->set_long_jump_base(base);
return Error::null();
}
@@ -939,7 +939,7 @@
func.set_num_fixed_parameters(0);
func.SetNumOptionalParameters(0, true);
// Manually generated AST, do not recompile.
- func.set_is_optimizable(false);
+ func.SetIsOptimizable(false);
// We compile the function here, even though InvokeStatic() below
// would compile func automatically. We are checking fewer invariants
diff --git a/runtime/vm/custom_isolate_test.cc b/runtime/vm/custom_isolate_test.cc
index 7d43473..9394e57 100644
--- a/runtime/vm/custom_isolate_test.cc
+++ b/runtime/vm/custom_isolate_test.cc
@@ -18,7 +18,9 @@
static void native_echo(Dart_NativeArguments args);
static void CustomIsolateImpl_start(Dart_NativeArguments args);
-static Dart_NativeFunction NativeLookup(Dart_Handle name, int argc);
+static Dart_NativeFunction NativeLookup(Dart_Handle name,
+ int argc,
+ bool* auto_setup_scope);
static const char* kCustomIsolateScriptChars =
@@ -229,7 +231,11 @@
}
-static Dart_NativeFunction NativeLookup(Dart_Handle name, int argc) {
+static Dart_NativeFunction NativeLookup(Dart_Handle name,
+ int argc,
+ bool* auto_setup_scope) {
+ ASSERT(auto_setup_scope != NULL);
+ *auto_setup_scope = false;
const char* name_str = NULL;
EXPECT(Dart_IsString(name));
EXPECT_VALID(Dart_StringToCString(name, &name_str));
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index 2633f25..248d413 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -21,6 +21,7 @@
#include "vm/snapshot.h"
#include "vm/stub_code.h"
#include "vm/symbols.h"
+#include "vm/thread_interrupter.h"
#include "vm/thread_pool.h"
#include "vm/virtual_memory.h"
#include "vm/zone.h"
@@ -97,7 +98,7 @@
FreeListElement::InitOnce();
Api::InitOnce();
CodeObservers::InitOnce();
- ProfilerManager::InitOnce();
+ Profiler::InitOnce();
#if defined(USING_SIMULATOR)
Simulator::InitOnce();
#endif
@@ -172,7 +173,7 @@
vm_isolate_ = NULL;
#endif
- ProfilerManager::Shutdown();
+ Profiler::Shutdown();
CodeObservers::DeleteAll();
return NULL;
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index 8280f94..a25c698 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -293,6 +293,27 @@
}
+bool Api::GetNativeBooleanArgument(Dart_NativeArguments args,
+ int arg_index,
+ bool* value) {
+ NoGCScope no_gc_scope;
+ NativeArguments* arguments = reinterpret_cast<NativeArguments*>(args);
+ RawObject* raw_obj = arguments->NativeArgAt(arg_index);
+ if (raw_obj->IsHeapObject()) {
+ intptr_t cid = raw_obj->GetClassId();
+ if (cid == kBoolCid) {
+ *value = (raw_obj == Object::bool_true().raw());
+ return true;
+ }
+ if (cid == kNullCid) {
+ *value = false;
+ return true;
+ }
+ }
+ return false;
+}
+
+
void Api::SetWeakHandleReturnValue(NativeArguments* args,
Dart_WeakPersistentHandle retval) {
args->SetReturnUnsafe(Api::UnwrapAsWeakPersistentHandle(retval)->raw());
@@ -1033,6 +1054,17 @@
}
+DART_EXPORT bool Dart_HandleServiceMessages() {
+ Isolate* isolate = Isolate::Current();
+ CHECK_ISOLATE_SCOPE(isolate);
+ CHECK_CALLBACK_STATE(isolate);
+ isolate->message_handler()->HandleOOBMessages();
+ // TODO(turnidge): The return value here should indicate whether an
+ // OOB message should cause the program to resume. Implement.
+ return false;
+}
+
+
DART_EXPORT bool Dart_HasLivePorts() {
Isolate* isolate = Isolate::Current();
ASSERT(isolate);
@@ -1055,7 +1087,7 @@
writer.WriteMessage(object);
intptr_t len = writer.BytesWritten();
return PortMap::PostMessage(new Message(
- port_id, Message::kIllegalPort, data, len, Message::kNormalPriority));
+ port_id, data, len, Message::kNormalPriority));
}
@@ -1161,7 +1193,7 @@
DART_EXPORT Dart_Handle Dart_Null() {
Isolate* isolate = Isolate::Current();
- CHECK_ISOLATE_SCOPE(isolate);
+ CHECK_ISOLATE(isolate);
return Api::Null();
}
@@ -1540,21 +1572,21 @@
DART_EXPORT Dart_Handle Dart_True() {
Isolate* isolate = Isolate::Current();
- CHECK_ISOLATE_SCOPE(isolate);
+ CHECK_ISOLATE(isolate);
return Api::True();
}
DART_EXPORT Dart_Handle Dart_False() {
Isolate* isolate = Isolate::Current();
- CHECK_ISOLATE_SCOPE(isolate);
+ CHECK_ISOLATE(isolate);
return Api::False();
}
DART_EXPORT Dart_Handle Dart_NewBoolean(bool value) {
Isolate* isolate = Isolate::Current();
- CHECK_ISOLATE_SCOPE(isolate);
+ CHECK_ISOLATE(isolate);
return value ? Api::True() : Api::False();
}
@@ -3846,21 +3878,10 @@
"%s: argument 'index' out of range. Expected 0..%d but saw %d.",
CURRENT_FUNC, arguments->NativeArgCount() - 1, index);
}
- Isolate* isolate = arguments->isolate();
- ReusableObjectHandleScope reused_obj_handle(isolate);
- Object& obj = reused_obj_handle.Handle();
- obj = arguments->NativeArgAt(index);
- intptr_t cid = obj.GetClassId();
- if (cid == kBoolCid) {
- *value = Bool::Cast(obj).value();
+ if (Api::GetNativeBooleanArgument(args, index, value)) {
return Api::Success();
}
- if (obj.IsNull()) {
- *value = false;
- return Api::Success();
- }
- return Api::NewError(
- "%s: argument %d is not a Boolean argument.",
+ return Api::NewError("%s: argument %d is not a Boolean argument.",
CURRENT_FUNC, index);
}
diff --git a/runtime/vm/dart_api_impl.h b/runtime/vm/dart_api_impl.h
index 762ade4..1cc84a5 100644
--- a/runtime/vm/dart_api_impl.h
+++ b/runtime/vm/dart_api_impl.h
@@ -209,6 +209,11 @@
int arg_index,
void** peer);
+ // Helper function to get the boolean value of a Bool native argument.
+ static bool GetNativeBooleanArgument(Dart_NativeArguments args,
+ int arg_index,
+ bool* value);
+
// Helper function to set the return value of native functions.
static void SetReturnValue(NativeArguments* args, Dart_Handle retval) {
args->SetReturnUnsafe(UnwrapHandle(retval));
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index cb7e97c..6dfbf5c 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -370,7 +370,9 @@
static Dart_NativeFunction CurrentStackTraceNativeLookup(
- Dart_Handle name, int argument_count) {
+ Dart_Handle name, int argument_count, bool* auto_setup_scope) {
+ ASSERT(auto_setup_scope != NULL);
+ *auto_setup_scope = false;
return reinterpret_cast<Dart_NativeFunction>(&CurrentStackTraceNative);
}
@@ -458,7 +460,9 @@
static Dart_NativeFunction PropagateError_native_lookup(
- Dart_Handle name, int argument_count) {
+ Dart_Handle name, int argument_count, bool* auto_setup_scope) {
+ ASSERT(auto_setup_scope != NULL);
+ *auto_setup_scope = false;
return reinterpret_cast<Dart_NativeFunction>(&PropagateErrorNative);
}
@@ -1266,7 +1270,10 @@
static Dart_NativeFunction ByteDataNativeResolver(Dart_Handle name,
- int arg_count) {
+ int arg_count,
+ bool* auto_setup_scope) {
+ ASSERT(auto_setup_scope != NULL);
+ *auto_setup_scope = false;
return &ByteDataNativeFunction;
}
@@ -1324,8 +1331,10 @@
}
-static Dart_NativeFunction ExternalByteDataNativeResolver(Dart_Handle name,
- int arg_count) {
+static Dart_NativeFunction ExternalByteDataNativeResolver(
+ Dart_Handle name, int arg_count, bool* auto_setup_scope) {
+ ASSERT(auto_setup_scope != NULL);
+ *auto_setup_scope = false;
return &ExternalByteDataNativeFunction;
}
@@ -3580,7 +3589,10 @@
static Dart_NativeFunction native_field_lookup(Dart_Handle name,
- int argument_count) {
+ int argument_count,
+ bool* auto_setup_scope) {
+ ASSERT(auto_setup_scope != NULL);
+ *auto_setup_scope = false;
return reinterpret_cast<Dart_NativeFunction>(&NativeFieldLookup);
}
@@ -4744,7 +4756,11 @@
}
-static Dart_NativeFunction native_lookup(Dart_Handle name, int argument_count) {
+static Dart_NativeFunction native_lookup(Dart_Handle name,
+ int argument_count,
+ bool* auto_setup_scope) {
+ ASSERT(auto_setup_scope != NULL);
+ *auto_setup_scope = false;
return reinterpret_cast<Dart_NativeFunction>(&ExceptionNative);
}
@@ -4788,7 +4804,11 @@
}
-static Dart_NativeFunction gnac_lookup(Dart_Handle name, int argument_count) {
+static Dart_NativeFunction gnac_lookup(Dart_Handle name,
+ int argument_count,
+ bool* auto_setup_scope) {
+ ASSERT(auto_setup_scope != NULL);
+ *auto_setup_scope = false;
return reinterpret_cast<Dart_NativeFunction>(&NativeArgumentCounter);
}
@@ -5682,7 +5702,10 @@
static Dart_NativeFunction PatchNativeResolver(Dart_Handle name,
- int arg_count) {
+ int arg_count,
+ bool* auto_setup_scope) {
+ ASSERT(auto_setup_scope != NULL);
+ *auto_setup_scope = false;
return &PatchNativeFunction;
}
@@ -5876,13 +5899,19 @@
static Dart_NativeFunction MyNativeResolver1(Dart_Handle name,
- int arg_count) {
+ int arg_count,
+ bool* auto_setup_scope) {
+ ASSERT(auto_setup_scope != NULL);
+ *auto_setup_scope = false;
return &MyNativeFunction1;
}
static Dart_NativeFunction MyNativeResolver2(Dart_Handle name,
- int arg_count) {
+ int arg_count,
+ bool* auto_setup_scope) {
+ ASSERT(auto_setup_scope != NULL);
+ *auto_setup_scope = false;
return &MyNativeFunction2;
}
@@ -6343,7 +6372,9 @@
static Dart_NativeFunction IsolateInterruptTestNativeLookup(
- Dart_Handle name, int argument_count) {
+ Dart_Handle name, int argument_count, bool* auto_setup_scope) {
+ ASSERT(auto_setup_scope != NULL);
+ *auto_setup_scope = false;
return reinterpret_cast<Dart_NativeFunction>(&MarkMainEntered);
}
@@ -6648,7 +6679,10 @@
static Dart_NativeFunction MyNativeClosureResolver(Dart_Handle name,
- int arg_count) {
+ int arg_count,
+ bool* auto_setup_scope) {
+ ASSERT(auto_setup_scope != NULL);
+ *auto_setup_scope = false;
const Object& obj = Object::Handle(Api::UnwrapHandle(name));
if (!obj.IsString()) {
return NULL;
@@ -6791,8 +6825,10 @@
}
-static Dart_NativeFunction MyStaticNativeClosureResolver(Dart_Handle name,
- int arg_count) {
+static Dart_NativeFunction MyStaticNativeClosureResolver(
+ Dart_Handle name, int arg_count, bool* auto_setup_scope) {
+ ASSERT(auto_setup_scope != NULL);
+ *auto_setup_scope = false;
const Object& obj = Object::Handle(Api::UnwrapHandle(name));
if (!obj.IsString()) {
return NULL;
@@ -7598,7 +7634,9 @@
static Dart_NativeFunction ExternalStringDeoptimize_native_lookup(
- Dart_Handle name, int argument_count) {
+ Dart_Handle name, int argument_count, bool* auto_setup_scope) {
+ ASSERT(auto_setup_scope != NULL);
+ *auto_setup_scope = false;
return reinterpret_cast<Dart_NativeFunction>(&A_change_str_native);
}
diff --git a/runtime/vm/dart_entry.cc b/runtime/vm/dart_entry.cc
index 39e53aa..97dd924 100644
--- a/runtime/vm/dart_entry.cc
+++ b/runtime/vm/dart_entry.cc
@@ -401,20 +401,18 @@
RawObject* DartLibraryCalls::HandleMessage(const Object& receive_port,
- Dart_Port reply_port_id,
const Instance& message) {
Isolate* isolate = Isolate::Current();
- Function& function =
- Function::Handle(isolate,
- isolate->object_store()->handle_message_function());
- const int kNumArguments = 3;
+ Function& function = Function::Handle(isolate,
+ isolate->object_store()->handle_message_function());
+ const int kNumArguments = 2;
if (function.IsNull()) {
- Library& isolate_lib = Library::Handle(Library::IsolateLibrary());
+ Library& isolate_lib = Library::Handle(isolate, Library::IsolateLibrary());
ASSERT(!isolate_lib.IsNull());
- const String& class_name =
- String::Handle(isolate_lib.PrivateName(Symbols::_RawReceivePortImpl()));
- const String& function_name =
- String::Handle(isolate_lib.PrivateName(Symbols::_handleMessage()));
+ const String& class_name = String::Handle(isolate,
+ isolate_lib.PrivateName(Symbols::_RawReceivePortImpl()));
+ const String& function_name = String::Handle(isolate,
+ isolate_lib.PrivateName(Symbols::_handleMessage()));
function = Resolver::ResolveStatic(isolate_lib,
class_name,
function_name,
@@ -425,16 +423,15 @@
}
const Array& args = Array::Handle(isolate, Array::New(kNumArguments));
args.SetAt(0, receive_port);
- args.SetAt(1, Integer::Handle(isolate, Integer::New(reply_port_id)));
- args.SetAt(2, message);
+ args.SetAt(1, message);
if (isolate->debugger()->IsStepping()) {
// If the isolate is being debugged and the debugger was stepping
// through code, enable single stepping so debugger will stop
// at the first location the user is interested in.
isolate->debugger()->SetSingleStep();
}
- const Object& result =
- Object::Handle(isolate, DartEntry::InvokeFunction(function, args));
+ const Object& result = Object::Handle(isolate,
+ DartEntry::InvokeFunction(function, args));
ASSERT(result.IsNull() || result.IsError());
return result.raw();
}
diff --git a/runtime/vm/dart_entry.h b/runtime/vm/dart_entry.h
index 5b3a851..7420e8b 100644
--- a/runtime/vm/dart_entry.h
+++ b/runtime/vm/dart_entry.h
@@ -167,7 +167,6 @@
// Returns null on success, a RawError on failure.
static RawObject* HandleMessage(const Object& receive_port,
- Dart_Port reply_port_id,
const Instance& dart_message);
// On success returns new SendPort, on failure returns a RawError.
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index bd9cbf3..097cee8 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -14,6 +14,7 @@
#include "vm/flags.h"
#include "vm/globals.h"
#include "vm/longjump.h"
+#include "vm/json_stream.h"
#include "vm/object.h"
#include "vm/object_store.h"
#include "vm/os.h"
@@ -27,8 +28,6 @@
namespace dart {
DEFINE_FLAG(bool, verbose_debug, false, "Verbose debugger messages");
-DEFINE_FLAG(bool, use_new_stacktrace, true,
- "Use new stacktrace creation");
Debugger::EventHandler* Debugger::event_handler_ = NULL;
@@ -86,7 +85,7 @@
void SourceBreakpoint::GetCodeLocation(
Library* lib,
Script* script,
- intptr_t* pos) {
+ intptr_t* pos) const {
const Function& func = Function::Handle(function_);
const Class& cls = Class::Handle(func.origin());
*lib = cls.library();
@@ -121,11 +120,39 @@
}
+void SourceBreakpoint::PrintToJSONStream(JSONStream* stream) const {
+ Isolate* isolate = Isolate::Current();
+
+ JSONObject jsobj(stream);
+ jsobj.AddProperty("type", "Breakpoint");
+
+ jsobj.AddProperty("id", id());
+ jsobj.AddProperty("enabled", IsEnabled());
+
+ const Function& func = Function::Handle(function());
+ jsobj.AddProperty("resolved", func.HasCode());
+
+ Library& library = Library::Handle(isolate);
+ Script& script = Script::Handle(isolate);
+ intptr_t token_pos;
+ GetCodeLocation(&library, &script, &token_pos);
+ {
+ JSONObject location(&jsobj, "location");
+ location.AddProperty("type", "Location");
+ location.AddProperty("libId", library.index());
+
+ const String& url = String::Handle(script.url());
+ location.AddProperty("script", url.ToCString());
+ location.AddProperty("tokenPos", token_pos);
+ }
+}
+
void CodeBreakpoint::VisitObjectPointers(ObjectPointerVisitor* visitor) {
visitor->VisitPointer(reinterpret_cast<RawObject**>(&function_));
}
+
ActivationFrame::ActivationFrame(
uword pc,
uword fp,
@@ -221,6 +248,15 @@
}
+void Debugger::PrintBreakpointsToJSONArray(JSONArray* jsarr) const {
+ SourceBreakpoint* sbpt = src_breakpoints_;
+ while (sbpt != NULL) {
+ jsarr->AddValue(sbpt);
+ sbpt = sbpt->next_;
+ }
+}
+
+
RawString* ActivationFrame::QualifiedFunctionName() {
return String::New(Debugger::QualifiedFunctionName(function()));
}
@@ -366,23 +402,7 @@
}
-// Get the caller's context, or return ctx if the function does not
-// save the caller's context on entry.
-RawContext* ActivationFrame::GetSavedEntryContext(const Context& ctx) {
- GetVarDescriptors();
- intptr_t var_desc_len = var_descriptors_.Length();
- for (intptr_t i = 0; i < var_desc_len; i++) {
- RawLocalVarDescriptors::VarInfo var_info;
- var_descriptors_.GetInfo(i, &var_info);
- if (var_info.kind == RawLocalVarDescriptors::kSavedEntryContext) {
- return GetLocalContextVar(var_info.index);
- }
- }
- return ctx.raw();
-}
-
-
-RawContext* ActivationFrame::GetSavedEntryContextNew() {
+RawContext* ActivationFrame::GetSavedEntryContext() {
if (ctx_.IsNull()) {
// We have bailed on providing a context for this frame. Bail for
// the caller as well.
@@ -466,15 +486,6 @@
}
GetVarDescriptors();
- // We don't trust variable descriptors in optimized code.
- // Rather than potentially displaying incorrect values, we
- // pretend that there are no variables in the frame.
- // We should be more clever about this in the future.
- if (!FLAG_use_new_stacktrace && code().is_optimized()) {
- vars_initialized_ = true;
- return;
- }
-
intptr_t activation_token_pos = TokenPos();
if (activation_token_pos < 0) {
// We don't have a token position for this frame, so can't determine
@@ -598,28 +609,15 @@
ASSERT(var_info.kind == RawLocalVarDescriptors::kContextVar);
// The context level at the PC/token index of this activation frame.
intptr_t frame_ctx_level = ContextLevel();
- if (ctx_.IsNull()) {
- if (FLAG_use_new_stacktrace) {
- UNREACHABLE(); // ctx_ should never be null.
- }
- *value = Symbols::New("<unknown>");
- return;
- }
+ ASSERT(!ctx_.IsNull());
+
// The context level of the variable.
intptr_t var_ctx_level = var_info.scope_id;
intptr_t level_diff = frame_ctx_level - var_ctx_level;
intptr_t ctx_slot = var_info.index;
if (level_diff == 0) {
- // TODO(12767) : Need to ensure that we end up with the correct context
- // here so that this check can be an assert.
- if ((ctx_slot < ctx_.num_variables()) && (ctx_slot >= 0)) {
- *value = ctx_.At(ctx_slot);
- } else {
- if (FLAG_use_new_stacktrace) {
- UNREACHABLE(); // ctx_ should be correct.
- }
- *value = Symbols::New("<unknown>");
- }
+ ASSERT((ctx_slot >= 0) && (ctx_slot < ctx_.num_variables()));
+ *value = ctx_.At(ctx_slot);
} else {
ASSERT(level_diff > 0);
Context& var_ctx = Context::Handle(ctx_.raw());
@@ -627,17 +625,9 @@
level_diff--;
var_ctx = var_ctx.parent();
}
- // TODO(12767) : Need to ensure that we end up with the correct context
- // here so that this check can be assert.
- if (!var_ctx.IsNull() &&
- ((ctx_slot < var_ctx.num_variables()) && (ctx_slot >= 0))) {
- *value = var_ctx.At(ctx_slot);
- } else {
- if (FLAG_use_new_stacktrace) {
- UNREACHABLE(); // var_ctx should be correct.
- }
- *value = Symbols::New("<unknown>");
- }
+ ASSERT(!var_ctx.IsNull());
+ ASSERT((ctx_slot >= 0) && (ctx_slot < var_ctx.num_variables()));
+ *value = var_ctx.At(ctx_slot);
}
}
}
@@ -1050,25 +1040,6 @@
}
-static void PrintStackTraceError(const char* message,
- ActivationFrame* current_activation,
- ActivationFrame* callee_activation) {
- const Function& current = current_activation->function();
- const Function& callee = callee_activation->function();
- const Script& script =
- Script::Handle(Class::Handle(current.Owner()).script());
- intptr_t line, col;
- script.GetTokenLocation(current_activation->TokenPos(), &line, &col);
- OS::PrintErr("Error building stack trace: %s:"
- "current function '%s' callee_function '%s' "
- " line %" Pd " column %" Pd "\n",
- message,
- current.ToFullyQualifiedCString(),
- callee.ToFullyQualifiedCString(),
- line, col);
-}
-
-
ActivationFrame* Debugger::CollectDartFrame(Isolate* isolate,
uword pc,
StackFrame* frame,
@@ -1095,26 +1066,15 @@
// in the current frame before making the call.
const Context& closure_call_ctx =
Context::Handle(isolate, activation->GetSavedCurrentContext());
+ ASSERT(!closure_call_ctx.IsNull());
activation->SetContext(closure_call_ctx);
- // Sometimes there is no saved context. This is a bug.
- // https://code.google.com/p/dart/issues/detail?id=12767
- if ((FLAG_verbose_debug || FLAG_use_new_stacktrace) &&
- closure_call_ctx.IsNull()) {
- PrintStackTraceError(
- "Expected to find saved context for call to closure function",
- activation, callee_activation);
- if (FLAG_use_new_stacktrace) {
- UNREACHABLE(); // This bug should be fixed with new stack collection.
- }
- }
-
} else {
// Use the context provided by our callee. This is either the
// callee's context or a context that was saved in the callee's
// frame.
const Context& callee_ctx =
- Context::Handle(isolate, callee_activation->GetSavedEntryContextNew());
+ Context::Handle(isolate, callee_activation->GetSavedEntryContext());
activation->SetContext(callee_ctx);
}
return activation;
@@ -1144,7 +1104,7 @@
}
-DebuggerStackTrace* Debugger::CollectStackTraceNew() {
+DebuggerStackTrace* Debugger::CollectStackTrace() {
Isolate* isolate = Isolate::Current();
DebuggerStackTrace* stack_trace = new DebuggerStackTrace(8);
StackFrameIterator iterator(false);
@@ -1200,70 +1160,6 @@
}
-
-DebuggerStackTrace* Debugger::CollectStackTrace() {
- if (FLAG_use_new_stacktrace) {
- // Guard new stack trace generation under a flag in case there are
- // problems rolling it out.
- return CollectStackTraceNew();
- }
- Isolate* isolate = Isolate::Current();
- DebuggerStackTrace* stack_trace = new DebuggerStackTrace(8);
- Context& ctx = Context::Handle(isolate->top_context());
- Code& code = Code::Handle(isolate);
- StackFrameIterator iterator(false);
- ActivationFrame* callee_activation = NULL;
- bool optimized_frame_found = false;
- for (StackFrame* frame = iterator.NextFrame();
- frame != NULL;
- frame = iterator.NextFrame()) {
- ASSERT(frame->IsValid());
- if (frame->IsDartFrame()) {
- code = frame->LookupDartCode();
- ActivationFrame* activation =
- new ActivationFrame(frame->pc(), frame->fp(), frame->sp(), code,
- Object::null_array(), 0);
- // If this activation frame called a closure, the function has
- // saved its context before the call.
- if ((callee_activation != NULL) &&
- (callee_activation->function().IsClosureFunction())) {
- ctx = activation->GetSavedCurrentContext();
- if (FLAG_verbose_debug && ctx.IsNull()) {
- const Function& caller = activation->function();
- const Function& callee = callee_activation->function();
- const Script& script =
- Script::Handle(Class::Handle(caller.Owner()).script());
- intptr_t line, col;
- script.GetTokenLocation(activation->TokenPos(), &line, &col);
- OS::Print("CollectStackTrace error: no saved context in function "
- "'%s' which calls closure '%s' "
- " in line %" Pd " column %" Pd "\n",
- caller.ToFullyQualifiedCString(),
- callee.ToFullyQualifiedCString(),
- line, col);
- }
- }
- if (optimized_frame_found || code.is_optimized()) {
- // Set context to null, to avoid returning bad context variable values.
- activation->SetContext(Context::Handle());
- optimized_frame_found = true;
- } else {
- ASSERT(!ctx.IsNull());
- activation->SetContext(ctx);
- }
- stack_trace->AddActivation(activation);
- callee_activation = activation;
- // Get caller's context if this function saved it on entry.
- ctx = activation->GetSavedEntryContext(ctx);
- } else if (frame->IsEntryFrame()) {
- ctx = reinterpret_cast<EntryFrame*>(frame)->SavedContext();
- callee_activation = NULL;
- }
- }
- return stack_trace;
-}
-
-
ActivationFrame* Debugger::TopDartFrame() const {
StackFrameIterator iterator(false);
StackFrame* frame = iterator.NextFrame();
@@ -1283,7 +1179,7 @@
}
DebuggerStackTrace* Debugger::CurrentStackTrace() {
- return CollectStackTraceNew();
+ return CollectStackTrace();
}
DebuggerStackTrace* Debugger::StackTraceFrom(const Stacktrace& ex_trace) {
@@ -1588,7 +1484,7 @@
SourceBreakpoint* Debugger::SetBreakpointAtLine(const String& script_url,
- intptr_t line_number) {
+ intptr_t line_number) {
Library& lib = Library::Handle(isolate_);
Script& script = Script::Handle(isolate_);
const GrowableObjectArray& libs =
diff --git a/runtime/vm/debugger.h b/runtime/vm/debugger.h
index f70debf..c484b56 100644
--- a/runtime/vm/debugger.h
+++ b/runtime/vm/debugger.h
@@ -15,6 +15,8 @@
class ActiveVariables;
class CodeBreakpoint;
class Isolate;
+class JSONArray;
+class JSONStream;
class ObjectPointerVisitor;
class RemoteObjectCache;
class SourceBreakpoint;
@@ -36,12 +38,16 @@
RawString* SourceUrl();
intptr_t LineNumber();
- void GetCodeLocation(Library* lib, Script* script, intptr_t* token_pos);
+ void GetCodeLocation(Library* lib,
+ Script* script,
+ intptr_t* token_pos) const;
void Enable();
void Disable();
bool IsEnabled() const { return is_enabled_; }
+ void PrintToJSONStream(JSONStream* stream) const;
+
private:
void VisitObjectPointers(ObjectPointerVisitor* visitor);
@@ -167,8 +173,7 @@
Instance* value);
RawArray* GetLocalVariables();
- RawContext* GetSavedEntryContext(const Context& ctx);
- RawContext* GetSavedEntryContextNew();
+ RawContext* GetSavedEntryContext();
RawContext* GetSavedCurrentContext();
private:
@@ -353,6 +358,8 @@
uword GetPatchedStubAddress(uword breakpoint_address);
+ void PrintBreakpointsToJSONArray(JSONArray* jsarr) const;
+
static bool IsDebuggable(const Function& func);
private:
@@ -386,7 +393,6 @@
void SyncBreakpoint(SourceBreakpoint* bpt);
ActivationFrame* TopDartFrame() const;
- static DebuggerStackTrace* CollectStackTrace();
static ActivationFrame* CollectDartFrame(Isolate* isolate,
uword pc,
StackFrame* frame,
@@ -398,7 +404,7 @@
static RawArray* DeoptimizeToArray(Isolate* isolate,
StackFrame* frame,
const Code& code);
- static DebuggerStackTrace* CollectStackTraceNew();
+ static DebuggerStackTrace* CollectStackTrace();
void SignalBpResolved(SourceBreakpoint *bpt);
void SignalPausedEvent(ActivationFrame* top_frame,
SourceBreakpoint* bpt);
diff --git a/runtime/vm/debugger_api_impl.cc b/runtime/vm/debugger_api_impl.cc
index a2ec598..01676eb 100644
--- a/runtime/vm/debugger_api_impl.cc
+++ b/runtime/vm/debugger_api_impl.cc
@@ -973,6 +973,12 @@
}
+DART_EXPORT Dart_IsolateId Dart_GetIsolateId(Dart_Isolate dart_isolate) {
+ Isolate* isolate = reinterpret_cast<Isolate*>(dart_isolate);
+ return isolate->debugger()->GetIsolateId();
+}
+
+
DART_EXPORT char* Dart_GetVmStatus(const char* request) {
if (strncmp(request, "/isolate/", 9) == 0) {
return Isolate::GetStatus(request);
diff --git a/runtime/vm/debugger_api_impl_test.cc b/runtime/vm/debugger_api_impl_test.cc
index 9089e5c..c4e07a5 100644
--- a/runtime/vm/debugger_api_impl_test.cc
+++ b/runtime/vm/debugger_api_impl_test.cc
@@ -1300,6 +1300,7 @@
EXPECT_VALID(retval);
EXPECT(test_isolate_id != ILLEGAL_ISOLATE_ID);
EXPECT(Dart_GetIsolate(test_isolate_id) == isolate);
+ EXPECT(Dart_GetIsolateId(isolate) == test_isolate_id);
Dart_ExitScope();
Dart_ShutdownIsolate();
EXPECT(verify_callback == 0x5); // Only created and shutdown events.
@@ -1349,7 +1350,10 @@
static Dart_NativeFunction InterruptNativeResolver(Dart_Handle name,
- int arg_count) {
+ int arg_count,
+ bool* auto_setup_scope) {
+ ASSERT(auto_setup_scope != NULL);
+ *auto_setup_scope = false;
return &InterruptNativeFunction;
}
diff --git a/runtime/vm/debugger_test.cc b/runtime/vm/debugger_test.cc
new file mode 100644
index 0000000..17f1780
--- /dev/null
+++ b/runtime/vm/debugger_test.cc
@@ -0,0 +1,57 @@
+// 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.
+
+#include "vm/debugger.h"
+#include "vm/unit_test.h"
+
+namespace dart {
+
+TEST_CASE(Debugger_PrintBreakpointsToJSONArray) {
+ const char* kScriptChars =
+ "void main() {\n"
+ " print('won');\n"
+ " print('too');\n"
+ " print('free');\n"
+ " print('for');\n"
+ "}\n";
+ Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
+ EXPECT_VALID(lib);
+
+ Isolate* isolate = Isolate::Current();
+ Debugger* debugger = isolate->debugger();
+ const String& url = String::Handle(String::New(TestCase::url()));
+
+ // Empty case.
+ {
+ JSONStream js;
+ {
+ JSONArray jsarr(&js);
+ debugger->PrintBreakpointsToJSONArray(&jsarr);
+ }
+ EXPECT_STREQ("[]", js.ToCString());
+ }
+
+ // Test with a couple of breakpoints.
+ debugger->SetBreakpointAtLine(url, 2);
+ debugger->SetBreakpointAtLine(url, 3);
+ {
+ JSONStream js;
+ {
+ JSONArray jsarr(&js);
+ debugger->PrintBreakpointsToJSONArray(&jsarr);
+ }
+ EXPECT_STREQ(
+ "[{\"type\":\"Breakpoint\",\"id\":2,"
+ "\"enabled\":true,\"resolved\":false,"
+ "\"location\":{\"type\":\"Location\",\"libId\":12,"
+ "\"script\":\"dart:test-lib\",\"tokenPos\":12}},"
+ "{\"type\":\"Breakpoint\",\"id\":1,"
+ "\"enabled\":true,\"resolved\":false,"
+ "\"location\":{\"type\":\"Location\",\"libId\":12,"
+ "\"script\":\"dart:test-lib\",\"tokenPos\":6}}]",
+ js.ToCString());
+ }
+}
+
+} // namespace dart
diff --git a/runtime/vm/exceptions_test.cc b/runtime/vm/exceptions_test.cc
index 6586435..e3138a3 100644
--- a/runtime/vm/exceptions_test.cc
+++ b/runtime/vm/exceptions_test.cc
@@ -76,7 +76,10 @@
static Dart_NativeFunction native_lookup(Dart_Handle name,
- int argument_count) {
+ int argument_count,
+ bool* auto_setup_scope) {
+ ASSERT(auto_setup_scope != NULL);
+ *auto_setup_scope = false;
const Object& obj = Object::Handle(Api::UnwrapHandle(name));
ASSERT(obj.IsString());
const char* function_name = obj.ToCString();
diff --git a/runtime/vm/flow_graph_allocator.cc b/runtime/vm/flow_graph_allocator.cc
index f40c175..b59a05b 100644
--- a/runtime/vm/flow_graph_allocator.cc
+++ b/runtime/vm/flow_graph_allocator.cc
@@ -122,6 +122,7 @@
}
// Handle uses.
+ current->InitializeLocationSummary(true); // Optimizing.
LocationSummary* locs = current->locs();
ASSERT(locs->input_count() == current->InputCount());
for (intptr_t j = 0; j < current->InputCount(); j++) {
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index 848a632..fb064ba 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -3175,7 +3175,6 @@
}
}
InlineBailout("EffectGraphVisitor::VisitNativeBodyNode");
- function.set_is_optimizable(false);
NativeCallInstr* native_call = new NativeCallInstr(node);
ReturnDefinition(native_call);
}
@@ -3285,18 +3284,12 @@
new StoreInstanceFieldInstr(node->field(),
for_instance.value(),
store_value,
- kEmitStoreBarrier);
+ kEmitStoreBarrier,
+ true); // Maybe initializing store.
ReturnDefinition(store);
}
-// StoreInstanceFieldNode does not return result.
-void ValueGraphVisitor::VisitStoreInstanceFieldNode(
- StoreInstanceFieldNode* node) {
- UNIMPLEMENTED();
-}
-
-
void EffectGraphVisitor::VisitLoadStaticFieldNode(LoadStaticFieldNode* node) {
if (node->field().is_const()) {
ASSERT(node->field().value() != Object::sentinel().raw());
diff --git a/runtime/vm/flow_graph_builder.h b/runtime/vm/flow_graph_builder.h
index f9adcd6..ead8e24 100644
--- a/runtime/vm/flow_graph_builder.h
+++ b/runtime/vm/flow_graph_builder.h
@@ -454,7 +454,6 @@
virtual void VisitLoadLocalNode(LoadLocalNode* node);
virtual void VisitStoreLocalNode(StoreLocalNode* node);
virtual void VisitStoreIndexedNode(StoreIndexedNode* node);
- virtual void VisitStoreInstanceFieldNode(StoreInstanceFieldNode* node);
virtual void VisitInstanceSetterNode(InstanceSetterNode* node);
virtual void VisitThrowNode(ThrowNode* node);
virtual void VisitClosureCallNode(ClosureCallNode* node);
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index 9f99579..2e90989b 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -131,7 +131,9 @@
if ((ic_data != NULL) && (ic_data->NumberOfChecks() == 0)) {
may_reoptimize_ = true;
}
- if (is_leaf && !current->IsCheckStackOverflow()) {
+ if (is_leaf &&
+ !current->IsCheckStackOverflow() &&
+ !current->IsParallelMove()) {
// Note that we do not care if the code contains instructions that
// can deoptimize.
LocationSummary* locs = current->locs();
@@ -267,7 +269,6 @@
if (instr->IsParallelMove()) {
parallel_move_resolver_.EmitNativeCode(instr->AsParallelMove());
} else {
- ASSERT(instr->locs() != NULL);
EmitInstructionPrologue(instr);
ASSERT(pending_deoptimization_env_ == NULL);
pending_deoptimization_env_ = instr->env();
@@ -636,7 +637,11 @@
ASSERT(return_node.value()->IsLoadInstanceFieldNode());
const LoadInstanceFieldNode& load_node =
*return_node.value()->AsLoadInstanceFieldNode();
- GenerateInlinedGetter(load_node.field().Offset());
+ // Only intrinsify getter if the field cannot contain a mutable double.
+ // Reading from a mutable double box requires allocating a fresh double.
+ if (load_node.field().guarded_cid() == kDynamicCid) {
+ GenerateInlinedGetter(load_node.field().Offset());
+ }
return;
}
if (parsed_function().function().kind() == RawFunction::kImplicitSetter) {
@@ -819,6 +824,7 @@
void FlowGraphCompiler::AllocateRegistersLocally(Instruction* instr) {
ASSERT(!is_optimizing());
+ instr->InitializeLocationSummary(false); // Not optimizing.
LocationSummary* locs = instr->locs();
bool blocked_registers[kNumberOfCpuRegisters];
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index f4bc5f9..f8d4182 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -1037,7 +1037,7 @@
void FlowGraphCompiler::EmitFrameEntry() {
const Function& function = parsed_function().function();
if (CanOptimizeFunction() &&
- function.is_optimizable() &&
+ function.IsOptimizable() &&
(!is_optimizing() || may_reoptimize())) {
const Register function_reg = R6;
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index a1661e0..807e6e4 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -1064,7 +1064,7 @@
void FlowGraphCompiler::EmitFrameEntry() {
const Function& function = parsed_function().function();
if (CanOptimizeFunction() &&
- function.is_optimizable() &&
+ function.IsOptimizable() &&
(!is_optimizing() || may_reoptimize())) {
const Register function_reg = EDI;
__ LoadObject(function_reg, function);
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index c615a12..f524363 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -1065,7 +1065,7 @@
void FlowGraphCompiler::EmitFrameEntry() {
const Function& function = parsed_function().function();
if (CanOptimizeFunction() &&
- function.is_optimizable() &&
+ function.IsOptimizable() &&
(!is_optimizing() || may_reoptimize())) {
const Register function_reg = T0;
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index 9a28abd..496ea0a 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -1046,7 +1046,7 @@
Register new_pp = kNoRegister;
Register new_pc = kNoRegister;
if (CanOptimizeFunction() &&
- function.is_optimizable() &&
+ function.IsOptimizable() &&
(!is_optimizing() || may_reoptimize())) {
const Register function_reg = RDI;
new_pp = R13;
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index dd798b8..c6e88b6 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -1065,7 +1065,7 @@
bool PolymorphicInliner::TryInlining(intptr_t receiver_cid,
const Function& target) {
- if (!target.is_optimizable()) {
+ if (!target.IsOptimizable()) {
if (TryInlineRecognizedMethod(receiver_cid, target)) {
owner_->inlined_ = true;
return true;
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index 9e89082..74f9080 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -41,6 +41,8 @@
"Print live sets for load optimization pass.");
DEFINE_FLAG(bool, enable_simd_inline, true,
"Enable inlining of SIMD related method calls.");
+DEFINE_FLAG(int, getter_setter_ratio, 10,
+ "Ratio of getter/setter usage used for double field unboxing heuristics");
DECLARE_FLAG(bool, eliminate_type_checks);
DECLARE_FLAG(bool, enable_type_checks);
DECLARE_FLAG(bool, trace_type_check_elimination);
@@ -62,9 +64,12 @@
}
-// Optimize instance calls using cid.
+// Optimize instance calls using cid. This is called after optimizer
+// converted instance calls to instructions. Any remaining
+// instance calls are either megamorphic calls, cannot be optimized or
+// have no runtime type feedback collected.
// Attempts to convert an instance call (IC call) using propagated class-ids,
-// e.g., receiver class id, guarded-cid.
+// e.g., receiver class id, guarded-cid, or by guessing cid-s.
void FlowGraphOptimizer::ApplyClassIds() {
ASSERT(current_iterator_ == NULL);
for (intptr_t i = 0; i < block_order_.length(); ++i) {
@@ -96,20 +101,42 @@
}
+// TODO(srdjan): Test/support other number types as well.
+static bool IsNumberCid(intptr_t cid) {
+ return (cid == kSmiCid) || (cid == kDoubleCid);
+}
+
+
// Attempt to build ICData for call using propagated class-ids.
bool FlowGraphOptimizer::TryCreateICData(InstanceCallInstr* call) {
ASSERT(call->HasICData());
if (call->ic_data()->NumberOfChecks() > 0) {
- // This occurs when an instance call has too many checks.
+ // This occurs when an instance call has too many checks, will be converted
+ // to megamorphic call.
return false;
}
GrowableArray<intptr_t> class_ids(call->ic_data()->num_args_tested());
ASSERT(call->ic_data()->num_args_tested() <= call->ArgumentCount());
for (intptr_t i = 0; i < call->ic_data()->num_args_tested(); i++) {
- intptr_t cid = call->PushArgumentAt(i)->value()->Type()->ToCid();
+ const intptr_t cid = call->PushArgumentAt(i)->value()->Type()->ToCid();
class_ids.Add(cid);
}
+ const Token::Kind op_kind = call->token_kind();
+ if (Token::IsRelationalOperator(op_kind) ||
+ Token::IsRelationalOperator(op_kind) ||
+ Token::IsBinaryOperator(op_kind)) {
+ // Guess cid: if one of the inputs is a number assume that the other
+ // is a number of same type.
+ const intptr_t cid_0 = class_ids[0];
+ const intptr_t cid_1 = class_ids[1];
+ if ((cid_0 == kDynamicCid) && (IsNumberCid(cid_1))) {
+ class_ids[0] = cid_1;
+ } else if (IsNumberCid(cid_0) && (cid_1 == kDynamicCid)) {
+ class_ids[1] = cid_0;
+ }
+ }
+
for (intptr_t i = 0; i < class_ids.length(); i++) {
if (class_ids[i] == kDynamicCid) {
// Not all cid-s known.
@@ -3506,6 +3533,40 @@
}
+void FlowGraphOptimizer::VisitStoreInstanceField(
+ StoreInstanceFieldInstr* instr) {
+ if (instr->IsUnboxedStore()) {
+ ASSERT(instr->is_initialization_);
+ // Determine if this field should be unboxed based on the usage of getter
+ // and setter functions: The heuristic requires that the setter has a
+ // usage count of at least 1/kGetterSetterRatio of the getter usage count.
+ // This is to avoid unboxing fields where the setter is never or rarely
+ // executed.
+ const Field& field = Field::ZoneHandle(instr->field().raw());
+ const String& field_name = String::Handle(field.name());
+ class Class& owner = Class::Handle(field.owner());
+ const Function& getter =
+ Function::Handle(owner.LookupGetterFunction(field_name));
+ const Function& setter =
+ Function::Handle(owner.LookupSetterFunction(field_name));
+ bool result = !getter.IsNull()
+ && !setter.IsNull()
+ && (setter.usage_counter() > 0)
+ && (FLAG_getter_setter_ratio * setter.usage_counter() >
+ getter.usage_counter());
+ if (!result) {
+ if (FLAG_trace_optimization) {
+ OS::Print("Disabling unboxing of %s\n", field.ToCString());
+ }
+ field.set_is_unboxing_candidate(false);
+ field.DeoptimizeDependentCode();
+ } else {
+ FlowGraph::AddToGuardedFields(flow_graph_->guarded_fields(), &field);
+ }
+ }
+}
+
+
bool FlowGraphOptimizer::TryInlineInstanceSetter(InstanceCallInstr* instr,
const ICData& unary_ic_data) {
ASSERT((unary_ic_data.NumberOfChecks() > 0) &&
@@ -3536,7 +3597,7 @@
// Inline implicit instance setter.
const String& field_name =
String::Handle(Field::NameFromSetter(instr->function_name()));
- const Field& field = Field::Handle(GetField(class_id, field_name));
+ const Field& field = Field::ZoneHandle(GetField(class_id, field_name));
ASSERT(!field.IsNull());
if (InstanceCallNeedsClassCheck(instr)) {
@@ -3567,6 +3628,11 @@
new Value(instr->ArgumentAt(0)),
new Value(instr->ArgumentAt(1)),
needs_store_barrier);
+
+ if (store->IsUnboxedStore()) {
+ FlowGraph::AddToGuardedFields(flow_graph_->guarded_fields(), &field);
+ }
+
// Discard the environment from the original instruction because the store
// can't deoptimize.
instr->RemoveEnvironment();
@@ -4373,9 +4439,12 @@
}
if (inputs_loop_invariant &&
!current->IsAssertAssignable() &&
- !current->IsAssertBoolean()) {
+ !current->IsAssertBoolean() &&
+ !current->IsGuardField()) {
// TODO(fschneider): Enable hoisting of Assert-instructions
// if it safe to do.
+ // TODO(15652): Hoisting guard-field instructions causes the
+ // optimizing compiler to crash.
Hoist(&it, pre_header, current);
} else if (current->IsCheckSmi() &&
current->InputAt(0)->definition()->IsPhi()) {
@@ -6605,7 +6674,37 @@
void ConstantPropagator::VisitLoadIndexed(LoadIndexedInstr* instr) {
- SetValue(instr, non_constant_);
+ const Object& array_obj = instr->array()->definition()->constant_value();
+ const Object& index_obj = instr->index()->definition()->constant_value();
+ if (IsNonConstant(array_obj) || IsNonConstant(index_obj)) {
+ SetValue(instr, non_constant_);
+ } else if (IsConstant(array_obj) && IsConstant(index_obj)) {
+ // Need index to be Smi and array to be either String or an immutable array.
+ if (!index_obj.IsSmi()) {
+ // Should not occur.
+ SetValue(instr, non_constant_);
+ return;
+ }
+ const intptr_t index = Smi::Cast(index_obj).Value();
+ if (index >= 0) {
+ if (array_obj.IsString()) {
+ const String& str = String::Cast(array_obj);
+ if (str.Length() > index) {
+ SetValue(instr, Smi::Handle(Smi::New(str.CharAt(index))));
+ return;
+ }
+ } else if (array_obj.IsArray()) {
+ const Array& a = Array::Cast(array_obj);
+ if ((a.Length() > index) && a.IsImmutable()) {
+ Instance& result = Instance::Handle();
+ result ^= a.At(index);
+ SetValue(instr, result);
+ return;
+ }
+ }
+ }
+ SetValue(instr, non_constant_);
+ }
}
diff --git a/runtime/vm/flow_graph_optimizer.h b/runtime/vm/flow_graph_optimizer.h
index c473514..0f611df 100644
--- a/runtime/vm/flow_graph_optimizer.h
+++ b/runtime/vm/flow_graph_optimizer.h
@@ -59,6 +59,7 @@
virtual void VisitStaticCall(StaticCallInstr* instr);
virtual void VisitInstanceCall(InstanceCallInstr* instr);
+ virtual void VisitStoreInstanceField(StoreInstanceFieldInstr* instr);
void InsertBefore(Instruction* next,
Instruction* instr,
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
index 249bcf1..9fecfe9 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -758,7 +758,7 @@
CompileType* value_type = value()->Type();
if (value_type->IsMoreSpecificThan(dst_type())) {
- return value_type;
+ return ZoneCompileType::Wrap(*value_type);
}
if (dst_type().IsVoidType()) {
@@ -772,13 +772,9 @@
bool AssertAssignableInstr::RecomputeType() {
CompileType* value_type = value()->Type();
- if (value_type == Type()) {
- return false;
- }
-
return UpdateType(value_type->IsMoreSpecificThan(dst_type())
- ? *value_type
- : CompileType::FromAbstractType(dst_type()));
+ ? *value_type
+ : CompileType::FromAbstractType(dst_type()));
}
@@ -820,17 +816,23 @@
CompileType CurrentContextInstr::ComputeType() const {
- return CompileType::FromCid(kContextCid);
+ return CompileType(CompileType::kNonNullable,
+ kContextCid,
+ &AbstractType::ZoneHandle(Type::DynamicType()));
}
CompileType CloneContextInstr::ComputeType() const {
- return CompileType::FromCid(kContextCid);
+ return CompileType(CompileType::kNonNullable,
+ kContextCid,
+ &AbstractType::ZoneHandle(Type::DynamicType()));
}
CompileType AllocateContextInstr::ComputeType() const {
- return CompileType::FromCid(kContextCid);
+ return CompileType(CompileType::kNonNullable,
+ kContextCid,
+ &AbstractType::ZoneHandle(Type::DynamicType()));
}
diff --git a/runtime/vm/il_printer.cc b/runtime/vm/il_printer.cc
index 7af39e3..05995dd 100644
--- a/runtime/vm/il_printer.cc
+++ b/runtime/vm/il_printer.cc
@@ -79,7 +79,7 @@
if (FLAG_print_environments && (instr->env() != NULL)) {
instr->env()->PrintTo(&f);
}
- if (print_locations && (instr->locs() != NULL)) {
+ if (print_locations && (instr->locs_ != NULL)) {
instr->locs()->PrintTo(&f);
}
if (instr->lifetime_position() != -1) {
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index edc727e..ed4f5c4 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -26,6 +26,7 @@
DEFINE_FLAG(bool, propagate_ic_data, true,
"Propagate IC data from unoptimized to optimized IC calls.");
+DEFINE_FLAG(bool, unbox_double_fields, true, "Support unboxed double fields.");
DECLARE_FLAG(bool, enable_type_checks);
DECLARE_FLAG(bool, eliminate_type_checks);
DECLARE_FLAG(bool, trace_optimization);
@@ -136,6 +137,30 @@
}
+bool LoadFieldInstr::IsUnboxedLoad() const {
+ return FLAG_unbox_double_fields
+ && (field() != NULL)
+ && field()->IsUnboxedField();
+}
+
+
+bool LoadFieldInstr::IsPotentialUnboxedLoad() const {
+ return FLAG_unbox_double_fields
+ && (field() != NULL)
+ && field()->IsPotentialUnboxedField();
+}
+
+
+bool StoreInstanceFieldInstr::IsUnboxedStore() const {
+ return FLAG_unbox_double_fields && field().IsUnboxedField();
+}
+
+
+bool StoreInstanceFieldInstr::IsPotentialUnboxedStore() const {
+ return FLAG_unbox_double_fields && field().IsPotentialUnboxedField();
+}
+
+
bool GuardFieldInstr::AttributesEqual(Instruction* other) const {
return field().raw() == other->AsGuardField()->field().raw();
}
@@ -1757,13 +1782,13 @@
#define __ compiler->assembler()->
-LocationSummary* GraphEntryInstr::MakeLocationSummary() const {
+LocationSummary* GraphEntryInstr::MakeLocationSummary(bool optimizing) const {
UNREACHABLE();
return NULL;
}
-LocationSummary* JoinEntryInstr::MakeLocationSummary() const {
+LocationSummary* JoinEntryInstr::MakeLocationSummary(bool optimizing) const {
UNREACHABLE();
return NULL;
}
@@ -1782,7 +1807,7 @@
}
-LocationSummary* TargetEntryInstr::MakeLocationSummary() const {
+LocationSummary* TargetEntryInstr::MakeLocationSummary(bool optimizing) const {
// FlowGraphCompiler::EmitInstructionPrologue is not called for block
// entry instructions, so this function is unused. If it becomes
// reachable, note that the deoptimization descriptor in unoptimized code
@@ -1794,7 +1819,7 @@
}
-LocationSummary* PhiInstr::MakeLocationSummary() const {
+LocationSummary* PhiInstr::MakeLocationSummary(bool optimizing) const {
UNREACHABLE();
return NULL;
}
@@ -1805,7 +1830,7 @@
}
-LocationSummary* RedefinitionInstr::MakeLocationSummary() const {
+LocationSummary* RedefinitionInstr::MakeLocationSummary(bool optimizing) const {
UNREACHABLE();
return NULL;
}
@@ -1816,7 +1841,7 @@
}
-LocationSummary* ParameterInstr::MakeLocationSummary() const {
+LocationSummary* ParameterInstr::MakeLocationSummary(bool optimizing) const {
UNREACHABLE();
return NULL;
}
@@ -1827,7 +1852,7 @@
}
-LocationSummary* ParallelMoveInstr::MakeLocationSummary() const {
+LocationSummary* ParallelMoveInstr::MakeLocationSummary(bool optimizing) const {
return NULL;
}
@@ -1837,7 +1862,7 @@
}
-LocationSummary* ConstraintInstr::MakeLocationSummary() const {
+LocationSummary* ConstraintInstr::MakeLocationSummary(bool optimizing) const {
UNREACHABLE();
return NULL;
}
@@ -1848,7 +1873,8 @@
}
-LocationSummary* MaterializeObjectInstr::MakeLocationSummary() const {
+LocationSummary* MaterializeObjectInstr::MakeLocationSummary(
+ bool optimizing) const {
UNREACHABLE();
return NULL;
}
@@ -1859,7 +1885,7 @@
}
-LocationSummary* StoreContextInstr::MakeLocationSummary() const {
+LocationSummary* StoreContextInstr::MakeLocationSummary(bool optimizing) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -1869,7 +1895,7 @@
}
-LocationSummary* PushTempInstr::MakeLocationSummary() const {
+LocationSummary* PushTempInstr::MakeLocationSummary(bool optimizing) const {
return LocationSummary::Make(1,
Location::NoLocation(),
LocationSummary::kNoCall);
@@ -1882,7 +1908,7 @@
}
-LocationSummary* DropTempsInstr::MakeLocationSummary() const {
+LocationSummary* DropTempsInstr::MakeLocationSummary(bool optimizing) const {
return LocationSummary::Make(1,
Location::SameAsFirstInput(),
LocationSummary::kNoCall);
@@ -1915,7 +1941,7 @@
}
-LocationSummary* InstanceCallInstr::MakeLocationSummary() const {
+LocationSummary* InstanceCallInstr::MakeLocationSummary(bool optimizing) const {
return MakeCallSummary();
}
@@ -1976,7 +2002,7 @@
}
-LocationSummary* StaticCallInstr::MakeLocationSummary() const {
+LocationSummary* StaticCallInstr::MakeLocationSummary(bool optimizing) const {
return MakeCallSummary();
}
@@ -2870,7 +2896,6 @@
intptr_t original_deopt_id,
MethodRecognizer::Kind recognized_kind)
: inputs_(inputs),
- locs_(NULL),
recognized_kind_(recognized_kind) {
ASSERT(inputs_->length() == ArgumentCountFor(recognized_kind_));
for (intptr_t i = 0; i < inputs_->length(); ++i) {
@@ -2978,7 +3003,6 @@
intptr_t original_deopt_id,
MergedMathInstr::Kind kind)
: inputs_(inputs),
- locs_(NULL),
kind_(kind) {
ASSERT(inputs_->length() == InputCountFor(kind_));
for (intptr_t i = 0; i < inputs_->length(); ++i) {
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index 43b9873..01dda16 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -302,7 +302,7 @@
// Create None CompileType. It is the bottom of the lattice and is used to
// represent type of the phi that was not yet inferred.
static CompileType None() {
- return CompileType(true, kIllegalCid, NULL);
+ return CompileType(kNullable, kIllegalCid, NULL);
}
// Create Dynamic CompileType. It is the top of the lattice and is used to
@@ -711,7 +711,7 @@
virtual void Accept(FlowGraphVisitor* visitor); \
virtual type##Instr* As##type() { return this; } \
virtual const char* DebugName() const { return #type; } \
- virtual LocationSummary* MakeLocationSummary() const; \
+ virtual LocationSummary* MakeLocationSummary(bool optimizing) const; \
virtual void EmitNativeCode(FlowGraphCompiler* compiler); \
@@ -729,6 +729,7 @@
previous_(NULL),
next_(NULL),
env_(NULL),
+ locs_(NULL),
place_id_(kNoPlaceId) { }
virtual Tag tag() const = 0;
@@ -830,13 +831,16 @@
// Returns structure describing location constraints required
// to emit native code for this instruction.
virtual LocationSummary* locs() {
- // TODO(vegorov): This should be pure virtual method.
- // However we are temporary using NULL for instructions that
- // were not converted to the location based code generation yet.
- return NULL;
+ ASSERT(locs_ != NULL);
+ return locs_;
}
- virtual LocationSummary* MakeLocationSummary() const = 0;
+ virtual LocationSummary* MakeLocationSummary(bool is_optimizing) const = 0;
+
+ void InitializeLocationSummary(bool optimizing) {
+ ASSERT(locs_ == NULL);
+ locs_ = MakeLocationSummary(optimizing);
+ }
static LocationSummary* MakeCallSummary();
@@ -953,6 +957,7 @@
}
private:
+ friend class FlowGraphPrinter;
friend class Definition; // Needed for InsertBefore, InsertAfter.
// Classes that set or read deopt_id_.
@@ -1027,6 +1032,7 @@
Instruction* previous_;
Instruction* next_;
Environment* env_;
+ LocationSummary* locs_;
intptr_t place_id_;
DISALLOW_COPY_AND_ASSIGN(Instruction);
@@ -1036,18 +1042,11 @@
template<intptr_t N>
class TemplateInstruction: public Instruction {
public:
- TemplateInstruction<N>() : locs_(NULL) { }
+ TemplateInstruction<N>() : inputs_() { }
virtual intptr_t InputCount() const { return N; }
virtual Value* InputAt(intptr_t i) const { return inputs_[i]; }
- virtual LocationSummary* locs() {
- if (locs_ == NULL) {
- locs_ = MakeLocationSummary();
- }
- return locs_;
- }
-
protected:
EmbeddedArray<Value*, N> inputs_;
@@ -1055,8 +1054,6 @@
virtual void RawSetInputAt(intptr_t i, Value* value) {
inputs_[i] = value;
}
-
- LocationSummary* locs_;
};
@@ -1929,7 +1926,7 @@
class PushArgumentInstr : public Definition {
public:
- explicit PushArgumentInstr(Value* value) : locs_(NULL) {
+ explicit PushArgumentInstr(Value* value) {
SetInputAt(0, value);
set_use_kind(kEffect); // Override the default.
}
@@ -1948,13 +1945,6 @@
Value* value() const { return value_; }
- virtual LocationSummary* locs() {
- if (locs_ == NULL) {
- locs_ = MakeLocationSummary();
- }
- return locs_;
- }
-
virtual intptr_t Hashcode() const {
UNREACHABLE();
return 0;
@@ -1975,7 +1965,6 @@
}
Value* value_;
- LocationSummary* locs_;
DISALLOW_COPY_AND_ASSIGN(PushArgumentInstr);
};
@@ -2133,20 +2122,11 @@
template<intptr_t N>
class TemplateDefinition : public Definition {
public:
- TemplateDefinition<N>() : locs_(NULL) { }
+ TemplateDefinition<N>() : inputs_() { }
virtual intptr_t InputCount() const { return N; }
virtual Value* InputAt(intptr_t i) const { return inputs_[i]; }
- // Returns a structure describing the location constraints required
- // to emit native code for this definition.
- LocationSummary* locs() {
- if (locs_ == NULL) {
- locs_ = MakeLocationSummary();
- }
- return locs_;
- }
-
protected:
EmbeddedArray<Value*, N> inputs_;
@@ -2157,8 +2137,6 @@
virtual void RawSetInputAt(intptr_t i, Value* value) {
inputs_[i] = value;
}
-
- LocationSummary* locs_;
};
@@ -2260,18 +2238,6 @@
bool is_checked() const { return is_checked_; }
- virtual LocationSummary* locs() {
- if (comparison()->locs_ == NULL) {
- LocationSummary* summary = comparison()->MakeLocationSummary();
- // Branches don't produce a result.
- summary->set_out(Location::NoLocation());
- // The back-end expects the location summary to be stored in the
- // comparison.
- comparison()->locs_ = summary;
- }
- return comparison()->locs_;
- }
-
virtual intptr_t DeoptimizationTarget() const {
return comparison()->DeoptimizationTarget();
}
@@ -3154,16 +3120,6 @@
return comparison()->CanBecomeDeoptimizationTarget();
}
- virtual LocationSummary* locs() {
- if (comparison()->locs_ == NULL) {
- LocationSummary* summary = MakeLocationSummary();
- // The back-end expects the location summary to be stored in the
- // comparison.
- comparison()->locs_ = summary;
- }
- return comparison()->locs_;
- }
-
virtual intptr_t DeoptimizationTarget() const {
return comparison()->DeoptimizationTarget();
}
@@ -3470,9 +3426,11 @@
StoreInstanceFieldInstr(const Field& field,
Value* instance,
Value* value,
- StoreBarrierType emit_store_barrier)
+ StoreBarrierType emit_store_barrier,
+ bool is_initialization = false)
: field_(field),
- emit_store_barrier_(emit_store_barrier) {
+ emit_store_barrier_(emit_store_barrier),
+ is_initialization_(is_initialization) {
SetInputAt(kInstancePos, instance);
SetInputAt(kValuePos, value);
}
@@ -3500,6 +3458,11 @@
virtual bool CanDeoptimize() const { return false; }
+ // May require a deoptimization target for input conversions.
+ virtual intptr_t DeoptimizationTarget() const {
+ return GetDeoptId();
+ }
+
// Currently CSE/LICM don't operate on any instructions that can be affected
// by stores/loads. LoadOptimizer handles loads separately. Hence stores
// are marked as having no side-effects.
@@ -3507,7 +3470,19 @@
virtual bool MayThrow() const { return false; }
+ bool IsUnboxedStore() const;
+
+ bool IsPotentialUnboxedStore() const;
+
+ virtual Representation RequiredInputRepresentation(intptr_t index) const {
+ ASSERT((index == 0) || (index == 1));
+ if ((index == 1) && IsUnboxedStore()) return kUnboxedDouble;
+ return kTagged;
+ }
+
private:
+ friend class FlowGraphOptimizer; // For ASSERT(initialization_).
+
bool CanValueBeSmi() const {
const intptr_t cid = value()->Type()->ToNullableCid();
// Write barrier is skipped for nullable and non-nullable smis.
@@ -3517,6 +3492,7 @@
const Field& field_;
const StoreBarrierType emit_store_barrier_;
+ const bool is_initialization_; // Marks stores in the constructor.
DISALLOW_COPY_AND_ASSIGN(StoreInstanceFieldInstr);
};
@@ -3997,11 +3973,6 @@
virtual bool CanDeoptimize() const { return false; }
virtual EffectSet Effects() const { return EffectSet::None(); }
- LocationSummary* locs() {
- UNREACHABLE();
- return NULL;
- }
-
Location* locations() { return locations_; }
void set_locations(Location* locations) { locations_ = locations; }
@@ -4217,6 +4188,14 @@
const Field* field() const { return field_; }
void set_field(const Field* field) { field_ = field; }
+ virtual Representation representation() const {
+ return IsUnboxedLoad() ? kUnboxedDouble : kTagged;
+ }
+
+ bool IsUnboxedLoad() const;
+
+ bool IsPotentialUnboxedLoad() const;
+
void set_recognized_kind(MethodRecognizer::Kind kind) {
recognized_kind_ = kind;
}
@@ -6618,15 +6597,6 @@
return (*inputs_)[i];
}
- // Returns a structure describing the location constraints required
- // to emit native code for this definition.
- LocationSummary* locs() {
- if (locs_ == NULL) {
- locs_ = MakeLocationSummary();
- }
- return locs_;
- }
-
virtual bool AllowsCSE() const { return true; }
virtual EffectSet Effects() const { return EffectSet::None(); }
virtual EffectSet Dependencies() const { return EffectSet::None(); }
@@ -6644,8 +6614,6 @@
ZoneGrowableArray<Value*>* inputs_;
- LocationSummary* locs_;
-
const MethodRecognizer::Kind recognized_kind_;
DISALLOW_COPY_AND_ASSIGN(InvokeMathCFunctionInstr);
@@ -6728,15 +6696,6 @@
DECLARE_INSTRUCTION(MergedMath)
- // Returns a structure describing the location constraints required
- // to emit native code for this definition.
- LocationSummary* locs() {
- if (locs_ == NULL) {
- locs_ = MakeLocationSummary();
- }
- return locs_;
- }
-
virtual bool AllowsCSE() const { return true; }
virtual EffectSet Effects() const { return EffectSet::None(); }
virtual EffectSet Dependencies() const { return EffectSet::None(); }
@@ -6760,7 +6719,6 @@
}
ZoneGrowableArray<Value*>* inputs_;
- LocationSummary* locs_;
MergedMathInstr::Kind kind_;
DISALLOW_COPY_AND_ASSIGN(MergedMathInstr);
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index 1266a3b..c3c2676 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -34,7 +34,7 @@
}
-LocationSummary* PushArgumentInstr::MakeLocationSummary() const {
+LocationSummary* PushArgumentInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps= 0;
LocationSummary* locs =
@@ -63,7 +63,7 @@
}
-LocationSummary* ReturnInstr::MakeLocationSummary() const {
+LocationSummary* ReturnInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -135,8 +135,9 @@
}
-LocationSummary* IfThenElseInstr::MakeLocationSummary() const {
- return comparison()->MakeLocationSummary();
+LocationSummary* IfThenElseInstr::MakeLocationSummary(bool opt) const {
+ comparison()->InitializeLocationSummary(opt);
+ return comparison()->locs();
}
@@ -193,7 +194,7 @@
}
-LocationSummary* ClosureCallInstr::MakeLocationSummary() const {
+LocationSummary* ClosureCallInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 0;
const intptr_t kNumTemps = 1;
LocationSummary* result =
@@ -223,7 +224,7 @@
}
-LocationSummary* LoadLocalInstr::MakeLocationSummary() const {
+LocationSummary* LoadLocalInstr::MakeLocationSummary(bool opt) const {
return LocationSummary::Make(0,
Location::RequiresRegister(),
LocationSummary::kNoCall);
@@ -236,7 +237,7 @@
}
-LocationSummary* StoreLocalInstr::MakeLocationSummary() const {
+LocationSummary* StoreLocalInstr::MakeLocationSummary(bool opt) const {
return LocationSummary::Make(1,
Location::SameAsFirstInput(),
LocationSummary::kNoCall);
@@ -251,7 +252,7 @@
}
-LocationSummary* ConstantInstr::MakeLocationSummary() const {
+LocationSummary* ConstantInstr::MakeLocationSummary(bool opt) const {
return LocationSummary::Make(0,
Location::RequiresRegister(),
LocationSummary::kNoCall);
@@ -267,7 +268,7 @@
}
-LocationSummary* AssertAssignableInstr::MakeLocationSummary() const {
+LocationSummary* AssertAssignableInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 3;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -280,7 +281,7 @@
}
-LocationSummary* AssertBooleanInstr::MakeLocationSummary() const {
+LocationSummary* AssertBooleanInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -341,7 +342,7 @@
}
-LocationSummary* EqualityCompareInstr::MakeLocationSummary() const {
+LocationSummary* EqualityCompareInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
if (operation_cid() == kMintCid) {
const intptr_t kNumTemps = 1;
@@ -538,7 +539,7 @@
}
-LocationSummary* TestSmiInstr::MakeLocationSummary() const {
+LocationSummary* TestSmiInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -581,7 +582,7 @@
}
-LocationSummary* RelationalOpInstr::MakeLocationSummary() const {
+LocationSummary* RelationalOpInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
if (operation_cid() == kMintCid) {
@@ -664,7 +665,7 @@
}
-LocationSummary* NativeCallInstr::MakeLocationSummary() const {
+LocationSummary* NativeCallInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 0;
const intptr_t kNumTemps = 3;
LocationSummary* locs =
@@ -708,6 +709,12 @@
// stub generates the redirection address when running under the simulator
// and hence we do not change 'entry' here.
stub_entry = &StubCode::CallNativeCFunctionLabel();
+#if defined(USING_SIMULATOR)
+ if (!function().IsNativeAutoSetupScope()) {
+ entry = Simulator::RedirectExternalReference(
+ entry, Simulator::kBootstrapNativeCall, function().NumParameters());
+ }
+#endif
}
__ LoadImmediate(R5, entry);
__ LoadImmediate(R1, NativeArguments::ComputeArgcTag(function()));
@@ -719,7 +726,7 @@
}
-LocationSummary* StringFromCharCodeInstr::MakeLocationSummary() const {
+LocationSummary* StringFromCharCodeInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
// TODO(fschneider): Allow immediate operands for the char code.
return LocationSummary::Make(kNumInputs,
@@ -738,7 +745,7 @@
}
-LocationSummary* StringInterpolateInstr::MakeLocationSummary() const {
+LocationSummary* StringInterpolateInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -764,7 +771,7 @@
}
-LocationSummary* LoadUntaggedInstr::MakeLocationSummary() const {
+LocationSummary* LoadUntaggedInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
return LocationSummary::Make(kNumInputs,
Location::RequiresRegister(),
@@ -779,7 +786,7 @@
}
-LocationSummary* LoadClassIdInstr::MakeLocationSummary() const {
+LocationSummary* LoadClassIdInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
return LocationSummary::Make(kNumInputs,
Location::RequiresRegister(),
@@ -875,7 +882,7 @@
}
-LocationSummary* LoadIndexedInstr::MakeLocationSummary() const {
+LocationSummary* LoadIndexedInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -1060,7 +1067,7 @@
}
-LocationSummary* StoreIndexedInstr::MakeLocationSummary() const {
+LocationSummary* StoreIndexedInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 3;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -1247,7 +1254,7 @@
}
-LocationSummary* GuardFieldInstr::MakeLocationSummary() const {
+LocationSummary* GuardFieldInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
LocationSummary* summary =
new LocationSummary(kNumInputs, 0, LocationSummary::kNoCall);
@@ -1572,21 +1579,147 @@
}
-LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary() const {
+class StoreInstanceFieldSlowPath : public SlowPathCode {
+ public:
+ explicit StoreInstanceFieldSlowPath(StoreInstanceFieldInstr* instruction)
+ : instruction_(instruction) { }
+
+ virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
+ __ Comment("StoreInstanceFieldSlowPath");
+ __ Bind(entry_label());
+ const Class& double_class = compiler->double_class();
+ const Code& stub =
+ Code::Handle(StubCode::GetAllocationStubForClass(double_class));
+ const ExternalLabel label(double_class.ToCString(), stub.EntryPoint());
+
+ LocationSummary* locs = instruction_->locs();
+ locs->live_registers()->Remove(locs->out());
+
+ compiler->SaveLiveRegisters(locs);
+ compiler->GenerateCall(Scanner::kDummyTokenIndex, // No token position.
+ &label,
+ PcDescriptors::kOther,
+ locs);
+ __ MoveRegister(locs->temp(0).reg(), R0);
+ compiler->RestoreLiveRegisters(locs);
+
+ __ b(exit_label());
+ }
+
+ private:
+ StoreInstanceFieldInstr* instruction_;
+};
+
+
+LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
- new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ new LocationSummary(kNumInputs, kNumTemps,
+ (field().guarded_cid() == kIllegalCid) || (is_initialization_)
+ ? LocationSummary::kCallOnSlowPath
+ : LocationSummary::kNoCall);
+
summary->set_in(0, Location::RequiresRegister());
- summary->set_in(1, ShouldEmitStoreBarrier()
+ if (IsUnboxedStore() && opt) {
+ summary->set_in(1, Location::RequiresFpuRegister());
+ summary->AddTemp(Location::RequiresRegister());
+ summary->AddTemp(Location::RequiresRegister());
+ } else if (IsPotentialUnboxedStore()) {
+ summary->set_in(1, ShouldEmitStoreBarrier()
+ ? Location::WritableRegister()
+ : Location::RequiresRegister());
+ summary->AddTemp(Location::RequiresRegister());
+ summary->AddTemp(Location::RequiresRegister());
+ summary->AddTemp(opt ? Location::RequiresFpuRegister()
+ : Location::FpuRegisterLocation(Q1));
+ } else {
+ summary->set_in(1, ShouldEmitStoreBarrier()
? Location::WritableRegister()
: Location::RegisterOrConstant(value()));
+ }
return summary;
}
void StoreInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ Label skip_store;
+
Register instance_reg = locs()->in(0).reg();
+
+ if (IsUnboxedStore() && compiler->is_optimizing()) {
+ DRegister value = EvenDRegisterOf(locs()->in(1).fpu_reg());
+ Register temp = locs()->temp(0).reg();
+ Register temp2 = locs()->temp(1).reg();
+
+ if (is_initialization_) {
+ StoreInstanceFieldSlowPath* slow_path =
+ new StoreInstanceFieldSlowPath(this);
+ compiler->AddSlowPathCode(slow_path);
+ __ TryAllocate(compiler->double_class(),
+ slow_path->entry_label(),
+ temp);
+ __ Bind(slow_path->exit_label());
+ __ MoveRegister(temp2, temp);
+ __ StoreIntoObject(instance_reg,
+ FieldAddress(instance_reg, field().Offset()),
+ temp2);
+ } else {
+ __ ldr(temp, FieldAddress(instance_reg, field().Offset()));
+ }
+ __ StoreDToOffset(value, temp, Double::value_offset() - kHeapObjectTag);
+ return;
+ }
+
+ if (IsPotentialUnboxedStore()) {
+ Register value_reg = locs()->in(1).reg();
+ Register temp = locs()->temp(0).reg();
+ Register temp2 = locs()->temp(1).reg();
+ DRegister fpu_temp = EvenDRegisterOf(locs()->temp(2).fpu_reg());
+
+ Label store_pointer, copy_payload;
+ __ LoadObject(temp, Field::ZoneHandle(field().raw()));
+ __ ldr(temp2, FieldAddress(temp, Field::guarded_cid_offset()));
+ __ CompareImmediate(temp2, kDoubleCid);
+ __ b(&store_pointer, NE);
+ __ ldr(temp2, FieldAddress(temp, Field::is_nullable_offset()));
+ __ CompareImmediate(temp2, kNullCid);
+ __ b(&store_pointer, EQ);
+ __ ldrb(temp2, FieldAddress(temp, Field::kind_bits_offset()));
+ __ tst(temp2, ShifterOperand(1 << Field::kUnboxingCandidateBit));
+ __ b(&store_pointer, EQ);
+
+ __ ldr(temp, FieldAddress(instance_reg, field().Offset()));
+ __ CompareImmediate(temp,
+ reinterpret_cast<intptr_t>(Object::null()));
+ __ b(©_payload, NE);
+
+ StoreInstanceFieldSlowPath* slow_path =
+ new StoreInstanceFieldSlowPath(this);
+ compiler->AddSlowPathCode(slow_path);
+
+ if (!compiler->is_optimizing()) {
+ locs()->live_registers()->Add(locs()->in(0));
+ locs()->live_registers()->Add(locs()->in(1));
+ }
+
+ __ TryAllocate(compiler->double_class(),
+ slow_path->entry_label(),
+ temp);
+ __ Bind(slow_path->exit_label());
+ __ MoveRegister(temp2, temp);
+ __ StoreIntoObject(instance_reg,
+ FieldAddress(instance_reg, field().Offset()),
+ temp2);
+ __ Bind(©_payload);
+ __ LoadDFromOffset(fpu_temp,
+ value_reg,
+ Double::value_offset() - kHeapObjectTag);
+ __ StoreDToOffset(fpu_temp, temp, Double::value_offset() - kHeapObjectTag);
+ __ b(&skip_store);
+ __ Bind(&store_pointer);
+ }
+
if (ShouldEmitStoreBarrier()) {
Register value_reg = locs()->in(1).reg();
__ StoreIntoObject(instance_reg,
@@ -1605,10 +1738,11 @@
FieldAddress(instance_reg, field().Offset()), value_reg);
}
}
+ __ Bind(&skip_store);
}
-LocationSummary* LoadStaticFieldInstr::MakeLocationSummary() const {
+LocationSummary* LoadStaticFieldInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -1632,7 +1766,7 @@
}
-LocationSummary* StoreStaticFieldInstr::MakeLocationSummary() const {
+LocationSummary* StoreStaticFieldInstr::MakeLocationSummary(bool opt) const {
LocationSummary* locs = new LocationSummary(1, 1, LocationSummary::kNoCall);
locs->set_in(0, value()->NeedsStoreBuffer() ? Location::WritableRegister()
: Location::RequiresRegister());
@@ -1656,7 +1790,7 @@
}
-LocationSummary* InstanceOfInstr::MakeLocationSummary() const {
+LocationSummary* InstanceOfInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 3;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -1683,7 +1817,7 @@
}
-LocationSummary* CreateArrayInstr::MakeLocationSummary() const {
+LocationSummary* CreateArrayInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -1707,7 +1841,7 @@
LocationSummary*
-AllocateObjectWithBoundsCheckInstr::MakeLocationSummary() const {
+AllocateObjectWithBoundsCheckInstr::MakeLocationSummary(bool opt) const {
return MakeCallSummary();
}
@@ -1725,23 +1859,119 @@
}
-LocationSummary* LoadFieldInstr::MakeLocationSummary() const {
- return LocationSummary::Make(1,
- Location::RequiresRegister(),
- LocationSummary::kNoCall);
+class BoxDoubleSlowPath : public SlowPathCode {
+ public:
+ explicit BoxDoubleSlowPath(Instruction* instruction)
+ : instruction_(instruction) { }
+
+ virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
+ __ Comment("BoxDoubleSlowPath");
+ __ Bind(entry_label());
+ const Class& double_class = compiler->double_class();
+ const Code& stub =
+ Code::Handle(StubCode::GetAllocationStubForClass(double_class));
+ const ExternalLabel label(double_class.ToCString(), stub.EntryPoint());
+
+ LocationSummary* locs = instruction_->locs();
+ locs->live_registers()->Remove(locs->out());
+
+ compiler->SaveLiveRegisters(locs);
+ compiler->GenerateCall(Scanner::kDummyTokenIndex, // No token position.
+ &label,
+ PcDescriptors::kOther,
+ locs);
+ __ MoveRegister(locs->out().reg(), R0);
+ compiler->RestoreLiveRegisters(locs);
+
+ __ b(exit_label());
+ }
+
+ private:
+ Instruction* instruction_;
+};
+
+
+LocationSummary* LoadFieldInstr::MakeLocationSummary(bool opt) const {
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* locs =
+ new LocationSummary(
+ kNumInputs, kNumTemps,
+ (opt && !IsPotentialUnboxedLoad())
+ ? LocationSummary::kNoCall
+ : LocationSummary::kCallOnSlowPath);
+
+ locs->set_in(0, Location::RequiresRegister());
+
+ if (IsUnboxedLoad() && opt) {
+ locs->AddTemp(Location::RequiresRegister());
+ } else if (IsPotentialUnboxedLoad()) {
+ locs->AddTemp(opt ? Location::RequiresFpuRegister()
+ : Location::FpuRegisterLocation(Q1));
+ locs->AddTemp(Location::RequiresRegister());
+ }
+ locs->set_out(Location::RequiresRegister());
+ return locs;
}
void LoadFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register instance_reg = locs()->in(0).reg();
- Register result_reg = locs()->out().reg();
+ if (IsUnboxedLoad() && compiler->is_optimizing()) {
+ DRegister result = EvenDRegisterOf(locs()->out().fpu_reg());
+ Register temp = locs()->temp(0).reg();
+ __ ldr(temp, FieldAddress(instance_reg, offset_in_bytes()));
+ __ LoadDFromOffset(result, temp, Double::value_offset() - kHeapObjectTag);
+ return;
+ }
+ Label done;
+ Register result_reg = locs()->out().reg();
+ if (IsPotentialUnboxedLoad()) {
+ Register temp = locs()->temp(1).reg();
+ DRegister value = EvenDRegisterOf(locs()->temp(0).fpu_reg());
+
+ Label load_pointer;
+ __ LoadObject(result_reg, Field::ZoneHandle(field()->raw()));
+
+ FieldAddress field_cid_operand(result_reg, Field::guarded_cid_offset());
+ FieldAddress field_nullability_operand(result_reg,
+ Field::is_nullable_offset());
+
+ __ ldr(temp, field_cid_operand);
+ __ CompareImmediate(temp, kDoubleCid);
+ __ b(&load_pointer, NE);
+
+ __ ldr(temp, field_nullability_operand);
+ __ CompareImmediate(temp, kNullCid);
+ __ b(&load_pointer, EQ);
+
+ BoxDoubleSlowPath* slow_path = new BoxDoubleSlowPath(this);
+ compiler->AddSlowPathCode(slow_path);
+
+ if (!compiler->is_optimizing()) {
+ locs()->live_registers()->Add(locs()->in(0));
+ }
+
+ __ TryAllocate(compiler->double_class(),
+ slow_path->entry_label(),
+ result_reg);
+ __ Bind(slow_path->exit_label());
+ __ ldr(temp, FieldAddress(instance_reg, offset_in_bytes()));
+ __ LoadDFromOffset(value, temp, Double::value_offset() - kHeapObjectTag);
+ __ StoreDToOffset(value,
+ result_reg,
+ Double::value_offset() - kHeapObjectTag);
+ __ b(&done);
+ __ Bind(&load_pointer);
+ }
__ LoadFromOffset(kWord, result_reg,
instance_reg, offset_in_bytes() - kHeapObjectTag);
+ __ Bind(&done);
}
-LocationSummary* InstantiateTypeInstr::MakeLocationSummary() const {
+LocationSummary* InstantiateTypeInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -1773,7 +2003,8 @@
}
-LocationSummary* InstantiateTypeArgumentsInstr::MakeLocationSummary() const {
+LocationSummary* InstantiateTypeArgumentsInstr::MakeLocationSummary(
+ bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -1822,7 +2053,7 @@
LocationSummary*
-ExtractConstructorTypeArgumentsInstr::MakeLocationSummary() const {
+ExtractConstructorTypeArgumentsInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -1864,7 +2095,7 @@
LocationSummary*
-ExtractConstructorInstantiatorInstr::MakeLocationSummary() const {
+ExtractConstructorInstantiatorInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -1903,7 +2134,7 @@
}
-LocationSummary* AllocateContextInstr::MakeLocationSummary() const {
+LocationSummary* AllocateContextInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 0;
const intptr_t kNumTemps = 1;
LocationSummary* locs =
@@ -1928,7 +2159,7 @@
}
-LocationSummary* CloneContextInstr::MakeLocationSummary() const {
+LocationSummary* CloneContextInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -1955,7 +2186,7 @@
}
-LocationSummary* CatchBlockEntryInstr::MakeLocationSummary() const {
+LocationSummary* CatchBlockEntryInstr::MakeLocationSummary(bool opt) const {
UNREACHABLE();
return NULL;
}
@@ -1992,7 +2223,7 @@
}
-LocationSummary* CheckStackOverflowInstr::MakeLocationSummary() const {
+LocationSummary* CheckStackOverflowInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 0;
const intptr_t kNumTemps = 1;
LocationSummary* summary =
@@ -2175,7 +2406,7 @@
}
-LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const {
+LocationSummary* BinarySmiOpInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -2506,7 +2737,7 @@
}
-LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary() const {
+LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary(bool opt) const {
intptr_t left_cid = left()->Type()->ToCid();
intptr_t right_cid = right()->Type()->ToCid();
ASSERT((left_cid != kDoubleCid) && (right_cid != kDoubleCid));
@@ -2538,7 +2769,7 @@
}
-LocationSummary* BoxDoubleInstr::MakeLocationSummary() const {
+LocationSummary* BoxDoubleInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -2551,38 +2782,6 @@
}
-class BoxDoubleSlowPath : public SlowPathCode {
- public:
- explicit BoxDoubleSlowPath(BoxDoubleInstr* instruction)
- : instruction_(instruction) { }
-
- virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
- __ Comment("BoxDoubleSlowPath");
- __ Bind(entry_label());
- const Class& double_class = compiler->double_class();
- const Code& stub =
- Code::Handle(StubCode::GetAllocationStubForClass(double_class));
- const ExternalLabel label(double_class.ToCString(), stub.EntryPoint());
-
- LocationSummary* locs = instruction_->locs();
- locs->live_registers()->Remove(locs->out());
-
- compiler->SaveLiveRegisters(locs);
- compiler->GenerateCall(Scanner::kDummyTokenIndex, // No token position.
- &label,
- PcDescriptors::kOther,
- locs);
- __ MoveRegister(locs->out().reg(), R0);
- compiler->RestoreLiveRegisters(locs);
-
- __ b(exit_label());
- }
-
- private:
- BoxDoubleInstr* instruction_;
-};
-
-
void BoxDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
BoxDoubleSlowPath* slow_path = new BoxDoubleSlowPath(this);
compiler->AddSlowPathCode(slow_path);
@@ -2598,7 +2797,7 @@
}
-LocationSummary* UnboxDoubleInstr::MakeLocationSummary() const {
+LocationSummary* UnboxDoubleInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t value_cid = value()->Type()->ToCid();
const bool needs_temp = ((value_cid != kSmiCid) && (value_cid != kDoubleCid));
@@ -2646,7 +2845,7 @@
}
-LocationSummary* BoxFloat32x4Instr::MakeLocationSummary() const {
+LocationSummary* BoxFloat32x4Instr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -2712,7 +2911,7 @@
}
-LocationSummary* UnboxFloat32x4Instr::MakeLocationSummary() const {
+LocationSummary* UnboxFloat32x4Instr::MakeLocationSummary(bool opt) const {
const intptr_t value_cid = value()->Type()->ToCid();
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = value_cid == kFloat32x4Cid ? 0 : 1;
@@ -2751,7 +2950,7 @@
}
-LocationSummary* BoxInt32x4Instr::MakeLocationSummary() const {
+LocationSummary* BoxInt32x4Instr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -2816,7 +3015,7 @@
}
-LocationSummary* UnboxInt32x4Instr::MakeLocationSummary() const {
+LocationSummary* UnboxInt32x4Instr::MakeLocationSummary(bool opt) const {
const intptr_t value_cid = value()->Type()->ToCid();
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = value_cid == kInt32x4Cid ? 0 : 1;
@@ -2855,7 +3054,7 @@
}
-LocationSummary* BinaryDoubleOpInstr::MakeLocationSummary() const {
+LocationSummary* BinaryDoubleOpInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -2881,7 +3080,7 @@
}
-LocationSummary* BinaryFloat32x4OpInstr::MakeLocationSummary() const {
+LocationSummary* BinaryFloat32x4OpInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -2908,7 +3107,7 @@
}
-LocationSummary* Simd32x4ShuffleInstr::MakeLocationSummary() const {
+LocationSummary* Simd32x4ShuffleInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -2988,7 +3187,7 @@
}
-LocationSummary* Simd32x4ShuffleMixInstr::MakeLocationSummary() const {
+LocationSummary* Simd32x4ShuffleMixInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3044,7 +3243,7 @@
}
-LocationSummary* Simd32x4GetSignMaskInstr::MakeLocationSummary() const {
+LocationSummary* Simd32x4GetSignMaskInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 1;
LocationSummary* summary =
@@ -3084,7 +3283,8 @@
}
-LocationSummary* Float32x4ConstructorInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4ConstructorInstr::MakeLocationSummary(
+ bool opt) const {
const intptr_t kNumInputs = 4;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3116,7 +3316,7 @@
}
-LocationSummary* Float32x4ZeroInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4ZeroInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 0;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3132,7 +3332,7 @@
}
-LocationSummary* Float32x4SplatInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4SplatInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3157,7 +3357,7 @@
}
-LocationSummary* Float32x4ComparisonInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4ComparisonInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3202,7 +3402,7 @@
}
-LocationSummary* Float32x4MinMaxInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4MinMaxInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3231,7 +3431,7 @@
}
-LocationSummary* Float32x4SqrtInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4SqrtInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 1;
LocationSummary* summary =
@@ -3263,7 +3463,7 @@
}
-LocationSummary* Float32x4ScaleInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4ScaleInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3291,7 +3491,7 @@
}
-LocationSummary* Float32x4ZeroArgInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4ZeroArgInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3318,7 +3518,7 @@
}
-LocationSummary* Float32x4ClampInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4ClampInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 3;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3341,7 +3541,7 @@
}
-LocationSummary* Float32x4WithInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4WithInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3389,7 +3589,7 @@
}
-LocationSummary* Float32x4ToInt32x4Instr::MakeLocationSummary() const {
+LocationSummary* Float32x4ToInt32x4Instr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3410,7 +3610,8 @@
}
-LocationSummary* Int32x4BoolConstructorInstr::MakeLocationSummary() const {
+LocationSummary* Int32x4BoolConstructorInstr::MakeLocationSummary(
+ bool opt) const {
const intptr_t kNumInputs = 4;
const intptr_t kNumTemps = 1;
LocationSummary* summary =
@@ -3457,7 +3658,7 @@
}
-LocationSummary* Int32x4GetFlagInstr::MakeLocationSummary() const {
+LocationSummary* Int32x4GetFlagInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3502,7 +3703,7 @@
}
-LocationSummary* Int32x4SelectInstr::MakeLocationSummary() const {
+LocationSummary* Int32x4SelectInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 3;
const intptr_t kNumTemps = 1;
LocationSummary* summary =
@@ -3537,7 +3738,7 @@
}
-LocationSummary* Int32x4SetFlagInstr::MakeLocationSummary() const {
+LocationSummary* Int32x4SetFlagInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3587,7 +3788,7 @@
}
-LocationSummary* Int32x4ToFloat32x4Instr::MakeLocationSummary() const {
+LocationSummary* Int32x4ToFloat32x4Instr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3608,7 +3809,7 @@
}
-LocationSummary* BinaryInt32x4OpInstr::MakeLocationSummary() const {
+LocationSummary* BinaryInt32x4OpInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3648,7 +3849,7 @@
}
-LocationSummary* MathUnaryInstr::MakeLocationSummary() const {
+LocationSummary* MathUnaryInstr::MakeLocationSummary(bool opt) const {
if ((kind() == MethodRecognizer::kMathSin) ||
(kind() == MethodRecognizer::kMathCos)) {
const intptr_t kNumInputs = 1;
@@ -3698,7 +3899,7 @@
}
-LocationSummary* MathMinMaxInstr::MakeLocationSummary() const {
+LocationSummary* MathMinMaxInstr::MakeLocationSummary(bool opt) const {
if (result_cid() == kDoubleCid) {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 1;
@@ -3783,7 +3984,7 @@
}
-LocationSummary* UnarySmiOpInstr::MakeLocationSummary() const {
+LocationSummary* UnarySmiOpInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3818,7 +4019,7 @@
}
-LocationSummary* UnaryDoubleOpInstr::MakeLocationSummary() const {
+LocationSummary* UnaryDoubleOpInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3836,7 +4037,7 @@
}
-LocationSummary* SmiToDoubleInstr::MakeLocationSummary() const {
+LocationSummary* SmiToDoubleInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* result =
@@ -3856,7 +4057,7 @@
}
-LocationSummary* DoubleToIntegerInstr::MakeLocationSummary() const {
+LocationSummary* DoubleToIntegerInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* result =
@@ -3908,7 +4109,7 @@
}
-LocationSummary* DoubleToSmiInstr::MakeLocationSummary() const {
+LocationSummary* DoubleToSmiInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* result = new LocationSummary(
@@ -3938,7 +4139,7 @@
}
-LocationSummary* DoubleToDoubleInstr::MakeLocationSummary() const {
+LocationSummary* DoubleToDoubleInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* result =
@@ -3971,7 +4172,7 @@
}
-LocationSummary* InvokeMathCFunctionInstr::MakeLocationSummary() const {
+LocationSummary* InvokeMathCFunctionInstr::MakeLocationSummary(bool opt) const {
ASSERT((InputCount() == 1) || (InputCount() == 2));
const intptr_t kNumTemps = 0;
LocationSummary* result =
@@ -4055,7 +4256,7 @@
}
-LocationSummary* MergedMathInstr::MakeLocationSummary() const {
+LocationSummary* MergedMathInstr::MakeLocationSummary(bool opt) const {
if (kind() == MergedMathInstr::kTruncDivMod) {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 4;
@@ -4144,7 +4345,8 @@
}
-LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary() const {
+LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary(
+ bool opt) const {
return MakeCallSummary();
}
@@ -4187,9 +4389,11 @@
}
-LocationSummary* BranchInstr::MakeLocationSummary() const {
- UNREACHABLE();
- return NULL;
+LocationSummary* BranchInstr::MakeLocationSummary(bool opt) const {
+ comparison()->InitializeLocationSummary(opt);
+ // Branches don't produce a result.
+ comparison()->locs()->set_out(Location::NoLocation());
+ return comparison()->locs();
}
@@ -4198,7 +4402,7 @@
}
-LocationSummary* CheckClassInstr::MakeLocationSummary() const {
+LocationSummary* CheckClassInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -4252,7 +4456,7 @@
}
-LocationSummary* CheckSmiInstr::MakeLocationSummary() const {
+LocationSummary* CheckSmiInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -4271,7 +4475,7 @@
}
-LocationSummary* CheckArrayBoundInstr::MakeLocationSummary() const {
+LocationSummary* CheckArrayBoundInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -4324,7 +4528,7 @@
}
-LocationSummary* UnboxIntegerInstr::MakeLocationSummary() const {
+LocationSummary* UnboxIntegerInstr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -4335,7 +4539,7 @@
}
-LocationSummary* BoxIntegerInstr::MakeLocationSummary() const {
+LocationSummary* BoxIntegerInstr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -4346,7 +4550,7 @@
}
-LocationSummary* BinaryMintOpInstr::MakeLocationSummary() const {
+LocationSummary* BinaryMintOpInstr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -4357,7 +4561,7 @@
}
-LocationSummary* ShiftMintOpInstr::MakeLocationSummary() const {
+LocationSummary* ShiftMintOpInstr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -4368,7 +4572,7 @@
}
-LocationSummary* UnaryMintOpInstr::MakeLocationSummary() const {
+LocationSummary* UnaryMintOpInstr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -4379,7 +4583,7 @@
}
-LocationSummary* ThrowInstr::MakeLocationSummary() const {
+LocationSummary* ThrowInstr::MakeLocationSummary(bool opt) const {
return new LocationSummary(0, 0, LocationSummary::kCall);
}
@@ -4394,7 +4598,7 @@
}
-LocationSummary* ReThrowInstr::MakeLocationSummary() const {
+LocationSummary* ReThrowInstr::MakeLocationSummary(bool opt) const {
return new LocationSummary(0, 0, LocationSummary::kCall);
}
@@ -4435,7 +4639,7 @@
}
-LocationSummary* GotoInstr::MakeLocationSummary() const {
+LocationSummary* GotoInstr::MakeLocationSummary(bool opt) const {
return new LocationSummary(0, 0, LocationSummary::kNoCall);
}
@@ -4464,7 +4668,7 @@
}
-LocationSummary* CurrentContextInstr::MakeLocationSummary() const {
+LocationSummary* CurrentContextInstr::MakeLocationSummary(bool opt) const {
return LocationSummary::Make(0,
Location::RequiresRegister(),
LocationSummary::kNoCall);
@@ -4476,7 +4680,7 @@
}
-LocationSummary* StrictCompareInstr::MakeLocationSummary() const {
+LocationSummary* StrictCompareInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
if (needs_number_check()) {
@@ -4549,7 +4753,7 @@
}
-LocationSummary* BooleanNegateInstr::MakeLocationSummary() const {
+LocationSummary* BooleanNegateInstr::MakeLocationSummary(bool opt) const {
return LocationSummary::Make(1,
Location::RequiresRegister(),
LocationSummary::kNoCall);
@@ -4566,7 +4770,7 @@
}
-LocationSummary* StoreVMFieldInstr::MakeLocationSummary() const {
+LocationSummary* StoreVMFieldInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -4592,7 +4796,7 @@
}
-LocationSummary* AllocateObjectInstr::MakeLocationSummary() const {
+LocationSummary* AllocateObjectInstr::MakeLocationSummary(bool opt) const {
return MakeCallSummary();
}
@@ -4608,7 +4812,7 @@
}
-LocationSummary* CreateClosureInstr::MakeLocationSummary() const {
+LocationSummary* CreateClosureInstr::MakeLocationSummary(bool opt) const {
return MakeCallSummary();
}
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index 8c9c9eb..46babb9 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -34,7 +34,7 @@
}
-LocationSummary* PushArgumentInstr::MakeLocationSummary() const {
+LocationSummary* PushArgumentInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps= 0;
LocationSummary* locs =
@@ -61,7 +61,7 @@
}
-LocationSummary* ReturnInstr::MakeLocationSummary() const {
+LocationSummary* ReturnInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -108,7 +108,7 @@
}
-LocationSummary* LoadLocalInstr::MakeLocationSummary() const {
+LocationSummary* LoadLocalInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 0;
return LocationSummary::Make(kNumInputs,
Location::RequiresRegister(),
@@ -122,7 +122,7 @@
}
-LocationSummary* StoreLocalInstr::MakeLocationSummary() const {
+LocationSummary* StoreLocalInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
return LocationSummary::Make(kNumInputs,
Location::SameAsFirstInput(),
@@ -138,7 +138,7 @@
}
-LocationSummary* ConstantInstr::MakeLocationSummary() const {
+LocationSummary* ConstantInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 0;
return LocationSummary::Make(kNumInputs,
Location::RequiresRegister(),
@@ -155,7 +155,7 @@
}
-LocationSummary* AssertAssignableInstr::MakeLocationSummary() const {
+LocationSummary* AssertAssignableInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 3;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -168,7 +168,7 @@
}
-LocationSummary* AssertBooleanInstr::MakeLocationSummary() const {
+LocationSummary* AssertBooleanInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -229,7 +229,7 @@
}
-LocationSummary* EqualityCompareInstr::MakeLocationSummary() const {
+LocationSummary* EqualityCompareInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
if (operation_cid() == kMintCid) {
const intptr_t kNumTemps = 1;
@@ -549,7 +549,7 @@
}
-LocationSummary* TestSmiInstr::MakeLocationSummary() const {
+LocationSummary* TestSmiInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -593,7 +593,7 @@
}
-LocationSummary* RelationalOpInstr::MakeLocationSummary() const {
+LocationSummary* RelationalOpInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
if (operation_cid() == kMintCid) {
@@ -667,7 +667,7 @@
}
-LocationSummary* NativeCallInstr::MakeLocationSummary() const {
+LocationSummary* NativeCallInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 0;
const intptr_t kNumTemps = 3;
LocationSummary* locs =
@@ -721,7 +721,7 @@
}
-LocationSummary* StringFromCharCodeInstr::MakeLocationSummary() const {
+LocationSummary* StringFromCharCodeInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
// TODO(fschneider): Allow immediate operands for the char code.
return LocationSummary::Make(kNumInputs,
@@ -742,7 +742,7 @@
}
-LocationSummary* StringInterpolateInstr::MakeLocationSummary() const {
+LocationSummary* StringInterpolateInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -768,7 +768,7 @@
}
-LocationSummary* LoadUntaggedInstr::MakeLocationSummary() const {
+LocationSummary* LoadUntaggedInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
return LocationSummary::Make(kNumInputs,
Location::RequiresRegister(),
@@ -783,7 +783,7 @@
}
-LocationSummary* LoadClassIdInstr::MakeLocationSummary() const {
+LocationSummary* LoadClassIdInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
return LocationSummary::Make(kNumInputs,
Location::RequiresRegister(),
@@ -879,7 +879,7 @@
}
-LocationSummary* LoadIndexedInstr::MakeLocationSummary() const {
+LocationSummary* LoadIndexedInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -1048,7 +1048,7 @@
}
-LocationSummary* StoreIndexedInstr::MakeLocationSummary() const {
+LocationSummary* StoreIndexedInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 3;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -1232,7 +1232,7 @@
}
-LocationSummary* GuardFieldInstr::MakeLocationSummary() const {
+LocationSummary* GuardFieldInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
LocationSummary* summary =
new LocationSummary(kNumInputs, 0, LocationSummary::kNoCall);
@@ -1581,21 +1581,150 @@
}
-LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary() const {
+class StoreInstanceFieldSlowPath : public SlowPathCode {
+ public:
+ explicit StoreInstanceFieldSlowPath(StoreInstanceFieldInstr* instruction)
+ : instruction_(instruction) { }
+
+ virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
+ __ Comment("StoreInstanceFieldSlowPath");
+ __ Bind(entry_label());
+ const Class& double_class = compiler->double_class();
+ const Code& stub =
+ Code::Handle(StubCode::GetAllocationStubForClass(double_class));
+ const ExternalLabel label(double_class.ToCString(), stub.EntryPoint());
+
+ LocationSummary* locs = instruction_->locs();
+ locs->live_registers()->Remove(locs->out());
+
+ compiler->SaveLiveRegisters(locs);
+ compiler->GenerateCall(Scanner::kDummyTokenIndex, // No token position.
+ &label,
+ PcDescriptors::kOther,
+ locs);
+ __ MoveRegister(locs->temp(0).reg(), EAX);
+ compiler->RestoreLiveRegisters(locs);
+
+ __ jmp(exit_label());
+ }
+
+ private:
+ StoreInstanceFieldInstr* instruction_;
+};
+
+
+LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
- new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ new LocationSummary(kNumInputs, kNumTemps,
+ (field().guarded_cid() == kIllegalCid) || (is_initialization_)
+ ? LocationSummary::kCallOnSlowPath
+ : LocationSummary::kNoCall);
+
summary->set_in(0, Location::RequiresRegister());
- summary->set_in(1, ShouldEmitStoreBarrier()
+ if (IsUnboxedStore() && opt) {
+ summary->set_in(1, Location::RequiresFpuRegister());
+ summary->AddTemp(Location::RequiresRegister());
+ summary->AddTemp(Location::RequiresRegister());
+ } else if (IsPotentialUnboxedStore()) {
+ summary->set_in(1, ShouldEmitStoreBarrier()
+ ? Location::WritableRegister()
+ : Location::RequiresRegister());
+ summary->AddTemp(Location::RequiresRegister());
+ summary->AddTemp(Location::RequiresRegister());
+ summary->AddTemp(opt ? Location::RequiresFpuRegister()
+ : Location::FpuRegisterLocation(XMM1));
+ } else {
+ summary->set_in(1, ShouldEmitStoreBarrier()
? Location::WritableRegister()
: Location::RegisterOrConstant(value()));
+ }
return summary;
}
void StoreInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ Label skip_store;
+
Register instance_reg = locs()->in(0).reg();
+
+ if (IsUnboxedStore() && compiler->is_optimizing()) {
+ XmmRegister value = locs()->in(1).fpu_reg();
+ Register temp = locs()->temp(0).reg();
+ Register temp2 = locs()->temp(1).reg();
+
+ if (is_initialization_) {
+ StoreInstanceFieldSlowPath* slow_path =
+ new StoreInstanceFieldSlowPath(this);
+ compiler->AddSlowPathCode(slow_path);
+
+ __ TryAllocate(compiler->double_class(),
+ slow_path->entry_label(),
+ Assembler::kFarJump,
+ temp);
+ __ Bind(slow_path->exit_label());
+ __ movl(temp2, temp);
+ __ StoreIntoObject(instance_reg,
+ FieldAddress(instance_reg, field().Offset()),
+ temp2);
+ } else {
+ __ movl(temp, FieldAddress(instance_reg, field().Offset()));
+ }
+ __ movsd(FieldAddress(temp, Double::value_offset()), value);
+ return;
+ }
+
+ if (IsPotentialUnboxedStore()) {
+ Register value_reg = locs()->in(1).reg();
+ Register temp = locs()->temp(0).reg();
+ Register temp2 = locs()->temp(1).reg();
+ FpuRegister fpu_temp = locs()->temp(2).fpu_reg();
+
+ Label store_pointer, copy_payload;
+ __ LoadObject(temp, Field::ZoneHandle(field().raw()));
+ __ cmpl(FieldAddress(temp, Field::guarded_cid_offset()),
+ Immediate(kDoubleCid));
+ __ j(NOT_EQUAL, &store_pointer);
+ __ cmpl(FieldAddress(temp, Field::is_nullable_offset()),
+ Immediate(kNullCid));
+ __ j(EQUAL, &store_pointer);
+ __ movzxb(temp2, FieldAddress(temp, Field::kind_bits_offset()));
+ __ testl(temp2, Immediate(1 << Field::kUnboxingCandidateBit));
+ __ j(ZERO, &store_pointer);
+
+ const Immediate& raw_null =
+ Immediate(reinterpret_cast<intptr_t>(Object::null()));
+ __ movl(temp, FieldAddress(instance_reg, field().Offset()));
+ __ cmpl(temp, raw_null);
+ __ j(NOT_EQUAL, ©_payload);
+
+ StoreInstanceFieldSlowPath* slow_path =
+ new StoreInstanceFieldSlowPath(this);
+ compiler->AddSlowPathCode(slow_path);
+
+ if (!compiler->is_optimizing()) {
+ locs()->live_registers()->Add(locs()->in(0));
+ locs()->live_registers()->Add(locs()->in(1));
+ }
+
+ __ TryAllocate(compiler->double_class(),
+ slow_path->entry_label(),
+ Assembler::kFarJump,
+ temp);
+ __ Bind(slow_path->exit_label());
+ __ movl(temp2, temp);
+ __ StoreIntoObject(instance_reg,
+ FieldAddress(instance_reg, field().Offset()),
+ temp2);
+
+ __ Bind(©_payload);
+ __ movsd(fpu_temp, FieldAddress(value_reg, Double::value_offset()));
+ __ movsd(FieldAddress(temp, Double::value_offset()), fpu_temp);
+ __ jmp(&skip_store);
+ __ Bind(&store_pointer);
+ }
+
if (ShouldEmitStoreBarrier()) {
Register value_reg = locs()->in(1).reg();
__ StoreIntoObject(instance_reg,
@@ -1614,10 +1743,11 @@
FieldAddress(instance_reg, field().Offset()), value_reg);
}
}
+ __ Bind(&skip_store);
}
-LocationSummary* LoadStaticFieldInstr::MakeLocationSummary() const {
+LocationSummary* LoadStaticFieldInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -1642,7 +1772,7 @@
}
-LocationSummary* StoreStaticFieldInstr::MakeLocationSummary() const {
+LocationSummary* StoreStaticFieldInstr::MakeLocationSummary(bool opt) const {
LocationSummary* locs = new LocationSummary(1, 1, LocationSummary::kNoCall);
locs->set_in(0, value()->NeedsStoreBuffer() ? Location::WritableRegister()
: Location::RequiresRegister());
@@ -1666,7 +1796,7 @@
}
-LocationSummary* InstanceOfInstr::MakeLocationSummary() const {
+LocationSummary* InstanceOfInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 3;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -1693,7 +1823,7 @@
}
-LocationSummary* CreateArrayInstr::MakeLocationSummary() const {
+LocationSummary* CreateArrayInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -1717,7 +1847,7 @@
LocationSummary*
-AllocateObjectWithBoundsCheckInstr::MakeLocationSummary() const {
+AllocateObjectWithBoundsCheckInstr::MakeLocationSummary(bool opt) const {
return MakeCallSummary();
}
@@ -1735,22 +1865,114 @@
}
-LocationSummary* LoadFieldInstr::MakeLocationSummary() const {
- return LocationSummary::Make(1,
- Location::RequiresRegister(),
- LocationSummary::kNoCall);
+class BoxDoubleSlowPath : public SlowPathCode {
+ public:
+ explicit BoxDoubleSlowPath(Instruction* instruction)
+ : instruction_(instruction) { }
+
+ virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
+ __ Comment("BoxDoubleSlowPath");
+ __ Bind(entry_label());
+ const Class& double_class = compiler->double_class();
+ const Code& stub =
+ Code::Handle(StubCode::GetAllocationStubForClass(double_class));
+ const ExternalLabel label(double_class.ToCString(), stub.EntryPoint());
+
+ LocationSummary* locs = instruction_->locs();
+ locs->live_registers()->Remove(locs->out());
+
+ compiler->SaveLiveRegisters(locs);
+ compiler->GenerateCall(Scanner::kDummyTokenIndex, // No token position.
+ &label,
+ PcDescriptors::kOther,
+ locs);
+ __ MoveRegister(locs->out().reg(), EAX);
+ compiler->RestoreLiveRegisters(locs);
+
+ __ jmp(exit_label());
+ }
+
+ private:
+ Instruction* instruction_;
+};
+
+
+LocationSummary* LoadFieldInstr::MakeLocationSummary(bool opt) const {
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* locs =
+ new LocationSummary(
+ kNumInputs, kNumTemps,
+ (opt && !IsPotentialUnboxedLoad())
+ ? LocationSummary::kNoCall
+ : LocationSummary::kCallOnSlowPath);
+
+ locs->set_in(0, Location::RequiresRegister());
+
+ if (IsUnboxedLoad() && opt) {
+ locs->AddTemp(Location::RequiresRegister());
+ } else if (IsPotentialUnboxedLoad()) {
+ locs->AddTemp(opt ? Location::RequiresFpuRegister()
+ : Location::FpuRegisterLocation(XMM1));
+ locs->AddTemp(Location::RequiresRegister());
+ }
+ locs->set_out(Location::RequiresRegister());
+ return locs;
}
void LoadFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register instance_reg = locs()->in(0).reg();
- Register result_reg = locs()->out().reg();
+ if (IsUnboxedLoad() && compiler->is_optimizing()) {
+ XmmRegister result = locs()->out().fpu_reg();
+ Register temp = locs()->temp(0).reg();
+ __ movl(temp, FieldAddress(instance_reg, offset_in_bytes()));
+ __ movsd(result, FieldAddress(temp, Double::value_offset()));
+ return;
+ }
- __ movl(result_reg, FieldAddress(instance_reg, offset_in_bytes()));
+ Label done;
+ Register result = locs()->out().reg();
+ if (IsPotentialUnboxedLoad()) {
+ Register temp = locs()->temp(1).reg();
+ XmmRegister value = locs()->temp(0).fpu_reg();
+
+ Label load_pointer;
+ __ LoadObject(result, Field::ZoneHandle(field()->raw()));
+
+ FieldAddress field_cid_operand(result, Field::guarded_cid_offset());
+ FieldAddress field_nullability_operand(result, Field::is_nullable_offset());
+
+ __ cmpl(field_cid_operand, Immediate(kDoubleCid));
+ __ j(NOT_EQUAL, &load_pointer);
+
+ __ cmpl(field_nullability_operand, Immediate(kNullCid));
+ __ j(EQUAL, &load_pointer);
+
+ BoxDoubleSlowPath* slow_path = new BoxDoubleSlowPath(this);
+ compiler->AddSlowPathCode(slow_path);
+
+ if (!compiler->is_optimizing()) {
+ locs()->live_registers()->Add(locs()->in(0));
+ }
+
+ __ TryAllocate(compiler->double_class(),
+ slow_path->entry_label(),
+ Assembler::kFarJump,
+ result);
+ __ Bind(slow_path->exit_label());
+ __ movl(temp, FieldAddress(instance_reg, offset_in_bytes()));
+ __ movsd(value, FieldAddress(temp, Double::value_offset()));
+ __ movsd(FieldAddress(result, Double::value_offset()), value);
+ __ jmp(&done);
+ __ Bind(&load_pointer);
+ }
+ __ movl(result, FieldAddress(instance_reg, offset_in_bytes()));
+ __ Bind(&done);
}
-LocationSummary* InstantiateTypeInstr::MakeLocationSummary() const {
+LocationSummary* InstantiateTypeInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -1782,7 +2004,8 @@
}
-LocationSummary* InstantiateTypeArgumentsInstr::MakeLocationSummary() const {
+LocationSummary* InstantiateTypeArgumentsInstr::MakeLocationSummary(
+ bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -1832,7 +2055,7 @@
LocationSummary*
-ExtractConstructorTypeArgumentsInstr::MakeLocationSummary() const {
+ExtractConstructorTypeArgumentsInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -1875,7 +2098,7 @@
LocationSummary*
-ExtractConstructorInstantiatorInstr::MakeLocationSummary() const {
+ExtractConstructorInstantiatorInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -1915,7 +2138,7 @@
}
-LocationSummary* AllocateContextInstr::MakeLocationSummary() const {
+LocationSummary* AllocateContextInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 0;
const intptr_t kNumTemps = 1;
LocationSummary* locs =
@@ -1940,7 +2163,7 @@
}
-LocationSummary* CloneContextInstr::MakeLocationSummary() const {
+LocationSummary* CloneContextInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -1967,7 +2190,7 @@
}
-LocationSummary* CatchBlockEntryInstr::MakeLocationSummary() const {
+LocationSummary* CatchBlockEntryInstr::MakeLocationSummary(bool opt) const {
UNREACHABLE();
return NULL;
}
@@ -2000,7 +2223,7 @@
}
-LocationSummary* CheckStackOverflowInstr::MakeLocationSummary() const {
+LocationSummary* CheckStackOverflowInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 0;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -2190,7 +2413,7 @@
}
-LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const {
+LocationSummary* BinarySmiOpInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
if (op_kind() == Token::kTRUNCDIV) {
const intptr_t kNumTemps = 1;
@@ -2560,7 +2783,7 @@
}
-LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary() const {
+LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary(bool opt) const {
intptr_t left_cid = left()->Type()->ToCid();
intptr_t right_cid = right()->Type()->ToCid();
ASSERT((left_cid != kDoubleCid) && (right_cid != kDoubleCid));
@@ -2596,7 +2819,7 @@
}
-LocationSummary* BoxDoubleInstr::MakeLocationSummary() const {
+LocationSummary* BoxDoubleInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -2609,38 +2832,6 @@
}
-class BoxDoubleSlowPath : public SlowPathCode {
- public:
- explicit BoxDoubleSlowPath(BoxDoubleInstr* instruction)
- : instruction_(instruction) { }
-
- virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
- __ Comment("BoxDoubleSlowPath");
- __ Bind(entry_label());
- const Class& double_class = compiler->double_class();
- const Code& stub =
- Code::Handle(StubCode::GetAllocationStubForClass(double_class));
- const ExternalLabel label(double_class.ToCString(), stub.EntryPoint());
-
- LocationSummary* locs = instruction_->locs();
- locs->live_registers()->Remove(locs->out());
-
- compiler->SaveLiveRegisters(locs);
- compiler->GenerateCall(Scanner::kDummyTokenIndex, // No token position.
- &label,
- PcDescriptors::kOther,
- locs);
- __ MoveRegister(locs->out().reg(), EAX);
- compiler->RestoreLiveRegisters(locs);
-
- __ jmp(exit_label());
- }
-
- private:
- BoxDoubleInstr* instruction_;
-};
-
-
void BoxDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
BoxDoubleSlowPath* slow_path = new BoxDoubleSlowPath(this);
compiler->AddSlowPathCode(slow_path);
@@ -2657,7 +2848,7 @@
}
-LocationSummary* UnboxDoubleInstr::MakeLocationSummary() const {
+LocationSummary* UnboxDoubleInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t value_cid = value()->Type()->ToCid();
const bool needs_temp = ((value_cid != kSmiCid) && (value_cid != kDoubleCid));
@@ -2703,7 +2894,7 @@
}
-LocationSummary* BoxFloat32x4Instr::MakeLocationSummary() const {
+LocationSummary* BoxFloat32x4Instr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -2764,7 +2955,7 @@
}
-LocationSummary* UnboxFloat32x4Instr::MakeLocationSummary() const {
+LocationSummary* UnboxFloat32x4Instr::MakeLocationSummary(bool opt) const {
const intptr_t value_cid = value()->Type()->ToCid();
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = value_cid == kFloat32x4Cid ? 0 : 1;
@@ -2797,7 +2988,7 @@
}
-LocationSummary* BoxInt32x4Instr::MakeLocationSummary() const {
+LocationSummary* BoxInt32x4Instr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -2858,7 +3049,7 @@
}
-LocationSummary* UnboxInt32x4Instr::MakeLocationSummary() const {
+LocationSummary* UnboxInt32x4Instr::MakeLocationSummary(bool opt) const {
const intptr_t value_cid = value()->Type()->ToCid();
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = value_cid == kInt32x4Cid ? 0 : 1;
@@ -2892,7 +3083,7 @@
-LocationSummary* BinaryDoubleOpInstr::MakeLocationSummary() const {
+LocationSummary* BinaryDoubleOpInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -2920,7 +3111,7 @@
}
-LocationSummary* BinaryFloat32x4OpInstr::MakeLocationSummary() const {
+LocationSummary* BinaryFloat32x4OpInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -2948,7 +3139,7 @@
}
-LocationSummary* Simd32x4ShuffleInstr::MakeLocationSummary() const {
+LocationSummary* Simd32x4ShuffleInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -2990,7 +3181,7 @@
}
-LocationSummary* Simd32x4ShuffleMixInstr::MakeLocationSummary() const {
+LocationSummary* Simd32x4ShuffleMixInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3017,7 +3208,7 @@
}
-LocationSummary* Simd32x4GetSignMaskInstr::MakeLocationSummary() const {
+LocationSummary* Simd32x4GetSignMaskInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3037,7 +3228,8 @@
}
-LocationSummary* Float32x4ConstructorInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4ConstructorInstr::MakeLocationSummary(
+ bool opt) const {
const intptr_t kNumInputs = 4;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3074,7 +3266,7 @@
}
-LocationSummary* Float32x4ZeroInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4ZeroInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 0;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3090,7 +3282,7 @@
}
-LocationSummary* Float32x4SplatInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4SplatInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3111,7 +3303,7 @@
}
-LocationSummary* Float32x4ComparisonInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4ComparisonInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3154,7 +3346,7 @@
}
-LocationSummary* Float32x4MinMaxInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4MinMaxInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3184,7 +3376,7 @@
}
-LocationSummary* Float32x4ScaleInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4ScaleInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3213,7 +3405,7 @@
}
-LocationSummary* Float32x4SqrtInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4SqrtInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3244,7 +3436,7 @@
}
-LocationSummary* Float32x4ZeroArgInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4ZeroArgInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3271,7 +3463,7 @@
}
-LocationSummary* Float32x4ClampInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4ClampInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 3;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3294,7 +3486,7 @@
}
-LocationSummary* Float32x4WithInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4WithInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3362,7 +3554,7 @@
}
-LocationSummary* Float32x4ToInt32x4Instr::MakeLocationSummary() const {
+LocationSummary* Float32x4ToInt32x4Instr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3378,7 +3570,8 @@
}
-LocationSummary* Int32x4BoolConstructorInstr::MakeLocationSummary() const {
+LocationSummary* Int32x4BoolConstructorInstr::MakeLocationSummary(
+ bool opt) const {
const intptr_t kNumInputs = 4;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3440,7 +3633,7 @@
}
-LocationSummary* Int32x4GetFlagInstr::MakeLocationSummary() const {
+LocationSummary* Int32x4GetFlagInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3485,7 +3678,7 @@
}
-LocationSummary* Int32x4SelectInstr::MakeLocationSummary() const {
+LocationSummary* Int32x4SelectInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 3;
const intptr_t kNumTemps = 1;
LocationSummary* summary =
@@ -3519,7 +3712,7 @@
}
-LocationSummary* Int32x4SetFlagInstr::MakeLocationSummary() const {
+LocationSummary* Int32x4SetFlagInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3575,7 +3768,7 @@
}
-LocationSummary* Int32x4ToFloat32x4Instr::MakeLocationSummary() const {
+LocationSummary* Int32x4ToFloat32x4Instr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3591,7 +3784,7 @@
}
-LocationSummary* BinaryInt32x4OpInstr::MakeLocationSummary() const {
+LocationSummary* BinaryInt32x4OpInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3631,7 +3824,7 @@
}
-LocationSummary* MathUnaryInstr::MakeLocationSummary() const {
+LocationSummary* MathUnaryInstr::MakeLocationSummary(bool opt) const {
if ((kind() == MethodRecognizer::kMathSin) ||
(kind() == MethodRecognizer::kMathCos)) {
const intptr_t kNumInputs = 1;
@@ -3667,7 +3860,7 @@
}
-LocationSummary* MathMinMaxInstr::MakeLocationSummary() const {
+LocationSummary* MathMinMaxInstr::MakeLocationSummary(bool opt) const {
if (result_cid() == kDoubleCid) {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 1;
@@ -3755,7 +3948,7 @@
}
-LocationSummary* UnarySmiOpInstr::MakeLocationSummary() const {
+LocationSummary* UnarySmiOpInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
return LocationSummary::Make(kNumInputs,
Location::SameAsFirstInput(),
@@ -3784,7 +3977,7 @@
}
-LocationSummary* UnaryDoubleOpInstr::MakeLocationSummary() const {
+LocationSummary* UnaryDoubleOpInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3802,7 +3995,7 @@
}
-LocationSummary* SmiToDoubleInstr::MakeLocationSummary() const {
+LocationSummary* SmiToDoubleInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* result =
@@ -3821,7 +4014,7 @@
}
-LocationSummary* DoubleToIntegerInstr::MakeLocationSummary() const {
+LocationSummary* DoubleToIntegerInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* result =
@@ -3865,7 +4058,7 @@
}
-LocationSummary* DoubleToSmiInstr::MakeLocationSummary() const {
+LocationSummary* DoubleToSmiInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* result = new LocationSummary(
@@ -3888,7 +4081,7 @@
}
-LocationSummary* DoubleToDoubleInstr::MakeLocationSummary() const {
+LocationSummary* DoubleToDoubleInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* result =
@@ -3918,7 +4111,7 @@
}
-LocationSummary* InvokeMathCFunctionInstr::MakeLocationSummary() const {
+LocationSummary* InvokeMathCFunctionInstr::MakeLocationSummary(bool opt) const {
ASSERT((InputCount() == 1) || (InputCount() == 2));
const intptr_t kNumTemps = 0;
LocationSummary* result =
@@ -3989,7 +4182,7 @@
}
-LocationSummary* MergedMathInstr::MakeLocationSummary() const {
+LocationSummary* MergedMathInstr::MakeLocationSummary(bool opt) const {
if (kind() == MergedMathInstr::kTruncDivMod) {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 1;
@@ -4139,7 +4332,8 @@
}
-LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary() const {
+LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary(
+ bool opt) const {
return MakeCallSummary();
}
@@ -4182,9 +4376,11 @@
}
-LocationSummary* BranchInstr::MakeLocationSummary() const {
- UNREACHABLE();
- return NULL;
+LocationSummary* BranchInstr::MakeLocationSummary(bool opt) const {
+ comparison()->InitializeLocationSummary(opt);
+ // Branches don't produce a result.
+ comparison()->locs()->set_out(Location::NoLocation());
+ return comparison()->locs();
}
@@ -4193,7 +4389,7 @@
}
-LocationSummary* CheckClassInstr::MakeLocationSummary() const {
+LocationSummary* CheckClassInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -4253,7 +4449,7 @@
}
-LocationSummary* CheckSmiInstr::MakeLocationSummary() const {
+LocationSummary* CheckSmiInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -4272,7 +4468,7 @@
}
-LocationSummary* CheckArrayBoundInstr::MakeLocationSummary() const {
+LocationSummary* CheckArrayBoundInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -4325,7 +4521,7 @@
}
-LocationSummary* UnboxIntegerInstr::MakeLocationSummary() const {
+LocationSummary* UnboxIntegerInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t value_cid = value()->Type()->ToCid();
const bool needs_temp = ((value_cid != kSmiCid) && (value_cid != kMintCid));
@@ -4373,7 +4569,7 @@
}
-LocationSummary* BoxIntegerInstr::MakeLocationSummary() const {
+LocationSummary* BoxIntegerInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 2;
LocationSummary* summary =
@@ -4461,7 +4657,7 @@
}
-LocationSummary* BinaryMintOpInstr::MakeLocationSummary() const {
+LocationSummary* BinaryMintOpInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
switch (op_kind()) {
case Token::kBIT_AND:
@@ -4551,7 +4747,7 @@
}
-LocationSummary* ShiftMintOpInstr::MakeLocationSummary() const {
+LocationSummary* ShiftMintOpInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = op_kind() == Token::kSHL ? 2 : 1;
LocationSummary* summary =
@@ -4625,7 +4821,7 @@
}
-LocationSummary* UnaryMintOpInstr::MakeLocationSummary() const {
+LocationSummary* UnaryMintOpInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps =
FLAG_throw_on_javascript_int_overflow ? 1 : 0;
@@ -4658,7 +4854,7 @@
}
-LocationSummary* ThrowInstr::MakeLocationSummary() const {
+LocationSummary* ThrowInstr::MakeLocationSummary(bool opt) const {
return new LocationSummary(0, 0, LocationSummary::kCall);
}
@@ -4674,7 +4870,7 @@
}
-LocationSummary* ReThrowInstr::MakeLocationSummary() const {
+LocationSummary* ReThrowInstr::MakeLocationSummary(bool opt) const {
return new LocationSummary(0, 0, LocationSummary::kCall);
}
@@ -4714,7 +4910,7 @@
}
-LocationSummary* GotoInstr::MakeLocationSummary() const {
+LocationSummary* GotoInstr::MakeLocationSummary(bool opt) const {
return new LocationSummary(0, 0, LocationSummary::kNoCall);
}
@@ -4743,7 +4939,7 @@
}
-LocationSummary* CurrentContextInstr::MakeLocationSummary() const {
+LocationSummary* CurrentContextInstr::MakeLocationSummary(bool opt) const {
return LocationSummary::Make(0,
Location::RequiresRegister(),
LocationSummary::kNoCall);
@@ -4755,7 +4951,7 @@
}
-LocationSummary* StrictCompareInstr::MakeLocationSummary() const {
+LocationSummary* StrictCompareInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
if (needs_number_check()) {
@@ -4841,11 +5037,11 @@
}
-LocationSummary* IfThenElseInstr::MakeLocationSummary() const {
- LocationSummary* locs = comparison()->MakeLocationSummary();
+LocationSummary* IfThenElseInstr::MakeLocationSummary(bool opt) const {
+ comparison()->InitializeLocationSummary(opt);
// TODO(vegorov): support byte register constraints in the register allocator.
- locs->set_out(Location::RegisterLocation(EDX));
- return locs;
+ comparison()->locs()->set_out(Location::RegisterLocation(EDX));
+ return comparison()->locs();
}
@@ -4898,7 +5094,7 @@
}
-LocationSummary* ClosureCallInstr::MakeLocationSummary() const {
+LocationSummary* ClosureCallInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 0;
const intptr_t kNumTemps = 1;
LocationSummary* result =
@@ -4928,7 +5124,7 @@
}
-LocationSummary* BooleanNegateInstr::MakeLocationSummary() const {
+LocationSummary* BooleanNegateInstr::MakeLocationSummary(bool opt) const {
return LocationSummary::Make(1,
Location::RequiresRegister(),
LocationSummary::kNoCall);
@@ -4948,7 +5144,7 @@
}
-LocationSummary* StoreVMFieldInstr::MakeLocationSummary() const {
+LocationSummary* StoreVMFieldInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -4974,7 +5170,7 @@
}
-LocationSummary* AllocateObjectInstr::MakeLocationSummary() const {
+LocationSummary* AllocateObjectInstr::MakeLocationSummary(bool opt) const {
return MakeCallSummary();
}
@@ -4990,7 +5186,7 @@
}
-LocationSummary* CreateClosureInstr::MakeLocationSummary() const {
+LocationSummary* CreateClosureInstr::MakeLocationSummary(bool opt) const {
return MakeCallSummary();
}
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index 07ac406..3473a36 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -34,7 +34,7 @@
}
-LocationSummary* PushArgumentInstr::MakeLocationSummary() const {
+LocationSummary* PushArgumentInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps= 0;
LocationSummary* locs =
@@ -64,7 +64,7 @@
}
-LocationSummary* ReturnInstr::MakeLocationSummary() const {
+LocationSummary* ReturnInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -134,8 +134,9 @@
}
-LocationSummary* IfThenElseInstr::MakeLocationSummary() const {
- return comparison()->MakeLocationSummary();
+LocationSummary* IfThenElseInstr::MakeLocationSummary(bool opt) const {
+ comparison()->InitializeLocationSummary(opt);
+ return comparison()->locs();
}
@@ -215,7 +216,7 @@
}
-LocationSummary* ClosureCallInstr::MakeLocationSummary() const {
+LocationSummary* ClosureCallInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 0;
const intptr_t kNumTemps = 1;
LocationSummary* result =
@@ -245,7 +246,7 @@
}
-LocationSummary* LoadLocalInstr::MakeLocationSummary() const {
+LocationSummary* LoadLocalInstr::MakeLocationSummary(bool opt) const {
return LocationSummary::Make(0,
Location::RequiresRegister(),
LocationSummary::kNoCall);
@@ -259,7 +260,7 @@
}
-LocationSummary* StoreLocalInstr::MakeLocationSummary() const {
+LocationSummary* StoreLocalInstr::MakeLocationSummary(bool opt) const {
return LocationSummary::Make(1,
Location::SameAsFirstInput(),
LocationSummary::kNoCall);
@@ -275,7 +276,7 @@
}
-LocationSummary* ConstantInstr::MakeLocationSummary() const {
+LocationSummary* ConstantInstr::MakeLocationSummary(bool opt) const {
return LocationSummary::Make(0,
Location::RequiresRegister(),
LocationSummary::kNoCall);
@@ -292,7 +293,7 @@
}
-LocationSummary* AssertAssignableInstr::MakeLocationSummary() const {
+LocationSummary* AssertAssignableInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 3;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -305,7 +306,7 @@
}
-LocationSummary* AssertBooleanInstr::MakeLocationSummary() const {
+LocationSummary* AssertBooleanInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -350,7 +351,7 @@
}
-LocationSummary* EqualityCompareInstr::MakeLocationSummary() const {
+LocationSummary* EqualityCompareInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
if (operation_cid() == kMintCid) {
const intptr_t kNumTemps = 1;
@@ -602,7 +603,7 @@
}
-LocationSummary* TestSmiInstr::MakeLocationSummary() const {
+LocationSummary* TestSmiInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -647,7 +648,7 @@
}
-LocationSummary* RelationalOpInstr::MakeLocationSummary() const {
+LocationSummary* RelationalOpInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
if (operation_cid() == kMintCid) {
@@ -723,7 +724,7 @@
}
-LocationSummary* NativeCallInstr::MakeLocationSummary() const {
+LocationSummary* NativeCallInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 0;
const intptr_t kNumTemps = 3;
LocationSummary* locs =
@@ -768,6 +769,12 @@
// stub generates the redirection address when running under the simulator
// and hence we do not change 'entry' here.
stub_entry = &StubCode::CallNativeCFunctionLabel();
+#if defined(USING_SIMULATOR)
+ if (!function().IsNativeAutoSetupScope()) {
+ entry = Simulator::RedirectExternalReference(
+ entry, Simulator::kBootstrapNativeCall, function().NumParameters());
+ }
+#endif
}
__ LoadImmediate(T5, entry);
__ LoadImmediate(A1, NativeArguments::ComputeArgcTag(function()));
@@ -779,7 +786,7 @@
}
-LocationSummary* StringFromCharCodeInstr::MakeLocationSummary() const {
+LocationSummary* StringFromCharCodeInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
// TODO(fschneider): Allow immediate operands for the char code.
return LocationSummary::Make(kNumInputs,
@@ -803,7 +810,7 @@
}
-LocationSummary* StringInterpolateInstr::MakeLocationSummary() const {
+LocationSummary* StringInterpolateInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -829,7 +836,7 @@
}
-LocationSummary* LoadUntaggedInstr::MakeLocationSummary() const {
+LocationSummary* LoadUntaggedInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
return LocationSummary::Make(kNumInputs,
Location::RequiresRegister(),
@@ -844,7 +851,7 @@
}
-LocationSummary* LoadClassIdInstr::MakeLocationSummary() const {
+LocationSummary* LoadClassIdInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
return LocationSummary::Make(kNumInputs,
Location::RequiresRegister(),
@@ -940,7 +947,7 @@
}
-LocationSummary* LoadIndexedInstr::MakeLocationSummary() const {
+LocationSummary* LoadIndexedInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -1123,7 +1130,7 @@
}
-LocationSummary* StoreIndexedInstr::MakeLocationSummary() const {
+LocationSummary* StoreIndexedInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 3;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -1307,7 +1314,7 @@
}
-LocationSummary* GuardFieldInstr::MakeLocationSummary() const {
+LocationSummary* GuardFieldInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
LocationSummary* summary =
new LocationSummary(kNumInputs, 0, LocationSummary::kNoCall);
@@ -1640,21 +1647,145 @@
}
-LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary() const {
+class StoreInstanceFieldSlowPath : public SlowPathCode {
+ public:
+ explicit StoreInstanceFieldSlowPath(StoreInstanceFieldInstr* instruction)
+ : instruction_(instruction) { }
+
+ virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
+ __ Comment("StoreInstanceFieldSlowPath");
+ __ Bind(entry_label());
+ const Class& double_class = compiler->double_class();
+ const Code& stub =
+ Code::Handle(StubCode::GetAllocationStubForClass(double_class));
+ const ExternalLabel label(double_class.ToCString(), stub.EntryPoint());
+
+ LocationSummary* locs = instruction_->locs();
+ locs->live_registers()->Remove(locs->out());
+
+ compiler->SaveLiveRegisters(locs);
+ compiler->GenerateCall(Scanner::kDummyTokenIndex, // No token position.
+ &label,
+ PcDescriptors::kOther,
+ locs);
+ __ mov(locs->temp(0).reg(), V0);
+ compiler->RestoreLiveRegisters(locs);
+
+ __ b(exit_label());
+ }
+
+ private:
+ StoreInstanceFieldInstr* instruction_;
+};
+
+
+LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
- new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ new LocationSummary(kNumInputs, kNumTemps,
+ (field().guarded_cid() == kIllegalCid) || (is_initialization_)
+ ? LocationSummary::kCallOnSlowPath
+ : LocationSummary::kNoCall);
+
summary->set_in(0, Location::RequiresRegister());
- summary->set_in(1, ShouldEmitStoreBarrier()
+ if (IsUnboxedStore() && opt) {
+ summary->set_in(1, Location::RequiresFpuRegister());
+ summary->AddTemp(Location::RequiresRegister());
+ summary->AddTemp(Location::RequiresRegister());
+ } else if (IsPotentialUnboxedStore()) {
+ summary->set_in(1, ShouldEmitStoreBarrier()
+ ? Location::WritableRegister()
+ : Location::RequiresRegister());
+ summary->AddTemp(Location::RequiresRegister());
+ summary->AddTemp(Location::RequiresRegister());
+ summary->AddTemp(opt ? Location::RequiresFpuRegister()
+ : Location::FpuRegisterLocation(D1));
+ } else {
+ summary->set_in(1, ShouldEmitStoreBarrier()
? Location::WritableRegister()
: Location::RegisterOrConstant(value()));
+ }
return summary;
}
void StoreInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ Label skip_store;
+
Register instance_reg = locs()->in(0).reg();
+
+ if (IsUnboxedStore() && compiler->is_optimizing()) {
+ DRegister value = locs()->in(1).fpu_reg();
+ Register temp = locs()->temp(0).reg();
+ Register temp2 = locs()->temp(1).reg();
+
+ if (is_initialization_) {
+ StoreInstanceFieldSlowPath* slow_path =
+ new StoreInstanceFieldSlowPath(this);
+ compiler->AddSlowPathCode(slow_path);
+ __ TryAllocate(compiler->double_class(),
+ slow_path->entry_label(),
+ temp);
+ __ Bind(slow_path->exit_label());
+ __ mov(temp2, temp);
+ __ StoreIntoObject(instance_reg,
+ FieldAddress(instance_reg, field().Offset()),
+ temp2);
+ } else {
+ __ lw(temp, FieldAddress(instance_reg, field().Offset()));
+ }
+ __ StoreDToOffset(value, temp, Double::value_offset() - kHeapObjectTag);
+ return;
+ }
+
+ if (IsPotentialUnboxedStore()) {
+ Register value_reg = locs()->in(1).reg();
+ Register temp = locs()->temp(0).reg();
+ Register temp2 = locs()->temp(1).reg();
+ DRegister fpu_temp = locs()->temp(2).fpu_reg();
+
+ Label store_pointer, copy_payload;
+ __ LoadObject(temp, Field::ZoneHandle(field().raw()));
+ __ lw(temp2, FieldAddress(temp, Field::guarded_cid_offset()));
+ __ BranchNotEqual(temp2, kDoubleCid, &store_pointer);
+ __ lw(temp2, FieldAddress(temp, Field::is_nullable_offset()));
+ __ BranchEqual(temp2, kNullCid, &store_pointer);
+ __ lbu(temp2, FieldAddress(temp, Field::kind_bits_offset()));
+ __ andi(CMPRES1, temp2, Immediate(1 << Field::kUnboxingCandidateBit));
+ __ beq(CMPRES1, ZR, &store_pointer);
+
+ __ lw(temp, FieldAddress(instance_reg, field().Offset()));
+ __ BranchNotEqual(temp, reinterpret_cast<int32_t>(Object::null()),
+ ©_payload);
+
+ StoreInstanceFieldSlowPath* slow_path =
+ new StoreInstanceFieldSlowPath(this);
+ compiler->AddSlowPathCode(slow_path);
+
+ if (!compiler->is_optimizing()) {
+ locs()->live_registers()->Add(locs()->in(0));
+ locs()->live_registers()->Add(locs()->in(1));
+ }
+
+ __ TryAllocate(compiler->double_class(),
+ slow_path->entry_label(),
+ temp);
+ __ Bind(slow_path->exit_label());
+ __ mov(temp2, temp);
+ __ StoreIntoObject(instance_reg,
+ FieldAddress(instance_reg, field().Offset()),
+ temp2);
+
+ __ Bind(©_payload);
+ __ LoadDFromOffset(fpu_temp,
+ value_reg,
+ Double::value_offset() - kHeapObjectTag);
+ __ StoreDToOffset(fpu_temp, temp, Double::value_offset() - kHeapObjectTag);
+ __ b(&skip_store);
+ __ Bind(&store_pointer);
+ }
+
if (ShouldEmitStoreBarrier()) {
Register value_reg = locs()->in(1).reg();
__ StoreIntoObject(instance_reg,
@@ -1673,10 +1804,11 @@
FieldAddress(instance_reg, field().Offset()), value_reg);
}
}
+ __ Bind(&skip_store);
}
-LocationSummary* LoadStaticFieldInstr::MakeLocationSummary() const {
+LocationSummary* LoadStaticFieldInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -1700,7 +1832,7 @@
}
-LocationSummary* StoreStaticFieldInstr::MakeLocationSummary() const {
+LocationSummary* StoreStaticFieldInstr::MakeLocationSummary(bool opt) const {
LocationSummary* locs = new LocationSummary(1, 1, LocationSummary::kNoCall);
locs->set_in(0, value()->NeedsStoreBuffer() ? Location::WritableRegister()
: Location::RequiresRegister());
@@ -1725,7 +1857,7 @@
}
-LocationSummary* InstanceOfInstr::MakeLocationSummary() const {
+LocationSummary* InstanceOfInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 3;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -1753,7 +1885,7 @@
}
-LocationSummary* CreateArrayInstr::MakeLocationSummary() const {
+LocationSummary* CreateArrayInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -1778,7 +1910,7 @@
LocationSummary*
-AllocateObjectWithBoundsCheckInstr::MakeLocationSummary() const {
+AllocateObjectWithBoundsCheckInstr::MakeLocationSummary(bool opt) const {
return MakeCallSummary();
}
@@ -1796,22 +1928,118 @@
}
-LocationSummary* LoadFieldInstr::MakeLocationSummary() const {
- return LocationSummary::Make(1,
- Location::RequiresRegister(),
- LocationSummary::kNoCall);
+class BoxDoubleSlowPath : public SlowPathCode {
+ public:
+ explicit BoxDoubleSlowPath(Instruction* instruction)
+ : instruction_(instruction) { }
+
+ virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
+ __ Comment("BoxDoubleSlowPath");
+ __ Bind(entry_label());
+ const Class& double_class = compiler->double_class();
+ const Code& stub =
+ Code::Handle(StubCode::GetAllocationStubForClass(double_class));
+ const ExternalLabel label(double_class.ToCString(), stub.EntryPoint());
+
+ LocationSummary* locs = instruction_->locs();
+ locs->live_registers()->Remove(locs->out());
+
+ compiler->SaveLiveRegisters(locs);
+ compiler->GenerateCall(Scanner::kDummyTokenIndex, // No token position.
+ &label,
+ PcDescriptors::kOther,
+ locs);
+ if (locs->out().reg() != V0) {
+ __ mov(locs->out().reg(), V0);
+ }
+ compiler->RestoreLiveRegisters(locs);
+
+ __ b(exit_label());
+ }
+
+ private:
+ Instruction* instruction_;
+};
+
+
+LocationSummary* LoadFieldInstr::MakeLocationSummary(bool opt) const {
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* locs =
+ new LocationSummary(
+ kNumInputs, kNumTemps,
+ (opt && !IsPotentialUnboxedLoad())
+ ? LocationSummary::kNoCall
+ : LocationSummary::kCallOnSlowPath);
+
+ locs->set_in(0, Location::RequiresRegister());
+
+ if (IsUnboxedLoad() && opt) {
+ locs->AddTemp(Location::RequiresRegister());
+ } else if (IsPotentialUnboxedLoad()) {
+ locs->AddTemp(opt ? Location::RequiresFpuRegister()
+ : Location::FpuRegisterLocation(D1));
+ locs->AddTemp(Location::RequiresRegister());
+ }
+ locs->set_out(Location::RequiresRegister());
+ return locs;
}
void LoadFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register instance_reg = locs()->in(0).reg();
- Register result_reg = locs()->out().reg();
+ if (IsUnboxedLoad() && compiler->is_optimizing()) {
+ DRegister result = locs()->out().fpu_reg();
+ Register temp = locs()->temp(0).reg();
+ __ lw(temp, FieldAddress(instance_reg, offset_in_bytes()));
+ __ LoadDFromOffset(result, temp, Double::value_offset() - kHeapObjectTag);
+ return;
+ }
+ Label done;
+ Register result_reg = locs()->out().reg();
+ if (IsPotentialUnboxedLoad()) {
+ Register temp = locs()->temp(1).reg();
+ DRegister value = locs()->temp(0).fpu_reg();
+
+ Label load_pointer;
+ __ LoadObject(result_reg, Field::ZoneHandle(field()->raw()));
+
+ FieldAddress field_cid_operand(result_reg, Field::guarded_cid_offset());
+ FieldAddress field_nullability_operand(result_reg,
+ Field::is_nullable_offset());
+
+ __ lw(temp, field_cid_operand);
+ __ BranchNotEqual(temp, kDoubleCid, &load_pointer);
+
+ __ lw(temp, field_nullability_operand);
+ __ BranchEqual(temp, kNullCid, &load_pointer);
+
+ BoxDoubleSlowPath* slow_path = new BoxDoubleSlowPath(this);
+ compiler->AddSlowPathCode(slow_path);
+
+ if (!compiler->is_optimizing()) {
+ locs()->live_registers()->Add(locs()->in(0));
+ }
+
+ __ TryAllocate(compiler->double_class(),
+ slow_path->entry_label(),
+ result_reg);
+ __ Bind(slow_path->exit_label());
+ __ lw(temp, FieldAddress(instance_reg, offset_in_bytes()));
+ __ LoadDFromOffset(value, temp, Double::value_offset() - kHeapObjectTag);
+ __ StoreDToOffset(value,
+ result_reg,
+ Double::value_offset() - kHeapObjectTag);
+ __ b(&done);
+ __ Bind(&load_pointer);
+ }
__ lw(result_reg, Address(instance_reg, offset_in_bytes() - kHeapObjectTag));
+ __ Bind(&done);
}
-LocationSummary* InstantiateTypeInstr::MakeLocationSummary() const {
+LocationSummary* InstantiateTypeInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -1851,7 +2079,8 @@
}
-LocationSummary* InstantiateTypeArgumentsInstr::MakeLocationSummary() const {
+LocationSummary* InstantiateTypeArgumentsInstr::MakeLocationSummary(
+ bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -1907,7 +2136,7 @@
LocationSummary*
-ExtractConstructorTypeArgumentsInstr::MakeLocationSummary() const {
+ExtractConstructorTypeArgumentsInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -1948,7 +2177,7 @@
LocationSummary*
-ExtractConstructorInstantiatorInstr::MakeLocationSummary() const {
+ExtractConstructorInstantiatorInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -1986,7 +2215,7 @@
}
-LocationSummary* AllocateContextInstr::MakeLocationSummary() const {
+LocationSummary* AllocateContextInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 0;
const intptr_t kNumTemps = 1;
LocationSummary* locs =
@@ -2013,7 +2242,7 @@
}
-LocationSummary* CloneContextInstr::MakeLocationSummary() const {
+LocationSummary* CloneContextInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -2045,7 +2274,7 @@
}
-LocationSummary* CatchBlockEntryInstr::MakeLocationSummary() const {
+LocationSummary* CatchBlockEntryInstr::MakeLocationSummary(bool opt) const {
UNREACHABLE();
return NULL;
}
@@ -2085,7 +2314,7 @@
}
-LocationSummary* CheckStackOverflowInstr::MakeLocationSummary() const {
+LocationSummary* CheckStackOverflowInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 0;
const intptr_t kNumTemps = 1;
LocationSummary* summary =
@@ -2273,7 +2502,7 @@
}
-LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const {
+LocationSummary* BinarySmiOpInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = op_kind() == Token::kADD ? 1 : 0;
LocationSummary* summary =
@@ -2619,7 +2848,7 @@
}
-LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary() const {
+LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary(bool opt) const {
intptr_t left_cid = left()->Type()->ToCid();
intptr_t right_cid = right()->Type()->ToCid();
ASSERT((left_cid != kDoubleCid) && (right_cid != kDoubleCid));
@@ -2651,7 +2880,7 @@
}
-LocationSummary* BoxDoubleInstr::MakeLocationSummary() const {
+LocationSummary* BoxDoubleInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -2664,40 +2893,6 @@
}
-class BoxDoubleSlowPath : public SlowPathCode {
- public:
- explicit BoxDoubleSlowPath(BoxDoubleInstr* instruction)
- : instruction_(instruction) { }
-
- virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
- __ Comment("BoxDoubleSlowPath");
- __ Bind(entry_label());
- const Class& double_class = compiler->double_class();
- const Code& stub =
- Code::Handle(StubCode::GetAllocationStubForClass(double_class));
- const ExternalLabel label(double_class.ToCString(), stub.EntryPoint());
-
- LocationSummary* locs = instruction_->locs();
- locs->live_registers()->Remove(locs->out());
-
- compiler->SaveLiveRegisters(locs);
- compiler->GenerateCall(Scanner::kDummyTokenIndex, // No token position.
- &label,
- PcDescriptors::kOther,
- locs);
- if (locs->out().reg() != V0) {
- __ mov(locs->out().reg(), V0);
- }
- compiler->RestoreLiveRegisters(locs);
-
- __ b(exit_label());
- }
-
- private:
- BoxDoubleInstr* instruction_;
-};
-
-
void BoxDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
BoxDoubleSlowPath* slow_path = new BoxDoubleSlowPath(this);
compiler->AddSlowPathCode(slow_path);
@@ -2713,7 +2908,7 @@
}
-LocationSummary* UnboxDoubleInstr::MakeLocationSummary() const {
+LocationSummary* UnboxDoubleInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t value_cid = value()->Type()->ToCid();
const bool needs_writable_input = (value_cid == kSmiCid);
@@ -2759,7 +2954,7 @@
}
-LocationSummary* BoxFloat32x4Instr::MakeLocationSummary() const {
+LocationSummary* BoxFloat32x4Instr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -2770,7 +2965,7 @@
}
-LocationSummary* UnboxFloat32x4Instr::MakeLocationSummary() const {
+LocationSummary* UnboxFloat32x4Instr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -2781,7 +2976,7 @@
}
-LocationSummary* BoxInt32x4Instr::MakeLocationSummary() const {
+LocationSummary* BoxInt32x4Instr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -2792,7 +2987,7 @@
}
-LocationSummary* UnboxInt32x4Instr::MakeLocationSummary() const {
+LocationSummary* UnboxInt32x4Instr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -2803,7 +2998,7 @@
}
-LocationSummary* BinaryDoubleOpInstr::MakeLocationSummary() const {
+LocationSummary* BinaryDoubleOpInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -2829,7 +3024,7 @@
}
-LocationSummary* BinaryFloat32x4OpInstr::MakeLocationSummary() const {
+LocationSummary* BinaryFloat32x4OpInstr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -2840,7 +3035,7 @@
}
-LocationSummary* Simd32x4ShuffleInstr::MakeLocationSummary() const {
+LocationSummary* Simd32x4ShuffleInstr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -2852,7 +3047,7 @@
-LocationSummary* Simd32x4ShuffleMixInstr::MakeLocationSummary() const {
+LocationSummary* Simd32x4ShuffleMixInstr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -2863,7 +3058,8 @@
}
-LocationSummary* Float32x4ConstructorInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4ConstructorInstr::MakeLocationSummary(
+ bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -2874,7 +3070,7 @@
}
-LocationSummary* Float32x4ZeroInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4ZeroInstr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -2885,7 +3081,7 @@
}
-LocationSummary* Float32x4SplatInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4SplatInstr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -2896,7 +3092,7 @@
}
-LocationSummary* Float32x4ComparisonInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4ComparisonInstr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -2907,7 +3103,7 @@
}
-LocationSummary* Float32x4MinMaxInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4MinMaxInstr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -2918,7 +3114,7 @@
}
-LocationSummary* Float32x4SqrtInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4SqrtInstr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -2929,7 +3125,7 @@
}
-LocationSummary* Float32x4ScaleInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4ScaleInstr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -2940,7 +3136,7 @@
}
-LocationSummary* Float32x4ZeroArgInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4ZeroArgInstr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -2951,7 +3147,7 @@
}
-LocationSummary* Float32x4ClampInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4ClampInstr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -2962,7 +3158,7 @@
}
-LocationSummary* Float32x4WithInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4WithInstr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -2973,7 +3169,7 @@
}
-LocationSummary* Float32x4ToInt32x4Instr::MakeLocationSummary() const {
+LocationSummary* Float32x4ToInt32x4Instr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -2984,7 +3180,8 @@
}
-LocationSummary* Int32x4BoolConstructorInstr::MakeLocationSummary() const {
+LocationSummary* Int32x4BoolConstructorInstr::MakeLocationSummary(
+ bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -2995,7 +3192,7 @@
}
-LocationSummary* Int32x4GetFlagInstr::MakeLocationSummary() const {
+LocationSummary* Int32x4GetFlagInstr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -3006,7 +3203,7 @@
}
-LocationSummary* Simd32x4GetSignMaskInstr::MakeLocationSummary() const {
+LocationSummary* Simd32x4GetSignMaskInstr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -3017,7 +3214,7 @@
}
-LocationSummary* Int32x4SelectInstr::MakeLocationSummary() const {
+LocationSummary* Int32x4SelectInstr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -3028,7 +3225,7 @@
}
-LocationSummary* Int32x4SetFlagInstr::MakeLocationSummary() const {
+LocationSummary* Int32x4SetFlagInstr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -3039,7 +3236,7 @@
}
-LocationSummary* Int32x4ToFloat32x4Instr::MakeLocationSummary() const {
+LocationSummary* Int32x4ToFloat32x4Instr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -3050,7 +3247,7 @@
}
-LocationSummary* BinaryInt32x4OpInstr::MakeLocationSummary() const {
+LocationSummary* BinaryInt32x4OpInstr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -3061,7 +3258,7 @@
}
-LocationSummary* MathUnaryInstr::MakeLocationSummary() const {
+LocationSummary* MathUnaryInstr::MakeLocationSummary(bool opt) const {
if ((kind() == MethodRecognizer::kMathSin) ||
(kind() == MethodRecognizer::kMathCos)) {
const intptr_t kNumInputs = 1;
@@ -3091,7 +3288,7 @@
}
-LocationSummary* MathMinMaxInstr::MakeLocationSummary() const {
+LocationSummary* MathMinMaxInstr::MakeLocationSummary(bool opt) const {
if (result_cid() == kDoubleCid) {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 1;
@@ -3182,7 +3379,7 @@
}
-LocationSummary* UnarySmiOpInstr::MakeLocationSummary() const {
+LocationSummary* UnarySmiOpInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3216,7 +3413,7 @@
}
-LocationSummary* UnaryDoubleOpInstr::MakeLocationSummary() const {
+LocationSummary* UnaryDoubleOpInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 1;
LocationSummary* summary =
@@ -3241,7 +3438,7 @@
-LocationSummary* SmiToDoubleInstr::MakeLocationSummary() const {
+LocationSummary* SmiToDoubleInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* result =
@@ -3261,7 +3458,7 @@
}
-LocationSummary* DoubleToIntegerInstr::MakeLocationSummary() const {
+LocationSummary* DoubleToIntegerInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* result =
@@ -3307,7 +3504,7 @@
}
-LocationSummary* DoubleToSmiInstr::MakeLocationSummary() const {
+LocationSummary* DoubleToSmiInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* result = new LocationSummary(
@@ -3333,7 +3530,7 @@
}
-LocationSummary* DoubleToDoubleInstr::MakeLocationSummary() const {
+LocationSummary* DoubleToDoubleInstr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -3344,7 +3541,7 @@
}
-LocationSummary* InvokeMathCFunctionInstr::MakeLocationSummary() const {
+LocationSummary* InvokeMathCFunctionInstr::MakeLocationSummary(bool opt) const {
// Calling convetion on MIPS uses D6 and D7 to pass the first two
// double arguments.
ASSERT((InputCount() == 1) || (InputCount() == 2));
@@ -3406,7 +3603,7 @@
}
-LocationSummary* MergedMathInstr::MakeLocationSummary() const {
+LocationSummary* MergedMathInstr::MakeLocationSummary(bool opt) const {
if (kind() == MergedMathInstr::kTruncDivMod) {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 3;
@@ -3494,7 +3691,8 @@
}
-LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary() const {
+LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary(
+ bool opt) const {
return MakeCallSummary();
}
@@ -3537,9 +3735,11 @@
}
-LocationSummary* BranchInstr::MakeLocationSummary() const {
- UNREACHABLE();
- return NULL;
+LocationSummary* BranchInstr::MakeLocationSummary(bool opt) const {
+ comparison()->InitializeLocationSummary(opt);
+ // Branches don't produce a result.
+ comparison()->locs()->set_out(Location::NoLocation());
+ return comparison()->locs();
}
@@ -3549,7 +3749,7 @@
}
-LocationSummary* CheckClassInstr::MakeLocationSummary() const {
+LocationSummary* CheckClassInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3603,7 +3803,7 @@
}
-LocationSummary* CheckSmiInstr::MakeLocationSummary() const {
+LocationSummary* CheckSmiInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3623,7 +3823,7 @@
}
-LocationSummary* CheckArrayBoundInstr::MakeLocationSummary() const {
+LocationSummary* CheckArrayBoundInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -3675,7 +3875,7 @@
}
-LocationSummary* UnboxIntegerInstr::MakeLocationSummary() const {
+LocationSummary* UnboxIntegerInstr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -3686,7 +3886,7 @@
}
-LocationSummary* BoxIntegerInstr::MakeLocationSummary() const {
+LocationSummary* BoxIntegerInstr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -3697,7 +3897,7 @@
}
-LocationSummary* BinaryMintOpInstr::MakeLocationSummary() const {
+LocationSummary* BinaryMintOpInstr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -3708,7 +3908,7 @@
}
-LocationSummary* ShiftMintOpInstr::MakeLocationSummary() const {
+LocationSummary* ShiftMintOpInstr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -3719,7 +3919,7 @@
}
-LocationSummary* UnaryMintOpInstr::MakeLocationSummary() const {
+LocationSummary* UnaryMintOpInstr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -3730,7 +3930,7 @@
}
-LocationSummary* ThrowInstr::MakeLocationSummary() const {
+LocationSummary* ThrowInstr::MakeLocationSummary(bool opt) const {
return new LocationSummary(0, 0, LocationSummary::kCall);
}
@@ -3746,7 +3946,7 @@
}
-LocationSummary* ReThrowInstr::MakeLocationSummary() const {
+LocationSummary* ReThrowInstr::MakeLocationSummary(bool opt) const {
return new LocationSummary(0, 0, LocationSummary::kCall);
}
@@ -3786,7 +3986,7 @@
}
-LocationSummary* GotoInstr::MakeLocationSummary() const {
+LocationSummary* GotoInstr::MakeLocationSummary(bool opt) const {
return new LocationSummary(0, 0, LocationSummary::kNoCall);
}
@@ -3816,7 +4016,7 @@
}
-LocationSummary* CurrentContextInstr::MakeLocationSummary() const {
+LocationSummary* CurrentContextInstr::MakeLocationSummary(bool opt) const {
return LocationSummary::Make(0,
Location::RequiresRegister(),
LocationSummary::kNoCall);
@@ -3828,7 +4028,7 @@
}
-LocationSummary* StrictCompareInstr::MakeLocationSummary() const {
+LocationSummary* StrictCompareInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
if (needs_number_check()) {
@@ -3910,7 +4110,7 @@
}
-LocationSummary* BooleanNegateInstr::MakeLocationSummary() const {
+LocationSummary* BooleanNegateInstr::MakeLocationSummary(bool opt) const {
return LocationSummary::Make(1,
Location::RequiresRegister(),
LocationSummary::kNoCall);
@@ -3928,7 +4128,7 @@
}
-LocationSummary* StoreVMFieldInstr::MakeLocationSummary() const {
+LocationSummary* StoreVMFieldInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -3954,7 +4154,7 @@
}
-LocationSummary* AllocateObjectInstr::MakeLocationSummary() const {
+LocationSummary* AllocateObjectInstr::MakeLocationSummary(bool opt) const {
return MakeCallSummary();
}
@@ -3972,7 +4172,7 @@
}
-LocationSummary* CreateClosureInstr::MakeLocationSummary() const {
+LocationSummary* CreateClosureInstr::MakeLocationSummary(bool opt) const {
return MakeCallSummary();
}
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index 72160c2..a1eb248 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -34,7 +34,7 @@
}
-LocationSummary* PushArgumentInstr::MakeLocationSummary() const {
+LocationSummary* PushArgumentInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps= 0;
LocationSummary* locs =
@@ -61,7 +61,7 @@
}
-LocationSummary* ReturnInstr::MakeLocationSummary() const {
+LocationSummary* ReturnInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -130,11 +130,11 @@
}
-LocationSummary* IfThenElseInstr::MakeLocationSummary() const {
- LocationSummary* locs = comparison()->MakeLocationSummary();
+LocationSummary* IfThenElseInstr::MakeLocationSummary(bool opt) const {
+ comparison()->InitializeLocationSummary(opt);
// TODO(vegorov): support byte register constraints in the register allocator.
- locs->set_out(Location::RegisterLocation(RDX));
- return locs;
+ comparison()->locs()->set_out(Location::RegisterLocation(RDX));
+ return comparison()->locs();
}
@@ -187,7 +187,7 @@
}
-LocationSummary* LoadLocalInstr::MakeLocationSummary() const {
+LocationSummary* LoadLocalInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 0;
return LocationSummary::Make(kNumInputs,
Location::RequiresRegister(),
@@ -201,7 +201,7 @@
}
-LocationSummary* StoreLocalInstr::MakeLocationSummary() const {
+LocationSummary* StoreLocalInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
return LocationSummary::Make(kNumInputs,
Location::SameAsFirstInput(),
@@ -217,7 +217,7 @@
}
-LocationSummary* ConstantInstr::MakeLocationSummary() const {
+LocationSummary* ConstantInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 0;
return LocationSummary::Make(kNumInputs,
Location::RequiresRegister(),
@@ -234,7 +234,7 @@
}
-LocationSummary* AssertAssignableInstr::MakeLocationSummary() const {
+LocationSummary* AssertAssignableInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 3;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -247,7 +247,7 @@
}
-LocationSummary* AssertBooleanInstr::MakeLocationSummary() const {
+LocationSummary* AssertBooleanInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -308,7 +308,7 @@
}
-LocationSummary* EqualityCompareInstr::MakeLocationSummary() const {
+LocationSummary* EqualityCompareInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
if (operation_cid() == kDoubleCid) {
const intptr_t kNumTemps = 0;
@@ -491,7 +491,7 @@
}
-LocationSummary* TestSmiInstr::MakeLocationSummary() const {
+LocationSummary* TestSmiInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -535,7 +535,7 @@
}
-LocationSummary* RelationalOpInstr::MakeLocationSummary() const {
+LocationSummary* RelationalOpInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
if (operation_cid() == kDoubleCid) {
@@ -596,7 +596,7 @@
}
-LocationSummary* NativeCallInstr::MakeLocationSummary() const {
+LocationSummary* NativeCallInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 0;
const intptr_t kNumTemps = 3;
LocationSummary* locs =
@@ -652,7 +652,7 @@
}
-LocationSummary* StringFromCharCodeInstr::MakeLocationSummary() const {
+LocationSummary* StringFromCharCodeInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
// TODO(fschneider): Allow immediate operands for the char code.
return LocationSummary::Make(kNumInputs,
@@ -673,7 +673,7 @@
}
-LocationSummary* StringInterpolateInstr::MakeLocationSummary() const {
+LocationSummary* StringInterpolateInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -699,7 +699,7 @@
}
-LocationSummary* LoadUntaggedInstr::MakeLocationSummary() const {
+LocationSummary* LoadUntaggedInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
return LocationSummary::Make(kNumInputs,
Location::RequiresRegister(),
@@ -714,7 +714,7 @@
}
-LocationSummary* LoadClassIdInstr::MakeLocationSummary() const {
+LocationSummary* LoadClassIdInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
return LocationSummary::Make(kNumInputs,
Location::RequiresRegister(),
@@ -801,7 +801,7 @@
}
-LocationSummary* LoadIndexedInstr::MakeLocationSummary() const {
+LocationSummary* LoadIndexedInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -952,7 +952,7 @@
}
-LocationSummary* StoreIndexedInstr::MakeLocationSummary() const {
+LocationSummary* StoreIndexedInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 3;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -1130,7 +1130,7 @@
}
-LocationSummary* GuardFieldInstr::MakeLocationSummary() const {
+LocationSummary* GuardFieldInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
LocationSummary* summary =
new LocationSummary(kNumInputs, 0, LocationSummary::kNoCall);
@@ -1476,21 +1476,149 @@
}
-LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary() const {
+class StoreInstanceFieldSlowPath : public SlowPathCode {
+ public:
+ explicit StoreInstanceFieldSlowPath(StoreInstanceFieldInstr* instruction)
+ : instruction_(instruction) { }
+
+ virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
+ __ Comment("StoreInstanceFieldSlowPath");
+ __ Bind(entry_label());
+ const Class& double_class = compiler->double_class();
+ const Code& stub =
+ Code::Handle(StubCode::GetAllocationStubForClass(double_class));
+ const ExternalLabel label(double_class.ToCString(), stub.EntryPoint());
+
+ LocationSummary* locs = instruction_->locs();
+ locs->live_registers()->Remove(locs->out());
+
+ compiler->SaveLiveRegisters(locs);
+ compiler->GenerateCall(Scanner::kDummyTokenIndex, // No token position.
+ &label,
+ PcDescriptors::kOther,
+ locs);
+ __ MoveRegister(locs->temp(0).reg(), RAX);
+ compiler->RestoreLiveRegisters(locs);
+
+ __ jmp(exit_label());
+ }
+
+ private:
+ StoreInstanceFieldInstr* instruction_;
+};
+
+
+LocationSummary* StoreInstanceFieldInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
- new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ new LocationSummary(kNumInputs, kNumTemps,
+ (field().guarded_cid() == kIllegalCid) || (is_initialization_)
+ ? LocationSummary::kCallOnSlowPath
+ : LocationSummary::kNoCall);
+
summary->set_in(0, Location::RequiresRegister());
- summary->set_in(1, ShouldEmitStoreBarrier()
+ if (IsUnboxedStore() && opt) {
+ summary->set_in(1, Location::RequiresFpuRegister());
+ summary->AddTemp(Location::RequiresRegister());
+ summary->AddTemp(Location::RequiresRegister());
+ } else if (IsPotentialUnboxedStore()) {
+ summary->set_in(1, ShouldEmitStoreBarrier()
+ ? Location::WritableRegister()
+ : Location::RequiresRegister());
+ summary->AddTemp(Location::RequiresRegister());
+ summary->AddTemp(Location::RequiresRegister());
+ summary->AddTemp(opt ? Location::RequiresFpuRegister()
+ : Location::FpuRegisterLocation(XMM1));
+ } else {
+ summary->set_in(1, ShouldEmitStoreBarrier()
? Location::WritableRegister()
: Location::RegisterOrConstant(value()));
+ }
return summary;
}
void StoreInstanceFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ Label skip_store;
+
Register instance_reg = locs()->in(0).reg();
+
+ if (IsUnboxedStore() && compiler->is_optimizing()) {
+ XmmRegister value = locs()->in(1).fpu_reg();
+ Register temp = locs()->temp(0).reg();
+ Register temp2 = locs()->temp(1).reg();
+
+ if (is_initialization_) {
+ StoreInstanceFieldSlowPath* slow_path =
+ new StoreInstanceFieldSlowPath(this);
+ compiler->AddSlowPathCode(slow_path);
+
+ __ TryAllocate(compiler->double_class(),
+ slow_path->entry_label(),
+ Assembler::kFarJump,
+ temp,
+ PP);
+ __ Bind(slow_path->exit_label());
+ __ movq(temp2, temp);
+ __ StoreIntoObject(instance_reg,
+ FieldAddress(instance_reg, field().Offset()),
+ temp2);
+ } else {
+ __ movq(temp, FieldAddress(instance_reg, field().Offset()));
+ }
+ __ movsd(FieldAddress(temp, Double::value_offset()), value);
+ return;
+ }
+
+ if (IsPotentialUnboxedStore()) {
+ Register value_reg = locs()->in(1).reg();
+ Register temp = locs()->temp(0).reg();
+ Register temp2 = locs()->temp(1).reg();
+ FpuRegister fpu_temp = locs()->temp(2).fpu_reg();
+
+ Label store_pointer, copy_payload;
+ __ LoadObject(temp, Field::ZoneHandle(field().raw()), PP);
+ __ cmpq(FieldAddress(temp, Field::guarded_cid_offset()),
+ Immediate(kDoubleCid));
+ __ j(NOT_EQUAL, &store_pointer);
+ __ cmpq(FieldAddress(temp, Field::is_nullable_offset()),
+ Immediate(kNullCid));
+ __ j(EQUAL, &store_pointer);
+ __ movzxb(temp2, FieldAddress(temp, Field::kind_bits_offset()));
+ __ testq(temp2, Immediate(1 << Field::kUnboxingCandidateBit));
+ __ j(ZERO, &store_pointer);
+
+ __ movq(temp, FieldAddress(instance_reg, field().Offset()));
+ __ CompareObject(temp, Object::null_object(), PP);
+ __ j(NOT_EQUAL, ©_payload);
+
+ StoreInstanceFieldSlowPath* slow_path =
+ new StoreInstanceFieldSlowPath(this);
+ compiler->AddSlowPathCode(slow_path);
+
+ if (!compiler->is_optimizing()) {
+ locs()->live_registers()->Add(locs()->in(0));
+ locs()->live_registers()->Add(locs()->in(1));
+ }
+ __ TryAllocate(compiler->double_class(),
+ slow_path->entry_label(),
+ Assembler::kFarJump,
+ temp,
+ PP);
+ __ Bind(slow_path->exit_label());
+ __ movq(temp2, temp);
+ __ StoreIntoObject(instance_reg,
+ FieldAddress(instance_reg, field().Offset()),
+ temp2);
+
+ __ Bind(©_payload);
+ __ movsd(fpu_temp, FieldAddress(value_reg, Double::value_offset()));
+ __ movsd(FieldAddress(temp, Double::value_offset()), fpu_temp);
+ __ jmp(&skip_store);
+ __ Bind(&store_pointer);
+ }
+
if (ShouldEmitStoreBarrier()) {
Register value_reg = locs()->in(1).reg();
__ StoreIntoObject(instance_reg,
@@ -1507,10 +1635,11 @@
FieldAddress(instance_reg, field().Offset()), value_reg);
}
}
+ __ Bind(&skip_store);
}
-LocationSummary* LoadStaticFieldInstr::MakeLocationSummary() const {
+LocationSummary* LoadStaticFieldInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -1533,7 +1662,7 @@
}
-LocationSummary* StoreStaticFieldInstr::MakeLocationSummary() const {
+LocationSummary* StoreStaticFieldInstr::MakeLocationSummary(bool opt) const {
LocationSummary* locs = new LocationSummary(1, 1, LocationSummary::kNoCall);
locs->set_in(0, value()->NeedsStoreBuffer() ? Location::WritableRegister()
: Location::RequiresRegister());
@@ -1557,7 +1686,7 @@
}
-LocationSummary* InstanceOfInstr::MakeLocationSummary() const {
+LocationSummary* InstanceOfInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 3;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -1584,7 +1713,7 @@
}
-LocationSummary* CreateArrayInstr::MakeLocationSummary() const {
+LocationSummary* CreateArrayInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -1608,7 +1737,7 @@
LocationSummary*
-AllocateObjectWithBoundsCheckInstr::MakeLocationSummary() const {
+AllocateObjectWithBoundsCheckInstr::MakeLocationSummary(bool opt) const {
return MakeCallSummary();
}
@@ -1626,22 +1755,114 @@
}
-LocationSummary* LoadFieldInstr::MakeLocationSummary() const {
- return LocationSummary::Make(1,
- Location::RequiresRegister(),
- LocationSummary::kNoCall);
+class BoxDoubleSlowPath : public SlowPathCode {
+ public:
+ explicit BoxDoubleSlowPath(Instruction* instruction)
+ : instruction_(instruction) { }
+
+ virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
+ __ Comment("BoxDoubleSlowPath");
+ __ Bind(entry_label());
+ const Class& double_class = compiler->double_class();
+ const Code& stub =
+ Code::Handle(StubCode::GetAllocationStubForClass(double_class));
+ const ExternalLabel label(double_class.ToCString(), stub.EntryPoint());
+
+ LocationSummary* locs = instruction_->locs();
+ locs->live_registers()->Remove(locs->out());
+
+ compiler->SaveLiveRegisters(locs);
+ compiler->GenerateCall(Scanner::kDummyTokenIndex, // No token position.
+ &label,
+ PcDescriptors::kOther,
+ locs);
+ __ MoveRegister(locs->out().reg(), RAX);
+ compiler->RestoreLiveRegisters(locs);
+
+ __ jmp(exit_label());
+ }
+
+ private:
+ Instruction* instruction_;
+};
+
+
+LocationSummary* LoadFieldInstr::MakeLocationSummary(bool opt) const {
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* locs =
+ new LocationSummary(
+ kNumInputs, kNumTemps,
+ (opt && !IsPotentialUnboxedLoad())
+ ? LocationSummary::kNoCall
+ : LocationSummary::kCallOnSlowPath);
+
+ locs->set_in(0, Location::RequiresRegister());
+
+ if (IsUnboxedLoad() && opt) {
+ locs->AddTemp(Location::RequiresRegister());
+ } else if (IsPotentialUnboxedLoad()) {
+ locs->AddTemp(opt ? Location::RequiresFpuRegister()
+ : Location::FpuRegisterLocation(XMM1));
+ locs->AddTemp(Location::RequiresRegister());
+ }
+ locs->set_out(Location::RequiresRegister());
+ return locs;
}
void LoadFieldInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
Register instance_reg = locs()->in(0).reg();
- Register result_reg = locs()->out().reg();
+ if (IsUnboxedLoad() && compiler->is_optimizing()) {
+ XmmRegister result = locs()->out().fpu_reg();
+ Register temp = locs()->temp(0).reg();
+ __ movq(temp, FieldAddress(instance_reg, offset_in_bytes()));
+ __ movsd(result, FieldAddress(temp, Double::value_offset()));
+ return;
+ }
- __ movq(result_reg, FieldAddress(instance_reg, offset_in_bytes()));
+ Label done;
+ Register result = locs()->out().reg();
+ if (IsPotentialUnboxedLoad()) {
+ Register temp = locs()->temp(1).reg();
+ XmmRegister value = locs()->temp(0).fpu_reg();
+
+ Label load_pointer;
+ __ LoadObject(result, Field::ZoneHandle(field()->raw()), PP);
+
+
+ __ cmpq(FieldAddress(result, Field::guarded_cid_offset()),
+ Immediate(kDoubleCid));
+ __ j(NOT_EQUAL, &load_pointer);
+ __ cmpq(FieldAddress(result, Field::is_nullable_offset()),
+ Immediate(kNullCid));
+ __ j(EQUAL, &load_pointer);
+
+ BoxDoubleSlowPath* slow_path = new BoxDoubleSlowPath(this);
+ compiler->AddSlowPathCode(slow_path);
+
+ if (!compiler->is_optimizing()) {
+ locs()->live_registers()->Add(locs()->in(0));
+ }
+
+ __ TryAllocate(compiler->double_class(),
+ slow_path->entry_label(),
+ Assembler::kFarJump,
+ result,
+ PP);
+ __ Bind(slow_path->exit_label());
+ __ movq(temp, FieldAddress(instance_reg, offset_in_bytes()));
+ __ movsd(value, FieldAddress(temp, Double::value_offset()));
+ __ movsd(FieldAddress(result, Double::value_offset()), value);
+ __ jmp(&done);
+ __ Bind(&load_pointer);
+ }
+ __ movq(result, FieldAddress(instance_reg, offset_in_bytes()));
+ __ Bind(&done);
}
-LocationSummary* InstantiateTypeInstr::MakeLocationSummary() const {
+LocationSummary* InstantiateTypeInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -1673,7 +1894,8 @@
}
-LocationSummary* InstantiateTypeArgumentsInstr::MakeLocationSummary() const {
+LocationSummary* InstantiateTypeArgumentsInstr::MakeLocationSummary(
+ bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -1721,7 +1943,7 @@
LocationSummary*
-ExtractConstructorTypeArgumentsInstr::MakeLocationSummary() const {
+ExtractConstructorTypeArgumentsInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -1763,7 +1985,7 @@
LocationSummary*
-ExtractConstructorInstantiatorInstr::MakeLocationSummary() const {
+ExtractConstructorInstantiatorInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -1802,7 +2024,7 @@
}
-LocationSummary* AllocateContextInstr::MakeLocationSummary() const {
+LocationSummary* AllocateContextInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 0;
const intptr_t kNumTemps = 1;
LocationSummary* locs =
@@ -1827,7 +2049,7 @@
}
-LocationSummary* CloneContextInstr::MakeLocationSummary() const {
+LocationSummary* CloneContextInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -1854,7 +2076,7 @@
}
-LocationSummary* CatchBlockEntryInstr::MakeLocationSummary() const {
+LocationSummary* CatchBlockEntryInstr::MakeLocationSummary(bool opt) const {
UNREACHABLE();
return NULL;
}
@@ -1891,7 +2113,7 @@
}
-LocationSummary* CheckStackOverflowInstr::MakeLocationSummary() const {
+LocationSummary* CheckStackOverflowInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 0;
const intptr_t kNumTemps = 1;
LocationSummary* summary =
@@ -2114,7 +2336,7 @@
}
-LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const {
+LocationSummary* BinarySmiOpInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
ConstantInstr* right_constant = right()->definition()->AsConstant();
@@ -2565,7 +2787,7 @@
}
-LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary() const {
+LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary(bool opt) const {
intptr_t left_cid = left()->Type()->ToCid();
intptr_t right_cid = right()->Type()->ToCid();
ASSERT((left_cid != kDoubleCid) && (right_cid != kDoubleCid));
@@ -2601,7 +2823,7 @@
}
-LocationSummary* BoxDoubleInstr::MakeLocationSummary() const {
+LocationSummary* BoxDoubleInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -2614,38 +2836,6 @@
}
-class BoxDoubleSlowPath : public SlowPathCode {
- public:
- explicit BoxDoubleSlowPath(BoxDoubleInstr* instruction)
- : instruction_(instruction) { }
-
- virtual void EmitNativeCode(FlowGraphCompiler* compiler) {
- __ Comment("BoxDoubleSlowPath");
- __ Bind(entry_label());
- const Class& double_class = compiler->double_class();
- const Code& stub =
- Code::Handle(StubCode::GetAllocationStubForClass(double_class));
- const ExternalLabel label(double_class.ToCString(), stub.EntryPoint());
-
- LocationSummary* locs = instruction_->locs();
- locs->live_registers()->Remove(locs->out());
-
- compiler->SaveLiveRegisters(locs);
- compiler->GenerateCall(Scanner::kDummyTokenIndex, // No token position.
- &label,
- PcDescriptors::kOther,
- locs);
- __ MoveRegister(locs->out().reg(), RAX);
- compiler->RestoreLiveRegisters(locs);
-
- __ jmp(exit_label());
- }
-
- private:
- BoxDoubleInstr* instruction_;
-};
-
-
void BoxDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
BoxDoubleSlowPath* slow_path = new BoxDoubleSlowPath(this);
compiler->AddSlowPathCode(slow_path);
@@ -2663,7 +2853,7 @@
}
-LocationSummary* UnboxDoubleInstr::MakeLocationSummary() const {
+LocationSummary* UnboxDoubleInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -2704,7 +2894,7 @@
}
-LocationSummary* BoxFloat32x4Instr::MakeLocationSummary() const {
+LocationSummary* BoxFloat32x4Instr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -2766,7 +2956,7 @@
}
-LocationSummary* UnboxFloat32x4Instr::MakeLocationSummary() const {
+LocationSummary* UnboxFloat32x4Instr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
return LocationSummary::Make(kNumInputs,
Location::RequiresFpuRegister(),
@@ -2790,7 +2980,7 @@
}
-LocationSummary* BoxInt32x4Instr::MakeLocationSummary() const {
+LocationSummary* BoxInt32x4Instr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -2852,7 +3042,7 @@
}
-LocationSummary* UnboxInt32x4Instr::MakeLocationSummary() const {
+LocationSummary* UnboxInt32x4Instr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -2879,7 +3069,7 @@
}
-LocationSummary* BinaryDoubleOpInstr::MakeLocationSummary() const {
+LocationSummary* BinaryDoubleOpInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -2907,7 +3097,7 @@
}
-LocationSummary* BinaryFloat32x4OpInstr::MakeLocationSummary() const {
+LocationSummary* BinaryFloat32x4OpInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -2935,7 +3125,7 @@
}
-LocationSummary* Simd32x4ShuffleInstr::MakeLocationSummary() const {
+LocationSummary* Simd32x4ShuffleInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -2977,7 +3167,7 @@
}
-LocationSummary* Simd32x4ShuffleMixInstr::MakeLocationSummary() const {
+LocationSummary* Simd32x4ShuffleMixInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3004,7 +3194,7 @@
}
-LocationSummary* Simd32x4GetSignMaskInstr::MakeLocationSummary() const {
+LocationSummary* Simd32x4GetSignMaskInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3024,7 +3214,8 @@
}
-LocationSummary* Float32x4ConstructorInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4ConstructorInstr::MakeLocationSummary(
+ bool opt) const {
const intptr_t kNumInputs = 4;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3061,7 +3252,7 @@
}
-LocationSummary* Float32x4ZeroInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4ZeroInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 0;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3077,7 +3268,7 @@
}
-LocationSummary* Float32x4SplatInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4SplatInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3098,7 +3289,7 @@
}
-LocationSummary* Float32x4ComparisonInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4ComparisonInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3141,7 +3332,7 @@
}
-LocationSummary* Float32x4MinMaxInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4MinMaxInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3171,7 +3362,7 @@
}
-LocationSummary* Float32x4ScaleInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4ScaleInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3200,7 +3391,7 @@
}
-LocationSummary* Float32x4SqrtInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4SqrtInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3231,7 +3422,7 @@
}
-LocationSummary* Float32x4ZeroArgInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4ZeroArgInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3258,7 +3449,7 @@
}
-LocationSummary* Float32x4ClampInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4ClampInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 3;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3281,7 +3472,7 @@
}
-LocationSummary* Float32x4WithInstr::MakeLocationSummary() const {
+LocationSummary* Float32x4WithInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3349,7 +3540,7 @@
}
-LocationSummary* Float32x4ToInt32x4Instr::MakeLocationSummary() const {
+LocationSummary* Float32x4ToInt32x4Instr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3365,7 +3556,8 @@
}
-LocationSummary* Int32x4BoolConstructorInstr::MakeLocationSummary() const {
+LocationSummary* Int32x4BoolConstructorInstr::MakeLocationSummary(
+ bool opt) const {
const intptr_t kNumInputs = 4;
const intptr_t kNumTemps = 1;
LocationSummary* summary =
@@ -3434,7 +3626,7 @@
}
-LocationSummary* Int32x4GetFlagInstr::MakeLocationSummary() const {
+LocationSummary* Int32x4GetFlagInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3479,7 +3671,7 @@
}
-LocationSummary* Int32x4SelectInstr::MakeLocationSummary() const {
+LocationSummary* Int32x4SelectInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 3;
const intptr_t kNumTemps = 1;
LocationSummary* summary =
@@ -3513,7 +3705,7 @@
}
-LocationSummary* Int32x4SetFlagInstr::MakeLocationSummary() const {
+LocationSummary* Int32x4SetFlagInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 1;
LocationSummary* summary =
@@ -3579,7 +3771,7 @@
}
-LocationSummary* Int32x4ToFloat32x4Instr::MakeLocationSummary() const {
+LocationSummary* Int32x4ToFloat32x4Instr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3595,7 +3787,7 @@
}
-LocationSummary* BinaryInt32x4OpInstr::MakeLocationSummary() const {
+LocationSummary* BinaryInt32x4OpInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3635,7 +3827,7 @@
}
-LocationSummary* MathUnaryInstr::MakeLocationSummary() const {
+LocationSummary* MathUnaryInstr::MakeLocationSummary(bool opt) const {
if ((kind() == MethodRecognizer::kMathSin) ||
(kind() == MethodRecognizer::kMathCos)) {
// Calling convention on x64 uses XMM0 and XMM1 to pass the first two
@@ -3674,7 +3866,7 @@
}
-LocationSummary* UnarySmiOpInstr::MakeLocationSummary() const {
+LocationSummary* UnarySmiOpInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
return LocationSummary::Make(kNumInputs,
Location::SameAsFirstInput(),
@@ -3707,7 +3899,7 @@
}
-LocationSummary* UnaryDoubleOpInstr::MakeLocationSummary() const {
+LocationSummary* UnaryDoubleOpInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -3725,7 +3917,7 @@
}
-LocationSummary* MathMinMaxInstr::MakeLocationSummary() const {
+LocationSummary* MathMinMaxInstr::MakeLocationSummary(bool opt) const {
if (result_cid() == kDoubleCid) {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 1;
@@ -3814,7 +4006,7 @@
}
-LocationSummary* SmiToDoubleInstr::MakeLocationSummary() const {
+LocationSummary* SmiToDoubleInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* result =
@@ -3833,7 +4025,7 @@
}
-LocationSummary* DoubleToIntegerInstr::MakeLocationSummary() const {
+LocationSummary* DoubleToIntegerInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 1;
LocationSummary* result =
@@ -3884,7 +4076,7 @@
}
-LocationSummary* DoubleToSmiInstr::MakeLocationSummary() const {
+LocationSummary* DoubleToSmiInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 1;
LocationSummary* result = new LocationSummary(
@@ -3916,7 +4108,7 @@
}
-LocationSummary* DoubleToDoubleInstr::MakeLocationSummary() const {
+LocationSummary* DoubleToDoubleInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* result =
@@ -3946,7 +4138,7 @@
}
-LocationSummary* InvokeMathCFunctionInstr::MakeLocationSummary() const {
+LocationSummary* InvokeMathCFunctionInstr::MakeLocationSummary(bool opt) const {
// Calling convention on x64 uses XMM0 and XMM1 to pass the first two
// double arguments and XMM0 to return the result. Unfortunately
// currently we can't specify these registers because ParallelMoveResolver
@@ -4030,7 +4222,7 @@
}
-LocationSummary* MergedMathInstr::MakeLocationSummary() const {
+LocationSummary* MergedMathInstr::MakeLocationSummary(bool opt) const {
if (kind() == MergedMathInstr::kTruncDivMod) {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 1;
@@ -4219,7 +4411,8 @@
}
-LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary() const {
+LocationSummary* PolymorphicInstanceCallInstr::MakeLocationSummary(
+ bool opt) const {
return MakeCallSummary();
}
@@ -4260,9 +4453,11 @@
}
-LocationSummary* BranchInstr::MakeLocationSummary() const {
- UNREACHABLE();
- return NULL;
+LocationSummary* BranchInstr::MakeLocationSummary(bool opt) const {
+ comparison()->InitializeLocationSummary(opt);
+ // Branches don't produce a result.
+ comparison()->locs()->set_out(Location::NoLocation());
+ return comparison()->locs();
}
@@ -4271,7 +4466,7 @@
}
-LocationSummary* CheckClassInstr::MakeLocationSummary() const {
+LocationSummary* CheckClassInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -4330,7 +4525,7 @@
}
-LocationSummary* CheckSmiInstr::MakeLocationSummary() const {
+LocationSummary* CheckSmiInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 1;
const intptr_t kNumTemps = 0;
LocationSummary* summary =
@@ -4349,7 +4544,7 @@
}
-LocationSummary* CheckArrayBoundInstr::MakeLocationSummary() const {
+LocationSummary* CheckArrayBoundInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -4404,7 +4599,7 @@
}
-LocationSummary* UnboxIntegerInstr::MakeLocationSummary() const {
+LocationSummary* UnboxIntegerInstr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -4415,7 +4610,7 @@
}
-LocationSummary* BoxIntegerInstr::MakeLocationSummary() const {
+LocationSummary* BoxIntegerInstr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -4426,7 +4621,7 @@
}
-LocationSummary* BinaryMintOpInstr::MakeLocationSummary() const {
+LocationSummary* BinaryMintOpInstr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -4437,7 +4632,7 @@
}
-LocationSummary* UnaryMintOpInstr::MakeLocationSummary() const {
+LocationSummary* UnaryMintOpInstr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -4448,7 +4643,7 @@
}
-LocationSummary* ShiftMintOpInstr::MakeLocationSummary() const {
+LocationSummary* ShiftMintOpInstr::MakeLocationSummary(bool opt) const {
UNIMPLEMENTED();
return NULL;
}
@@ -4459,7 +4654,7 @@
}
-LocationSummary* ThrowInstr::MakeLocationSummary() const {
+LocationSummary* ThrowInstr::MakeLocationSummary(bool opt) const {
return new LocationSummary(0, 0, LocationSummary::kCall);
}
@@ -4474,7 +4669,7 @@
}
-LocationSummary* ReThrowInstr::MakeLocationSummary() const {
+LocationSummary* ReThrowInstr::MakeLocationSummary(bool opt) const {
return new LocationSummary(0, 0, LocationSummary::kCall);
}
@@ -4514,7 +4709,7 @@
}
-LocationSummary* GotoInstr::MakeLocationSummary() const {
+LocationSummary* GotoInstr::MakeLocationSummary(bool opt) const {
return new LocationSummary(0, 0, LocationSummary::kNoCall);
}
@@ -4543,7 +4738,7 @@
}
-LocationSummary* CurrentContextInstr::MakeLocationSummary() const {
+LocationSummary* CurrentContextInstr::MakeLocationSummary(bool opt) const {
return LocationSummary::Make(0,
Location::RequiresRegister(),
LocationSummary::kNoCall);
@@ -4555,7 +4750,7 @@
}
-LocationSummary* StrictCompareInstr::MakeLocationSummary() const {
+LocationSummary* StrictCompareInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
if (needs_number_check()) {
@@ -4636,7 +4831,7 @@
}
-LocationSummary* ClosureCallInstr::MakeLocationSummary() const {
+LocationSummary* ClosureCallInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 0;
const intptr_t kNumTemps = 1;
LocationSummary* result =
@@ -4666,7 +4861,7 @@
}
-LocationSummary* BooleanNegateInstr::MakeLocationSummary() const {
+LocationSummary* BooleanNegateInstr::MakeLocationSummary(bool opt) const {
return LocationSummary::Make(1,
Location::RequiresRegister(),
LocationSummary::kNoCall);
@@ -4686,7 +4881,7 @@
}
-LocationSummary* StoreVMFieldInstr::MakeLocationSummary() const {
+LocationSummary* StoreVMFieldInstr::MakeLocationSummary(bool opt) const {
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 0;
LocationSummary* locs =
@@ -4712,7 +4907,7 @@
}
-LocationSummary* AllocateObjectInstr::MakeLocationSummary() const {
+LocationSummary* AllocateObjectInstr::MakeLocationSummary(bool opt) const {
return MakeCallSummary();
}
@@ -4728,7 +4923,7 @@
}
-LocationSummary* CreateClosureInstr::MakeLocationSummary() const {
+LocationSummary* CreateClosureInstr::MakeLocationSummary(bool opt) const {
return MakeCallSummary();
}
diff --git a/runtime/vm/isolate.cc b/runtime/vm/isolate.cc
index 1874127..4d05b64 100644
--- a/runtime/vm/isolate.cc
+++ b/runtime/vm/isolate.cc
@@ -30,6 +30,7 @@
#include "vm/stub_code.h"
#include "vm/symbols.h"
#include "vm/thread.h"
+#include "vm/thread_interrupter.h"
#include "vm/timer.h"
#include "vm/visitor.h"
@@ -142,11 +143,10 @@
bool success = true;
if (message->IsOOB()) {
- Service::HandleServiceMessage(isolate_, message->reply_port(), msg);
+ Service::HandleServiceMessage(isolate_, msg);
} else {
const Object& result = Object::Handle(
- DartLibraryCalls::HandleMessage(
- receive_port, message->reply_port(), msg));
+ DartLibraryCalls::HandleMessage(receive_port, msg));
if (result.IsError()) {
success = ProcessUnhandledException(msg, Error::Cast(result));
} else {
@@ -339,13 +339,11 @@
}
void Isolate::SetCurrent(Isolate* current) {
- Isolate* old_isolate = Current();
- if (old_isolate != NULL) {
- ProfilerManager::DescheduleIsolate(old_isolate);
- }
- Thread::SetThreadLocal(isolate_key, reinterpret_cast<uword>(current));
- if (current != NULL) {
- ProfilerManager::ScheduleIsolate(current);
+ Isolate* old_current = Current();
+ if (old_current != current) {
+ Profiler::EndExecution(old_current);
+ Thread::SetThreadLocal(isolate_key, reinterpret_cast<uword>(current));
+ Profiler::BeginExecution(current);
}
}
@@ -370,7 +368,7 @@
ASSERT(result != NULL);
// Setup for profiling.
- ProfilerManager::SetupIsolateForProfiling(result);
+ Profiler::InitProfilingForIsolate(result);
// TODO(5411455): For now just set the recently created isolate as
// the current isolate.
@@ -724,6 +722,9 @@
PrintInvokedFunctions();
}
+ // Write out profiler data if requested.
+ Profiler::WriteTracing(this);
+
// Write out the coverage data if collection has been enabled.
CodeCoverage::Write(this);
@@ -744,8 +745,7 @@
// TODO(5411455): For now just make sure there are no current isolates
// as we are shutting down the isolate.
SetCurrent(NULL);
- ProfilerManager::DescheduleIsolate(this);
- ProfilerManager::ShutdownIsolateForProfiling(this);
+ Profiler::ShutdownProfilingForIsolate(this);
}
diff --git a/runtime/vm/isolate_test.cc b/runtime/vm/isolate_test.cc
index 2af007e..ee39fb0 100644
--- a/runtime/vm/isolate_test.cc
+++ b/runtime/vm/isolate_test.cc
@@ -23,17 +23,56 @@
TEST_CASE(IsolateSpawn) {
const char* kScriptChars =
"import 'dart:isolate';\n"
+ // Ignores printed lines.
+ "var _nullPrintClosure = (String line) {};\n"
"void entry(message) {}\n"
"int testMain() {\n"
- " try {\n"
- " Isolate.spawn(entry, null);\n"
- " } catch (e) {\n"
- " rethrow;\n"
- " }\n"
- " return 0;\n"
+ " Isolate.spawn(entry, null);\n"
+ // TODO(floitsch): the following code is only to bump the event loop
+ // so it executes asynchronous microtasks.
+ " var rp = new RawReceivePort();\n"
+ " rp.sendPort.send(null);\n"
+ " rp.handler = (_) { rp.close(); };\n"
"}\n";
- Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
- Dart_Handle result = Dart_Invoke(lib, NewString("testMain"), 0, NULL);
+
+ Dart_Handle test_lib = TestCase::LoadTestScript(kScriptChars, NULL);
+
+ // Setup the internal library's 'internalPrint' function.
+ // Necessary because asynchronous errors use "print" to print their
+ // stack trace.
+ Dart_Handle url = NewString("dart:_collection-dev");
+ DART_CHECK_VALID(url);
+ Dart_Handle internal_lib = Dart_LookupLibrary(url);
+ DART_CHECK_VALID(internal_lib);
+ Dart_Handle print = Dart_GetField(test_lib, NewString("_nullPrintClosure"));
+ Dart_Handle result = Dart_SetField(internal_lib,
+ NewString("_printClosure"),
+ print);
+
+ DART_CHECK_VALID(result);
+
+ // Setup the 'scheduleImmediate' closure.
+ url = NewString("dart:isolate");
+ DART_CHECK_VALID(url);
+ Dart_Handle isolate_lib = Dart_LookupLibrary(url);
+ DART_CHECK_VALID(isolate_lib);
+ Dart_Handle schedule_immediate_closure =
+ Dart_Invoke(isolate_lib, NewString("_getIsolateScheduleImmediateClosure"),
+ 0, NULL);
+ Dart_Handle args[1];
+ args[0] = schedule_immediate_closure;
+ url = NewString("dart:async");
+ DART_CHECK_VALID(url);
+ Dart_Handle async_lib = Dart_LookupLibrary(url);
+ DART_CHECK_VALID(async_lib);
+ DART_CHECK_VALID(Dart_Invoke(
+ async_lib, NewString("_setScheduleImmediateClosure"), 1, args));
+
+
+ result = Dart_Invoke(test_lib, NewString("testMain"), 0, NULL);
+ EXPECT(!Dart_IsError(result));
+ // Run until all ports to isolate are closed.
+ result = Dart_RunLoop();
EXPECT_ERROR(result, "Null callback specified for isolate creation");
EXPECT(Dart_ErrorHasException(result));
Dart_Handle exception_result = Dart_ErrorGetException(result);
diff --git a/runtime/vm/json_stream.cc b/runtime/vm/json_stream.cc
index ae06d19..0ab2cd5 100644
--- a/runtime/vm/json_stream.cc
+++ b/runtime/vm/json_stream.cc
@@ -4,6 +4,7 @@
#include "platform/assert.h"
#include "vm/object.h"
+#include "vm/debugger.h"
#include "vm/json_stream.h"
@@ -23,6 +24,16 @@
}
+const char* JSONStream::LookupOption(const char* key) const {
+ for (int i = 0; i < num_options(); i++) {
+ if (!strcmp(key, option_keys_[i])) {
+ return option_values_[i];
+ }
+ }
+ return NULL;
+}
+
+
void JSONStream::Clear() {
buffer_.Clear();
open_objects_ = 0;
@@ -122,6 +133,12 @@
}
+void JSONStream::PrintValue(const SourceBreakpoint* bpt) {
+ PrintCommaIfNeeded();
+ bpt->PrintToJSONStream(this);
+}
+
+
void JSONStream::PrintPropertyBool(const char* name, bool b) {
PrintPropertyName(name);
PrintValueBool(b);
diff --git a/runtime/vm/json_stream.h b/runtime/vm/json_stream.h
index 5410314..9829995 100644
--- a/runtime/vm/json_stream.h
+++ b/runtime/vm/json_stream.h
@@ -15,6 +15,7 @@
class JSONArray;
class JSONObject;
class Object;
+class SourceBreakpoint;
class JSONStream : ValueObject {
public:
@@ -40,6 +41,8 @@
return option_values_[i];
}
+ const char* LookupOption(const char* key) const;
+
private:
void Clear();
@@ -56,6 +59,7 @@
void PrintfValue(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
void PrintValue(const Object& o, bool ref = true);
void PrintValue(const Field& f, const Instance& instance, bool ref = true);
+ void PrintValue(const SourceBreakpoint* bpt);
void PrintPropertyBool(const char* name, bool b);
void PrintProperty(const char* name, intptr_t i);
@@ -154,6 +158,9 @@
bool ref = true) const {
stream_->PrintValue(field, instance, ref);
}
+ void AddValue(const SourceBreakpoint* bpt) const {
+ stream_->PrintValue(bpt);
+ }
void AddValueF(const char* format, ...) const PRINTF_ATTRIBUTE(2, 3);
private:
diff --git a/runtime/vm/message.h b/runtime/vm/message.h
index 4b894174e..e6a6f96 100644
--- a/runtime/vm/message.h
+++ b/runtime/vm/message.h
@@ -29,13 +29,9 @@
// A new message to be sent between two isolates. The data handed to this
// message will be disposed by calling free() once the message object is
// being destructed (after delivery or when the receiving port is closed).
- //
- // If reply_port is kIllegalPort, then there is no reply port.
- Message(Dart_Port dest_port, Dart_Port reply_port, uint8_t* data,
- intptr_t len, Priority priority)
+ Message(Dart_Port dest_port, uint8_t* data, intptr_t len, Priority priority)
: next_(NULL),
dest_port_(dest_port),
- reply_port_(reply_port),
data_(data),
len_(len),
priority_(priority) {}
@@ -44,7 +40,6 @@
}
Dart_Port dest_port() const { return dest_port_; }
- Dart_Port reply_port() const { return reply_port_; }
uint8_t* data() const { return data_; }
intptr_t len() const { return len_; }
Priority priority() const { return priority_; }
@@ -56,7 +51,6 @@
Message* next_;
Dart_Port dest_port_;
- Dart_Port reply_port_;
uint8_t* data_;
intptr_t len_;
Priority priority_;
diff --git a/runtime/vm/message_handler.cc b/runtime/vm/message_handler.cc
index a1df2a8..332a6e6 100644
--- a/runtime/vm/message_handler.cc
+++ b/runtime/vm/message_handler.cc
@@ -97,10 +97,9 @@
}
OS::Print("[>] Posting message:\n"
"\tsource: %s\n"
- "\treply_port: %" Pd64 "\n"
"\tdest: %s\n"
"\tdest_port: %" Pd64 "\n",
- source_name, message->reply_port(), name(), message->dest_port());
+ source_name, name(), message->dest_port());
}
Message::Priority saved_priority = message->priority();
diff --git a/runtime/vm/message_handler_test.cc b/runtime/vm/message_handler_test.cc
index 7fcf7dd..fbf69f5 100644
--- a/runtime/vm/message_handler_test.cc
+++ b/runtime/vm/message_handler_test.cc
@@ -123,7 +123,7 @@
EXPECT_EQ(0, handler.notify_count());
// Post a message.
- Message* message = new Message(0, 0, NULL, 0, Message::kNormalPriority);
+ Message* message = new Message(0, NULL, 0, Message::kNormalPriority);
handler_peer.PostMessage(message);
// The notify callback is called.
@@ -135,7 +135,7 @@
delete message;
// Post an oob message.
- message = new Message(0, 0, NULL, 0, Message::kOOBPriority);
+ message = new Message(0, NULL, 0, Message::kOOBPriority);
handler_peer.PostMessage(message);
// The notify callback is called.
@@ -151,9 +151,9 @@
UNIT_TEST_CASE(MessageHandler_ClosePort) {
TestMessageHandler handler;
MessageHandlerTestPeer handler_peer(&handler);
- Message* message1 = new Message(1, 0, NULL, 0, Message::kNormalPriority);
+ Message* message1 = new Message(1, NULL, 0, Message::kNormalPriority);
handler_peer.PostMessage(message1);
- Message* message2 = new Message(2, 0, NULL, 0, Message::kNormalPriority);
+ Message* message2 = new Message(2, NULL, 0, Message::kNormalPriority);
handler_peer.PostMessage(message2);
handler_peer.ClosePort(1);
@@ -169,9 +169,9 @@
UNIT_TEST_CASE(MessageHandler_CloseAllPorts) {
TestMessageHandler handler;
MessageHandlerTestPeer handler_peer(&handler);
- Message* message1 = new Message(1, 0, NULL, 0, Message::kNormalPriority);
+ Message* message1 = new Message(1, NULL, 0, Message::kNormalPriority);
handler_peer.PostMessage(message1);
- Message* message2 = new Message(2, 0, NULL, 0, Message::kNormalPriority);
+ Message* message2 = new Message(2, NULL, 0, Message::kNormalPriority);
handler_peer.PostMessage(message2);
handler_peer.CloseAllPorts();
@@ -187,13 +187,13 @@
Dart_Port port1 = PortMap::CreatePort(&handler);
Dart_Port port2 = PortMap::CreatePort(&handler);
Dart_Port port3 = PortMap::CreatePort(&handler);
- Message* message1 = new Message(port1, 0, NULL, 0, Message::kNormalPriority);
+ Message* message1 = new Message(port1, NULL, 0, Message::kNormalPriority);
handler_peer.PostMessage(message1);
- Message* oob_message1 = new Message(port2, 0, NULL, 0, Message::kOOBPriority);
+ Message* oob_message1 = new Message(port2, NULL, 0, Message::kOOBPriority);
handler_peer.PostMessage(oob_message1);
- Message* message2 = new Message(port2, 0, NULL, 0, Message::kNormalPriority);
+ Message* message2 = new Message(port2, NULL, 0, Message::kNormalPriority);
handler_peer.PostMessage(message2);
- Message* oob_message2 = new Message(port3, 0, NULL, 0, Message::kOOBPriority);
+ Message* oob_message2 = new Message(port3, NULL, 0, Message::kOOBPriority);
handler_peer.PostMessage(oob_message2);
// We handle both oob messages and a single normal message.
@@ -214,13 +214,13 @@
Dart_Port port2 = PortMap::CreatePort(&handler);
Dart_Port port3 = PortMap::CreatePort(&handler);
Dart_Port port4 = PortMap::CreatePort(&handler);
- Message* message1 = new Message(port1, 0, NULL, 0, Message::kNormalPriority);
+ Message* message1 = new Message(port1, NULL, 0, Message::kNormalPriority);
handler_peer.PostMessage(message1);
- Message* message2 = new Message(port2, 0, NULL, 0, Message::kNormalPriority);
+ Message* message2 = new Message(port2, NULL, 0, Message::kNormalPriority);
handler_peer.PostMessage(message2);
- Message* oob_message1 = new Message(port3, 0, NULL, 0, Message::kOOBPriority);
+ Message* oob_message1 = new Message(port3, NULL, 0, Message::kOOBPriority);
handler_peer.PostMessage(oob_message1);
- Message* oob_message2 = new Message(port4, 0, NULL, 0, Message::kOOBPriority);
+ Message* oob_message2 = new Message(port4, NULL, 0, Message::kOOBPriority);
handler_peer.PostMessage(oob_message2);
// We handle both oob messages but no normal messages.
@@ -246,7 +246,7 @@
MessageHandlerTestPeer handler_peer(handler);
for (int i = 0; i < info->count; i++) {
Message* message =
- new Message(info->ports[i], 0, NULL, 0, Message::kNormalPriority);
+ new Message(info->ports[i], NULL, 0, Message::kNormalPriority);
handler_peer.PostMessage(message);
}
}
@@ -267,7 +267,7 @@
TestEndFunction,
reinterpret_cast<uword>(&handler));
Dart_Port port = PortMap::CreatePort(&handler);
- Message* message = new Message(port, 0, NULL, 0, Message::kNormalPriority);
+ Message* message = new Message(port, NULL, 0, Message::kNormalPriority);
handler_peer.PostMessage(message);
// Wait for the first message to be handled.
diff --git a/runtime/vm/message_test.cc b/runtime/vm/message_test.cc
index e2bb672..bc47b39 100644
--- a/runtime/vm/message_test.cc
+++ b/runtime/vm/message_test.cc
@@ -45,13 +45,13 @@
// Add two messages.
Message* msg1 =
- new Message(port, 0, AllocMsg(str1), strlen(str1) + 1,
+ new Message(port, AllocMsg(str1), strlen(str1) + 1,
Message::kNormalPriority);
queue.Enqueue(msg1);
EXPECT(queue_peer.HasMessage());
Message* msg2 =
- new Message(port, 0, AllocMsg(str2), strlen(str2) + 1,
+ new Message(port, AllocMsg(str2), strlen(str2) + 1,
Message::kNormalPriority);
queue.Enqueue(msg2);
@@ -84,11 +84,11 @@
// Add two messages.
Message* msg1 =
- new Message(port1, 0, AllocMsg(str1), strlen(str1) + 1,
+ new Message(port1, AllocMsg(str1), strlen(str1) + 1,
Message::kNormalPriority);
queue.Enqueue(msg1);
Message* msg2 =
- new Message(port2, 0, AllocMsg(str2), strlen(str2) + 1,
+ new Message(port2, AllocMsg(str2), strlen(str2) + 1,
Message::kNormalPriority);
queue.Enqueue(msg2);
diff --git a/runtime/vm/native_api_impl.cc b/runtime/vm/native_api_impl.cc
index cb21834..9ff6f7f 100644
--- a/runtime/vm/native_api_impl.cc
+++ b/runtime/vm/native_api_impl.cc
@@ -31,8 +31,7 @@
// Post the message at the given port.
return PortMap::PostMessage(new Message(
- port_id, Message::kIllegalPort, buffer, writer.BytesWritten(),
- Message::kNormalPriority));
+ port_id, buffer, writer.BytesWritten(), Message::kNormalPriority));
}
diff --git a/runtime/vm/native_arguments.h b/runtime/vm/native_arguments.h
index 5194493..f25e723 100644
--- a/runtime/vm/native_arguments.h
+++ b/runtime/vm/native_arguments.h
@@ -131,6 +131,9 @@
static intptr_t retval_offset() {
return OFFSET_OF(NativeArguments, retval_);
}
+ static intptr_t AutoSetupScopeMask() {
+ return AutoSetupScopeBits::mask_in_place();
+ }
static int ParameterCountForResolution(const Function& function) {
ASSERT(function.is_native());
@@ -157,7 +160,11 @@
if (function.IsClosureFunction()) {
function_bits |= kClosureFunctionBit;
}
- return FunctionBits::update(function_bits, tag);
+ tag = FunctionBits::update(function_bits, tag);
+ if (function.IsNativeAutoSetupScope()) {
+ tag = AutoSetupScopeBits::update(1, tag);
+ }
+ return tag;
}
private:
@@ -170,9 +177,11 @@
kArgcSize = 24,
kFunctionBit = 24,
kFunctionSize = 2,
+ kAutoSetupScopeBit = 26,
};
class ArgcBits : public BitField<int, kArgcBit, kArgcSize> {};
class FunctionBits : public BitField<int, kFunctionBit, kFunctionSize> {};
+ class AutoSetupScopeBits : public BitField<int, kAutoSetupScopeBit, 1> {};
friend class Api;
friend class BootstrapNatives;
friend class Simulator;
diff --git a/runtime/vm/native_entry.cc b/runtime/vm/native_entry.cc
index c16af33..af4bd96 100644
--- a/runtime/vm/native_entry.cc
+++ b/runtime/vm/native_entry.cc
@@ -22,7 +22,8 @@
NativeFunction NativeEntry::ResolveNative(const Library& library,
const String& function_name,
- int number_of_arguments) {
+ int number_of_arguments,
+ bool* auto_setup_scope) {
// Now resolve the native function to the corresponding native entrypoint.
if (library.native_entry_resolver() == 0) {
// Native methods are not allowed in the library to which this
@@ -33,7 +34,7 @@
Dart_NativeEntryResolver resolver = library.native_entry_resolver();
Dart_NativeFunction native_function =
resolver(Api::NewHandle(Isolate::Current(), function_name.raw()),
- number_of_arguments);
+ number_of_arguments, auto_setup_scope);
Dart_ExitScope(); // Exit the Dart API scope.
return reinterpret_cast<NativeFunction>(native_function);
}
diff --git a/runtime/vm/native_entry.h b/runtime/vm/native_entry.h
index e2dc1cd..6c98d3a 100644
--- a/runtime/vm/native_entry.h
+++ b/runtime/vm/native_entry.h
@@ -93,7 +93,8 @@
// Resolve specified dart native function to the actual native entrypoint.
static NativeFunction ResolveNative(const Library& library,
const String& function_name,
- int number_of_arguments);
+ int number_of_arguments,
+ bool* auto_setup_scope);
static void NativeCallWrapper(Dart_NativeArguments args,
Dart_NativeFunction func);
static const ExternalLabel& NativeCallWrapperLabel();
diff --git a/runtime/vm/native_symbol_linux.cc b/runtime/vm/native_symbol_linux.cc
index 225a4b0..4a0e12f 100644
--- a/runtime/vm/native_symbol_linux.cc
+++ b/runtime/vm/native_symbol_linux.cc
@@ -8,7 +8,7 @@
#include "vm/native_symbol.h"
#include "vm/thread.h"
-
+#include <cxxabi.h> // NOLINT
#include <dlfcn.h> // NOLINT
namespace dart {
@@ -30,6 +30,11 @@
if (info.dli_sname == NULL) {
return NULL;
}
+ int status;
+ char* demangled = abi::__cxa_demangle(info.dli_sname, NULL, NULL, &status);
+ if (status == 0) {
+ return demangled;
+ }
return strdup(info.dli_sname);
}
diff --git a/runtime/vm/native_symbol_macos.cc b/runtime/vm/native_symbol_macos.cc
index 3b240bd..4de33ce 100644
--- a/runtime/vm/native_symbol_macos.cc
+++ b/runtime/vm/native_symbol_macos.cc
@@ -8,6 +8,7 @@
#include "vm/native_symbol.h"
#include "vm/thread.h"
+#include <cxxabi.h> // NOLINT
#include <dlfcn.h> // NOLINT
namespace dart {
@@ -29,6 +30,11 @@
if (info.dli_sname == NULL) {
return NULL;
}
+ int status;
+ char* demangled = abi::__cxa_demangle(info.dli_sname, NULL, NULL, &status);
+ if (status == 0) {
+ return demangled;
+ }
return strdup(info.dli_sname);
}
diff --git a/runtime/vm/native_symbol_win.cc b/runtime/vm/native_symbol_win.cc
index 7e8350f..b44633f 100644
--- a/runtime/vm/native_symbol_win.cc
+++ b/runtime/vm/native_symbol_win.cc
@@ -32,7 +32,7 @@
void NativeSymbolResolver::ShutdownOnce() {
- ScopedMutex lock(lock_);
+ MutexLocker lock(lock_);
if (!running_) {
return;
}
@@ -52,7 +52,7 @@
static const intptr_t kSymbolInfoSize = sizeof(SYMBOL_INFO); // NOLINT.
static char buffer[kSymbolInfoSize + kMaxNameLength];
static char name_buffer[kMaxNameLength];
- ScopedMutex lock(lock_);
+ MutexLocker lock(lock_);
if (!running_) {
return NULL;
}
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 01c7690..99bad2b6 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -143,7 +143,6 @@
RawClass* Object::unhandled_exception_class_ =
reinterpret_cast<RawClass*>(RAW_NULL);
RawClass* Object::unwind_error_class_ = reinterpret_cast<RawClass*>(RAW_NULL);
-#undef RAW_NULL
const double MegamorphicCache::kLoadFactor = 0.75;
@@ -1612,7 +1611,12 @@
// finalization time. The optimizer may canonicalize instantiated function
// types of the same signature class, but these will be added after the
// uninstantiated signature class at index 0.
- const Array& signature_types = Array::Handle(canonical_types());
+ Array& signature_types = Array::Handle();
+ signature_types ^= canonical_types();
+ if (signature_types.IsNull()) {
+ set_canonical_types(empty_array());
+ signature_types ^= canonical_types();
+ }
// The canonical_types array is initialized to the empty array.
ASSERT(!signature_types.IsNull());
if (signature_types.Length() > 0) {
@@ -1736,7 +1740,6 @@
}
StorePointer(&raw_ptr()->interfaces_, Object::empty_array().raw());
StorePointer(&raw_ptr()->constants_, Object::empty_array().raw());
- StorePointer(&raw_ptr()->canonical_types_, Object::empty_array().raw());
StorePointer(&raw_ptr()->functions_, Object::empty_array().raw());
StorePointer(&raw_ptr()->fields_, Object::empty_array().raw());
StorePointer(&raw_ptr()->invocation_dispatcher_cache_,
@@ -2355,7 +2358,7 @@
eval_func.set_result_type(Type::Handle(Type::DynamicType()));
eval_func.set_num_fixed_parameters(0);
eval_func.SetNumOptionalParameters(0, true);
- eval_func.set_is_optimizable(false);
+ eval_func.SetIsOptimizable(false);
const Array& args = Array::Handle(Array::New(0));
const Object& result =
@@ -2719,11 +2722,11 @@
}
-RawArray* Class::canonical_types() const {
+RawObject* Class::canonical_types() const {
return raw_ptr()->canonical_types_;
}
-void Class::set_canonical_types(const Array& value) const {
+void Class::set_canonical_types(const Object& value) const {
ASSERT(!value.IsNull());
StorePointer(&raw_ptr()->canonical_types_, value.raw());
}
@@ -4551,13 +4554,16 @@
}
-bool Function::is_optimizable() const {
+bool Function::IsOptimizable() const {
if (FLAG_coverage_dir != NULL) {
// Do not optimize if collecting coverage data.
return false;
}
- if (OptimizableBit::decode(raw_ptr()->kind_tag_) &&
- (script() != Script::null()) &&
+ if (is_native()) {
+ // Native methods don't need to be optimized.
+ return false;
+ }
+ if (is_optimizable() && (script() != Script::null()) &&
((end_token_pos() - token_pos()) < FLAG_huge_method_cutoff_in_tokens)) {
// Additional check needed for implicit getters.
if (HasCode() &&
@@ -4572,6 +4578,22 @@
}
+bool Function::IsNativeAutoSetupScope() const {
+ return is_native() ? is_optimizable() : false;
+}
+
+
+void Function::SetIsOptimizable(bool value) const {
+ ASSERT(!is_native());
+ set_is_optimizable(value);
+}
+
+
+void Function::SetIsNativeAutoSetupScope(bool value) const {
+ ASSERT(is_native());
+ set_is_optimizable(value);
+}
+
void Function::set_is_optimizable(bool value) const {
set_kind_tag(OptimizableBit::update(value, raw_ptr()->kind_tag_));
}
@@ -5093,7 +5115,7 @@
result.set_deoptimization_counter(0);
result.set_optimized_instruction_count(0);
result.set_optimized_call_site_count(0);
- result.set_is_optimizable(true);
+ result.set_is_optimizable(is_native ? false : true);
result.set_has_finally(false);
result.set_is_inlinable(true);
if (kind == RawFunction::kClosureFunction) {
@@ -5533,7 +5555,7 @@
// optimizing compiler can eliminate the call to the static initializer
// via constant folding.
init_function.set_is_visible(false);
- init_function.set_is_optimizable(false);
+ init_function.SetIsOptimizable(false);
init_function.set_is_inlinable(false);
init_function.set_saved_static_field(field);
return init_function.raw();
@@ -5855,6 +5877,7 @@
result.set_owner(owner);
result.set_token_pos(token_pos);
result.set_has_initializer(false);
+ result.set_is_unboxing_candidate(true);
result.set_guarded_cid(kIllegalCid);
result.set_is_nullable(false);
// Presently, we only attempt to remember the list length for final fields.
@@ -8833,7 +8856,7 @@
return;
}
// Only check ids for unoptimized code that is optimizable.
- if (!function.is_optimizable()) return;
+ if (!function.IsOptimizable()) return;
for (intptr_t i = 0; i < Length(); i++) {
PcDescriptors::Kind kind = DescriptorKind(i);
// 'deopt_id' is set for kDeopt and kIcCall and must be unique for one kind.
@@ -11082,7 +11105,7 @@
eval_func.set_result_type(Type::Handle(Type::DynamicType()));
eval_func.set_num_fixed_parameters(1);
eval_func.SetNumOptionalParameters(0, true);
- eval_func.set_is_optimizable(false);
+ eval_func.SetIsOptimizable(false);
const Array& args = Array::Handle(Array::New(1));
args.SetAt(0, *this);
@@ -11228,13 +11251,16 @@
return Type::NullType();
}
const Class& cls = Class::Handle(clazz());
- AbstractTypeArguments& type_arguments = AbstractTypeArguments::Handle();
- if (cls.NumTypeArguments() > 0) {
- type_arguments = GetTypeArguments();
+ Type& type = Type::Handle(cls.CanonicalType());
+ if (type.IsNull()) {
+ AbstractTypeArguments& type_arguments = AbstractTypeArguments::Handle();
+ if (cls.NumTypeArguments() > 0) {
+ type_arguments = GetTypeArguments();
+ }
+ type = Type::New(cls, type_arguments, Scanner::kDummyTokenIndex);
+ type.SetIsFinalized();
+ type ^= type.Canonicalize();
}
- const Type& type = Type::Handle(
- Type::New(cls, type_arguments, Scanner::kDummyTokenIndex));
- type.SetIsFinalized();
return type.raw();
}
@@ -11434,7 +11460,7 @@
}
-const char* Instance::ToUserCString(intptr_t maxLen) const {
+const char* Instance::ToUserCString(intptr_t max_len, intptr_t nesting) const {
if (raw() == Object::sentinel().raw()) {
return "<not initialized>";
} else if (raw() == Object::transition_sentinel().raw()) {
@@ -11958,13 +11984,23 @@
RawType* Type::NewNonParameterizedType(const Class& type_class) {
ASSERT(type_class.NumTypeArguments() == 0);
- const TypeArguments& no_type_arguments = TypeArguments::Handle();
- Type& type = Type::Handle();
- type ^= Type::New(Object::Handle(type_class.raw()),
- no_type_arguments,
- Scanner::kDummyTokenIndex);
- type.SetIsFinalized();
- type ^= type.Canonicalize();
+ if (type_class.raw() == Object::dynamic_class()) {
+ // If the dynamic type has not been setup in the VM isolate, then we need
+ // to allocate it here.
+ if (Object::dynamic_type() != reinterpret_cast<RawType*>(RAW_NULL)) {
+ return Object::dynamic_type();
+ }
+ ASSERT(Isolate::Current() == Dart::vm_isolate());
+ }
+ Type& type = Type::Handle(type_class.CanonicalType());
+ if (type.IsNull()) {
+ const TypeArguments& no_type_arguments = TypeArguments::Handle();
+ type ^= Type::New(Object::Handle(type_class.raw()),
+ no_type_arguments,
+ Scanner::kDummyTokenIndex);
+ type.SetIsFinalized();
+ type ^= type.Canonicalize();
+ }
return type.raw();
}
@@ -12201,18 +12237,35 @@
ASSERT(IsMalformed() || AbstractTypeArguments::Handle(arguments()).IsOld());
return this->raw();
}
- const Class& cls = Class::Handle(type_class());
- Array& canonical_types = Array::Handle(cls.canonical_types());
+ Isolate* isolate = Isolate::Current();
+ Type& type = Type::Handle(isolate);
+ const Class& cls = Class::Handle(isolate, type_class());
+ if (cls.raw() == Object::dynamic_class() && (isolate != Dart::vm_isolate())) {
+ return Object::dynamic_type();
+ }
+ // Fast canonical lookup/registry for simple types.
+ if ((cls.NumTypeArguments() == 0) && !cls.IsSignatureClass()) {
+ type = cls.CanonicalType();
+ if (type.IsNull()) {
+ ASSERT(!cls.raw()->IsVMHeapObject() || (isolate == Dart::vm_isolate()));
+ cls.set_canonical_types(*this);
+ SetCanonical();
+ return this->raw();
+ }
+ ASSERT(this->Equals(type));
+ return type.raw();
+ }
+
+ Array& canonical_types = Array::Handle(isolate);
+ canonical_types ^= cls.canonical_types();
if (canonical_types.IsNull()) {
- // Types defined in the VM isolate are canonicalized via the object store.
- return this->raw();
+ canonical_types = empty_array().raw();
}
const intptr_t canonical_types_len = canonical_types.Length();
// Linear search to see whether this type is already present in the
// list of canonicalized types.
// TODO(asiva): Try to re-factor this lookup code to make sharing
// easy between the 4 versions of this loop.
- Type& type = Type::Handle();
intptr_t index = 0;
while (index < canonical_types_len) {
type ^= canonical_types.At(index);
@@ -12226,7 +12279,8 @@
index++;
}
// Canonicalize the type arguments.
- AbstractTypeArguments& type_args = AbstractTypeArguments::Handle(arguments());
+ AbstractTypeArguments& type_args =
+ AbstractTypeArguments::Handle(isolate, arguments());
ASSERT(type_args.IsNull() || (type_args.Length() == cls.NumTypeArguments()));
type_args = type_args.Canonicalize();
set_arguments(type_args);
@@ -12234,8 +12288,8 @@
if (index == canonical_types_len) {
const intptr_t kLengthIncrement = 2; // Raw and parameterized.
const intptr_t new_length = canonical_types.Length() + kLengthIncrement;
- const Array& new_canonical_types =
- Array::Handle(Array::Grow(canonical_types, new_length, Heap::kOld));
+ const Array& new_canonical_types = Array::Handle(
+ isolate, Array::Grow(canonical_types, new_length, Heap::kOld));
cls.set_canonical_types(new_canonical_types);
new_canonical_types.SetAt(index, *this);
} else {
@@ -12253,11 +12307,11 @@
// of the super class of the owner class of its signature function will be
// prepended to the type argument vector during class finalization.
const TypeArguments& type_params =
- TypeArguments::Handle(cls.type_parameters());
+ TypeArguments::Handle(isolate, cls.type_parameters());
const intptr_t num_type_params = cls.NumTypeParameters();
const intptr_t num_type_args = cls.NumTypeArguments();
- TypeParameter& type_arg = TypeParameter::Handle();
- TypeParameter& type_param = TypeParameter::Handle();
+ TypeParameter& type_arg = TypeParameter::Handle(isolate);
+ TypeParameter& type_param = TypeParameter::Handle(isolate);
for (intptr_t i = 0; i < num_type_params; i++) {
type_arg ^= type_args.TypeAt(num_type_args - num_type_params + i);
type_param ^= type_params.TypeAt(i);
@@ -14433,33 +14487,34 @@
}
-static bool IsAsciiPrintChar(intptr_t codePoint) {
- return codePoint >= ' ' && codePoint <= '~';
+static bool IsAsciiPrintChar(intptr_t code_point) {
+ return code_point >= ' ' && code_point <= '~';
}
// Does not null-terminate.
-intptr_t String::EscapedString(char* buffer, int maxLen) const {
+intptr_t String::EscapedString(char* buffer, int max_len) const {
int pos = 0;
CodePointIterator cpi(*this);
while (cpi.Next()) {
- int32_t codePoint = cpi.Current();
- if (IsSpecialCharacter(codePoint)) {
- if (pos + 2 > maxLen) {
+ int32_t code_point = cpi.Current();
+ if (IsSpecialCharacter(code_point)) {
+ if (pos + 2 > max_len) {
return pos;
}
buffer[pos++] = '\\';
- buffer[pos++] = SpecialCharacter(codePoint);
- } else if (IsAsciiPrintChar(codePoint)) {
- buffer[pos++] = codePoint;
+ buffer[pos++] = SpecialCharacter(code_point);
+ } else if (IsAsciiPrintChar(code_point)) {
+ buffer[pos++] = code_point;
} else {
- if (pos + 6 > maxLen) {
+ if (pos + 6 > max_len) {
return pos;
}
- pos += OS::SNPrint((buffer + pos), (maxLen - pos), "\\u%04x", codePoint);
+ pos += OS::SNPrint((buffer + pos), (max_len - pos),
+ "\\u%04x", code_point);
}
- if (pos == maxLen) {
+ if (pos == max_len) {
return pos;
}
}
@@ -14467,20 +14522,20 @@
}
-intptr_t String::EscapedStringLen(intptr_t tooLong) const {
+intptr_t String::EscapedStringLen(intptr_t too_long) const {
intptr_t len = 0;
CodePointIterator cpi(*this);
while (cpi.Next()) {
- int32_t codePoint = cpi.Current();
- if (IsSpecialCharacter(codePoint)) {
+ int32_t code_point = cpi.Current();
+ if (IsSpecialCharacter(code_point)) {
len += 2; // e.g. "\n"
- } else if (IsAsciiPrintChar(codePoint)) {
+ } else if (IsAsciiPrintChar(code_point)) {
len += 1;
} else {
len += 6; // e.g. "\u0000".
}
- if (len > tooLong) {
+ if (len > too_long) {
// No point going further.
break;
}
@@ -14489,36 +14544,36 @@
}
-const char* String::ToUserCString(intptr_t maxLen) const {
+const char* String::ToUserCString(intptr_t max_len, intptr_t nesting) const {
// Compute the needed length for the buffer.
- const intptr_t escapedLen = EscapedStringLen(maxLen);
- intptr_t printLen = escapedLen;
- intptr_t bufferLen = escapedLen + 2; // +2 for quotes.
- if (bufferLen > maxLen) {
- bufferLen = maxLen; // Truncate.
- printLen = maxLen - 5; // -2 for quotes, -3 for elipsis.
+ const intptr_t escaped_len = EscapedStringLen(max_len);
+ intptr_t print_len = escaped_len;
+ intptr_t buffer_len = escaped_len + 2; // +2 for quotes.
+ if (buffer_len > max_len) {
+ buffer_len = max_len; // Truncate.
+ print_len = max_len - 5; // -2 for quotes, -3 for elipsis.
}
// Allocate the buffer.
Zone* zone = Isolate::Current()->current_zone();
- char* buffer = zone->Alloc<char>(bufferLen + 1);
+ char* buffer = zone->Alloc<char>(buffer_len + 1);
// Leading quote.
intptr_t pos = 0;
buffer[pos++] = '\"';
// Print escaped string.
- pos += EscapedString((buffer + pos), printLen);
+ pos += EscapedString((buffer + pos), print_len);
// Trailing quote.
buffer[pos++] = '\"';
- if (printLen < escapedLen) {
+ if (print_len < escaped_len) {
buffer[pos++] = '.';
buffer[pos++] = '.';
buffer[pos++] = '.';
}
- ASSERT(pos <= bufferLen);
+ ASSERT(pos <= buffer_len);
buffer[pos++] = '\0';
return buffer;
@@ -15581,6 +15636,107 @@
}
+const char* GrowableObjectArray::ToUserCString(intptr_t max_len,
+ intptr_t nesting) const {
+ if (Length() == 0) {
+ return "[]";
+ }
+ if (nesting > 3) {
+ return "[...]";
+ }
+
+ Isolate* isolate = Isolate::Current();
+ Zone* zone = isolate->current_zone();
+ Object& obj = Object::Handle(isolate);
+ Instance& element = Instance::Handle(isolate);
+
+ // Pre-print the suffix that we will use if the string is truncated.
+ // It is important to know the suffix length when deciding where to
+ // limit the list.
+ const intptr_t kMaxTruncSuffixLen = 16;
+ char trunc_suffix[kMaxTruncSuffixLen];
+ intptr_t trunc_suffix_len;
+ if (nesting == 0) {
+ trunc_suffix_len = OS::SNPrint(trunc_suffix, 16, "...](length:%" Pd ")",
+ Length());
+ } else {
+ trunc_suffix_len = OS::SNPrint(trunc_suffix, 16, "...]");
+ }
+ bool truncate = false;
+
+ const int kMaxPrintElements = 128;
+ const char* strings[kMaxPrintElements];
+ intptr_t print_len = 1; // +1 for "["
+
+ // Figure out how many elements will fit in the string.
+ int i = 0;
+ while (i < Length()) {
+ if (i == kMaxPrintElements) {
+ if (i < Length()) {
+ truncate = true;
+ }
+ break;
+ }
+ obj = At(i);
+ if (!obj.IsInstance()) {
+ // Bail.
+ UNREACHABLE();
+ return "[<invalid list>]";
+ }
+ element ^= obj.raw();
+
+ // Choose max child length. This is chosen so that it is small
+ // enough to maybe fit but not so small that we can't print
+ // anything.
+ int child_max_len = max_len - print_len;
+ if ((i + 1) < Length()) {
+ child_max_len -= (trunc_suffix_len + 1); // 1 for ","
+ } else {
+ child_max_len -= 1; // 1 for "]"
+ }
+ if (child_max_len < 8) {
+ child_max_len = 8;
+ }
+
+ strings[i] = element.ToUserCString(child_max_len, nesting + 1);
+ print_len += strlen(strings[i]) + 1; // +1 for "," or "]"
+ i++;
+ if (print_len > max_len) {
+ truncate = true;
+ break;
+ }
+ }
+ if (truncate) {
+ // Go backwards until there is enough room for the truncation suffix.
+ while (i >= 0 && (print_len + trunc_suffix_len) > max_len) {
+ i--;
+ print_len -= (strlen(strings[i]) + 1); // +1 for ","
+ }
+ }
+
+ // Finally, allocate and print the string.
+ int num_to_print = i;
+ char* buffer = zone->Alloc<char>(print_len + 1); // +1 for "\0"
+ intptr_t pos = 0;
+ buffer[pos++] = '[';
+ for (i = 0; i < num_to_print; i++) {
+ if ((i + 1) == Length()) {
+ pos += OS::SNPrint((buffer + pos), (max_len + 1 - pos),
+ "%s]", strings[i]);
+ } else {
+ pos += OS::SNPrint((buffer + pos), (max_len + 1 - pos),
+ "%s,", strings[i]);
+ }
+ }
+ if (i < Length()) {
+ pos += OS::SNPrint((buffer + pos), (max_len + 1 - pos), "%s", trunc_suffix);
+ }
+ ASSERT(pos <= max_len);
+ buffer[pos] = '\0';
+ return buffer;
+}
+
+
void GrowableObjectArray::PrintToJSONStream(JSONStream* stream,
bool ref) const {
Instance::PrintToJSONStream(stream, ref);
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 51d6418..93c865f 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -778,6 +778,13 @@
return OFFSET_OF(RawClass, type_arguments_field_offset_in_words_);
}
+ RawType* CanonicalType() const {
+ if ((NumTypeArguments() == 0) && !IsSignatureClass()) {
+ return reinterpret_cast<RawType*>(raw_ptr()->canonical_types_);
+ }
+ return reinterpret_cast<RawType*>(Object::null());
+ }
+
// The super type of this class, Object type if not explicitly specified.
// Note that the super type may be bounded, as in this example:
// class C<T> extends S<T> { }; class S<T extends num> { };
@@ -1084,8 +1091,8 @@
void set_constants(const Array& value) const;
- void set_canonical_types(const Array& value) const;
- RawArray* canonical_types() const;
+ void set_canonical_types(const Object& value) const;
+ RawObject* canonical_types() const;
RawArray* invocation_dispatcher_cache() const;
void set_invocation_dispatcher_cache(const Array& cache) const;
@@ -1727,8 +1734,10 @@
raw_ptr()->optimized_call_site_count_ = static_cast<uint16_t>(value);
}
- bool is_optimizable() const;
- void set_is_optimizable(bool value) const;
+ bool IsOptimizable() const;
+ bool IsNativeAutoSetupScope() const;
+ void SetIsOptimizable(bool value) const;
+ void SetIsNativeAutoSetupScope(bool value) const;
bool has_finally() const {
return HasFinallyBit::decode(raw_ptr()->kind_tag_);
@@ -1965,6 +1974,10 @@
void set_num_optional_parameters(intptr_t value) const; // Encoded value.
void set_kind_tag(intptr_t value) const;
void set_data(const Object& value) const;
+ bool is_optimizable() const {
+ return OptimizableBit::decode(raw_ptr()->kind_tag_);
+ }
+ void set_is_optimizable(bool value) const;
static RawFunction* New();
@@ -2106,6 +2119,8 @@
static intptr_t value_offset() { return OFFSET_OF(RawField, value_); }
+ static intptr_t kind_bits_offset() { return OFFSET_OF(RawField, kind_bits_); }
+
intptr_t token_pos() const { return raw_ptr()->token_pos_; }
bool has_initializer() const {
@@ -2142,6 +2157,25 @@
return r;
}
+ bool IsUnboxedField() const {
+ return is_unboxing_candidate()
+ && !is_final()
+ && (guarded_cid() == kDoubleCid && !is_nullable());
+ }
+
+ bool IsPotentialUnboxedField() const {
+ return is_unboxing_candidate()
+ && (IsUnboxedField() ||
+ (!is_final() && (guarded_cid() == kIllegalCid)));
+ }
+
+ bool is_unboxing_candidate() const {
+ return UnboxingCandidateBit::decode(raw_ptr()->kind_bits_);
+ }
+ void set_is_unboxing_candidate(bool b) const {
+ set_kind_bits(UnboxingCandidateBit::update(b, raw_ptr()->kind_bits_));
+ }
+
static bool IsExternalizableCid(intptr_t cid) {
return (cid == kOneByteStringCid) || (cid == kTwoByteStringCid);
}
@@ -2201,16 +2235,22 @@
JSONStream* stream, const Instance& instance, bool ref) const;
private:
+ friend class StoreInstanceFieldInstr; // Generated code access to bit field.
+
enum {
- kConstBit = 1,
+ kConstBit = 0,
kStaticBit,
kFinalBit,
kHasInitializerBit,
+ kUnboxingCandidateBit
};
class ConstBit : public BitField<bool, kConstBit, 1> {};
class StaticBit : public BitField<bool, kStaticBit, 1> {};
class FinalBit : public BitField<bool, kFinalBit, 1> {};
class HasInitializerBit : public BitField<bool, kHasInitializerBit, 1> {};
+ class UnboxingCandidateBit : public BitField<bool,
+ kUnboxingCandidateBit, 1> {
+ };
// Update guarded class id and nullability of the field to reflect assignment
// of the value with the given class id to this field. Returns true, if
@@ -3970,7 +4010,11 @@
// Returns a string representation of this instance in a form
// that is suitable for an end user.
- virtual const char* ToUserCString(intptr_t maxLen = 40) const;
+ //
+ // max_len is advisory, and the returned string may exceed this max
+ // length.
+ virtual const char* ToUserCString(intptr_t max_len = 40,
+ intptr_t nesting = 0) const;
static intptr_t InstanceSize() {
return RoundedAllocationSize(sizeof(RawInstance));
@@ -4965,7 +5009,8 @@
Dart_PeerFinalizer cback) const;
// Produces a quoted, escaped, (possibly) truncated string.
- const char* ToUserCString(intptr_t maxLen = 40) const;
+ const char* ToUserCString(intptr_t max_len = 40,
+ intptr_t nesting = 0) const;
// Creates a new String object from a C string that is assumed to contain
// UTF-8 encoded characters and '\0' is considered a termination character.
@@ -5091,7 +5136,7 @@
CallbackType new_symbol,
Snapshot::Kind kind);
- intptr_t EscapedString(char* buffer, int maxLen) const;
+ intptr_t EscapedString(char* buffer, int max_len) const;
intptr_t EscapedStringLen(intptr_t tooLong) const;
FINAL_HEAP_OBJECT_IMPLEMENTATION(String, Instance);
@@ -5693,6 +5738,11 @@
return Instance::null();
}
+ // Produces a readable representation of this array, e.g. '[1,2,3]',
+ // subject to length limits.
+ const char* ToUserCString(intptr_t max_len = 40,
+ intptr_t nesting = 0) const;
+
static intptr_t type_arguments_offset() {
return OFFSET_OF(RawGrowableObjectArray, type_arguments_);
}
diff --git a/runtime/vm/object_test.cc b/runtime/vm/object_test.cc
index ec1fc42..00c19bd 100644
--- a/runtime/vm/object_test.cc
+++ b/runtime/vm/object_test.cc
@@ -3643,7 +3643,15 @@
"class _Cobra { }\n"
"var instance = new _Cobra();\n"
"\n"
+ "var empty_list = [];\n"
"var simple_list = [1,2,'otter'];\n"
+ "var nested_list = [[[[1]]],[2,'otter']];\n"
+ "var deeply_nested_list = [[[[[1]]]],[2,'otter']];\n"
+ "var toolong_list = "
+ "['0123456789','0123456789','0123456789','0123456789'];\n"
+ "var toolong2_list = [toolong];\n"
+ "var justenough_list = [0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,99];"
+ "var toolong3_list = [0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,3,4];"
"\n"
"var simple_map = {1: 2, 2: 'otter'};\n";
Dart_Handle lib = TestCase::LoadTestScript(kScriptChars, NULL);
@@ -3704,13 +3712,56 @@
obj ^= Api::UnwrapHandle(result);
EXPECT_STREQ("Instance of '_Cobra'", obj.ToUserCString());
+ // Empty list.
+ result = Dart_GetField(lib, NewString("empty_list"));
+ EXPECT_VALID(result);
+ obj ^= Api::UnwrapHandle(result);
+ EXPECT_STREQ("[]", obj.ToUserCString());
+
// Simple list.
- //
- // TODO(turnidge): Consider showing something like: [1, 2, 'otter'].
result = Dart_GetField(lib, NewString("simple_list"));
EXPECT_VALID(result);
obj ^= Api::UnwrapHandle(result);
- EXPECT_STREQ("Instance(length:3) of '_GrowableList'",
+ EXPECT_STREQ("[1,2,\"otter\"]", obj.ToUserCString());
+
+ // Nested list.
+ result = Dart_GetField(lib, NewString("nested_list"));
+ EXPECT_VALID(result);
+ obj ^= Api::UnwrapHandle(result);
+ EXPECT_STREQ("[[[[1]]],[2,\"otter\"]]", obj.ToUserCString());
+
+ // Deeply ested list.
+ result = Dart_GetField(lib, NewString("deeply_nested_list"));
+ EXPECT_VALID(result);
+ obj ^= Api::UnwrapHandle(result);
+ EXPECT_STREQ("[[[[[...]]]],[2,\"otter\"]]", obj.ToUserCString());
+
+ // Truncation.
+ result = Dart_GetField(lib, NewString("toolong_list"));
+ EXPECT_VALID(result);
+ obj ^= Api::UnwrapHandle(result);
+ EXPECT_STREQ("[\"0123456789\",\"012345\"...,...](length:4)",
+ obj.ToUserCString());
+
+ // More truncation.
+ result = Dart_GetField(lib, NewString("toolong2_list"));
+ EXPECT_VALID(result);
+ obj ^= Api::UnwrapHandle(result);
+ EXPECT_STREQ("[\"012345678901234567890123456789012\"...]",
+ obj.ToUserCString());
+
+ // Just fits.
+ result = Dart_GetField(lib, NewString("justenough_list"));
+ EXPECT_VALID(result);
+ obj ^= Api::UnwrapHandle(result);
+ EXPECT_STREQ("[0,1,2,3,4,0,1,2,3,4,0,1,2,3,4,0,1,2,99]",
+ obj.ToUserCString());
+
+ // Just too big, small elements.
+ result = Dart_GetField(lib, NewString("toolong3_list"));
+ EXPECT_VALID(result);
+ obj ^= Api::UnwrapHandle(result);
+ EXPECT_STREQ("[0,1,2,3,4,0,1,2,3,4,0,1,...](length:20)",
obj.ToUserCString());
// Simple map.
diff --git a/runtime/vm/os.h b/runtime/vm/os.h
index 9eddae5..e260853 100644
--- a/runtime/vm/os.h
+++ b/runtime/vm/os.h
@@ -84,6 +84,9 @@
// Sleep the currently executing thread for millis ms.
static void Sleep(int64_t millis);
+ // Sleep the currently executing thread for micros microseconds.
+ static void SleepMicros(int64_t micros);
+
// Debug break.
static void DebugBreak();
diff --git a/runtime/vm/os_android.cc b/runtime/vm/os_android.cc
index cbce25c..c78bda5 100644
--- a/runtime/vm/os_android.cc
+++ b/runtime/vm/os_android.cc
@@ -319,8 +319,29 @@
void OS::Sleep(int64_t millis) {
- // TODO(5411554): For now just use usleep we may have to revisit this.
- usleep(millis * 1000);
+ int64_t micros = millis * kMicrosecondsPerMillisecond;
+ SleepMicros(micros);
+}
+
+
+void OS::SleepMicros(int64_t micros) {
+ struct timespec req; // requested.
+ struct timespec rem; // remainder.
+ int64_t seconds = micros / kMicrosecondsPerSecond;
+ micros = micros - seconds * kMicrosecondsPerSecond;
+ int64_t nanos = micros * kNanosecondsPerMicrosecond;
+ req.tv_sec = seconds;
+ req.tv_nsec = nanos;
+ while (true) {
+ int r = nanosleep(&req, &rem);
+ if (r == 0) {
+ break;
+ }
+ // We should only ever see an interrupt error.
+ ASSERT(errno == EINTR);
+ // Copy remainder into requested and repeat.
+ req = rem;
+ }
}
diff --git a/runtime/vm/os_linux.cc b/runtime/vm/os_linux.cc
index ed1d668..97e9e55 100644
--- a/runtime/vm/os_linux.cc
+++ b/runtime/vm/os_linux.cc
@@ -404,8 +404,29 @@
void OS::Sleep(int64_t millis) {
- // TODO(5411554): For now just use usleep we may have to revisit this.
- usleep(millis * 1000);
+ int64_t micros = millis * kMicrosecondsPerMillisecond;
+ SleepMicros(micros);
+}
+
+
+void OS::SleepMicros(int64_t micros) {
+ struct timespec req; // requested.
+ struct timespec rem; // remainder.
+ int64_t seconds = micros / kMicrosecondsPerSecond;
+ micros = micros - seconds * kMicrosecondsPerSecond;
+ int64_t nanos = micros * kNanosecondsPerMicrosecond;
+ req.tv_sec = seconds;
+ req.tv_nsec = nanos;
+ while (true) {
+ int r = nanosleep(&req, &rem);
+ if (r == 0) {
+ break;
+ }
+ // We should only ever see an interrupt error.
+ ASSERT(errno == EINTR);
+ // Copy remainder into requested and repeat.
+ req = rem;
+ }
}
diff --git a/runtime/vm/os_macos.cc b/runtime/vm/os_macos.cc
index 76d9fb6..10f6dcf 100644
--- a/runtime/vm/os_macos.cc
+++ b/runtime/vm/os_macos.cc
@@ -131,8 +131,29 @@
void OS::Sleep(int64_t millis) {
- // TODO(5411554): For now just use usleep we may have to revisit this.
- usleep(millis * 1000);
+ int64_t micros = millis * kMicrosecondsPerMillisecond;
+ SleepMicros(micros);
+}
+
+
+void OS::SleepMicros(int64_t micros) {
+ struct timespec req; // requested.
+ struct timespec rem; // remainder.
+ int64_t seconds = micros / kMicrosecondsPerSecond;
+ micros = micros - seconds * kMicrosecondsPerSecond;
+ int64_t nanos = micros * kNanosecondsPerMicrosecond;
+ req.tv_sec = seconds;
+ req.tv_nsec = nanos;
+ while (true) {
+ int r = nanosleep(&req, &rem);
+ if (r == 0) {
+ break;
+ }
+ // We should only ever see an interrupt error.
+ ASSERT(errno == EINTR);
+ // Copy remainder into requested and repeat.
+ req = rem;
+ }
}
diff --git a/runtime/vm/os_win.cc b/runtime/vm/os_win.cc
index fcb8447..98e864e 100644
--- a/runtime/vm/os_win.cc
+++ b/runtime/vm/os_win.cc
@@ -174,6 +174,16 @@
}
+void OS::SleepMicros(int64_t micros) {
+ // Windows only supports millisecond sleeps.
+ if (micros < kMicrosecondsPerMillisecond) {
+ // Calling ::Sleep with 0 has no determined behaviour, round up.
+ micros = kMicrosecondsPerMillisecond;
+ }
+ OS::Sleep(micros / kMicrosecondsPerMillisecond);
+}
+
+
void OS::DebugBreak() {
#if defined(_MSC_VER)
// Microsoft Visual C/C++ or drop-in replacement.
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 7ffa22e..72f93d8 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -5317,12 +5317,14 @@
// Now resolve the native function to the corresponding native entrypoint.
const int num_params = NativeArguments::ParameterCountForResolution(func);
+ bool auto_setup_scope = true;
NativeFunction native_function = NativeEntry::ResolveNative(
- library, native_name, num_params);
+ library, native_name, num_params, &auto_setup_scope);
if (native_function == NULL) {
ErrorMsg(native_pos, "native function '%s' cannot be found",
native_name.ToCString());
}
+ func.SetIsNativeAutoSetupScope(auto_setup_scope);
// Now add the NativeBodyNode and return statement.
Dart_NativeEntryResolver resolver = library.native_entry_resolver();
@@ -8825,7 +8827,7 @@
// An exception may not occur in every parse attempt, i.e., the
// generated AST is not deterministic. Therefore mark the function as
// not optimizable.
- current_function().set_is_optimizable(false);
+ current_function().SetIsOptimizable(false);
field.set_value(Object::null_instance());
// It is a compile-time error if evaluation of a compile-time constant
// would raise an exception.
@@ -8907,7 +8909,7 @@
// An exception may not occur in every parse attempt, i.e., the
// generated AST is not deterministic. Therefore mark the function as
// not optimizable.
- current_function().set_is_optimizable(false);
+ current_function().SetIsOptimizable(false);
if (result.IsUnhandledException()) {
return result.raw();
} else {
diff --git a/runtime/vm/port_test.cc b/runtime/vm/port_test.cc
index 329f81c..e2482e9 100644
--- a/runtime/vm/port_test.cc
+++ b/runtime/vm/port_test.cc
@@ -125,7 +125,7 @@
intptr_t message_len = strlen(message) + 1;
EXPECT(PortMap::PostMessage(new Message(
- port, 0, reinterpret_cast<uint8_t*>(strdup(message)), message_len,
+ port, reinterpret_cast<uint8_t*>(strdup(message)), message_len,
Message::kNormalPriority)));
// Check that the message notify callback was called.
@@ -139,7 +139,7 @@
intptr_t message_len = strlen(message) + 1;
EXPECT(!PortMap::PostMessage(new Message(
- 0, 0, reinterpret_cast<uint8_t*>(strdup(message)), message_len,
+ 0, reinterpret_cast<uint8_t*>(strdup(message)), message_len,
Message::kNormalPriority)));
}
diff --git a/runtime/vm/profiler.cc b/runtime/vm/profiler.cc
index 8de6d12..d254520 100644
--- a/runtime/vm/profiler.cc
+++ b/runtime/vm/profiler.cc
@@ -6,6 +6,7 @@
#include "platform/utils.h"
+#include "vm/atomic.h"
#include "vm/isolate.h"
#include "vm/json_stream.h"
#include "vm/native_symbol.h"
@@ -13,573 +14,437 @@
#include "vm/os.h"
#include "vm/profiler.h"
#include "vm/signal_handler.h"
+#include "vm/simulator.h"
namespace dart {
-// Notes on locking and signal handling:
-//
-// The ProfilerManager has a single monitor (monitor_). This monitor guards
-// access to the schedule list of isolates (isolates_, isolates_size_, etc).
-//
-// Each isolate has a mutex (profiler_data_mutex_) which protects access
-// to the isolate's profiler data.
-//
-// Locks can be taken in this order:
-// 1. ProfilerManager::monitor_
-// 2. isolate->profiler_data_mutex_
-// In other words, it is not acceptable to take ProfilerManager::monitor_
-// after grabbing isolate->profiler_data_mutex_.
-//
-// ProfileManager::monitor_ taking entry points:
-// InitOnce, Shutdown
-// ProfilerManager::monitor_
-// ScheduleIsolate, DescheduleIsolate.
-// ProfilerManager::monitor_, isolate->profiler_data_mutex_
-// ThreadMain
-// isolate->profiler_data_mutex_ taking entry points:
-// SetupIsolateForProfiling, FreeIsolateForProfiling.
-// ProfilerManager::monitor_, isolate->profiler_data_mutex_
-// ScheduleIsolate, DescheduleIsolate.
-// ProfilerManager::monitor_, isolate->profiler_data_mutex_
-// ProfileSignalAction
-// isolate->profiler_data_mutex_
-// ProfilerManager::monitor_, isolate->profiler_data_mutex_
-//
-// Signal handling and locking:
-// On OSes with pthreads (Android, Linux, and Mac) we use signal delivery
-// to interrupt the isolate running thread for sampling. After a thread
-// is sent the SIGPROF, it is removed from the scheduled isolate list.
-// Inside the signal handler, after the sample is taken, the isolate is
-// added to the scheduled isolate list again. The side effect of this is
-// that the signal handler must be able to acquire the isolate profiler data
-// mutex and the profile manager monitor. When an isolate running thread
-// (potential signal target) calls into an entry point which acquires
-// ProfileManager::monitor_ signal delivery must be blocked. An example is
-// ProfileManager::ScheduleIsolate which blocks signal delivery while removing
-// the scheduling the isolate.
-//
// Notes on stack frame walking:
//
// The sampling profiler will collect up to Sample::kNumStackFrames stack frames
// The stack frame walking code uses the frame pointer to traverse the stack.
// If the VM is compiled without frame pointers (which is the default on
-// recent GCC versions with optimizing enabled) the stack walking code will
+// recent GCC versions with optimizing enabled) the stack walking code may
// fail (sometimes leading to a crash).
//
-DEFINE_FLAG(bool, profile, false, "Enable Sampling Profiler");
+#if defined(USING_SIMULATOR) || defined(TARGET_OS_WINDOWS) || \
+ defined(TARGET_OS_MACOS) || defined(TARGET_OS_ANDROID)
+ DEFINE_FLAG(bool, profile, false, "Enable Sampling Profiler");
+#else
+ DEFINE_FLAG(bool, profile, true, "Enable Sampling Profiler");
+#endif
DEFINE_FLAG(bool, trace_profiled_isolates, false, "Trace profiled isolates.");
+DEFINE_FLAG(charp, profile_dir, NULL,
+ "Enable writing profile data into specified directory.");
+DEFINE_FLAG(int, profile_period, 1000,
+ "Time between profiler samples in microseconds. Minimum 250.");
-bool ProfilerManager::initialized_ = false;
-bool ProfilerManager::shutdown_ = false;
-bool ProfilerManager::thread_running_ = false;
-Monitor* ProfilerManager::monitor_ = NULL;
-Monitor* ProfilerManager::start_stop_monitor_ = NULL;
-Isolate** ProfilerManager::isolates_ = NULL;
-intptr_t ProfilerManager::isolates_capacity_ = 0;
-intptr_t ProfilerManager::isolates_size_ = 0;
+bool Profiler::initialized_ = false;
+Monitor* Profiler::monitor_ = NULL;
+SampleBuffer* Profiler::sample_buffer_ = NULL;
-
-void ProfilerManager::InitOnce() {
-#if defined(USING_SIMULATOR)
- // Force disable of profiling on simulator.
- FLAG_profile = false;
-#endif
-#if defined(TARGET_OS_WINDOWS)
- // Force disable of profiling on Windows.
- FLAG_profile = false;
-#endif
+void Profiler::InitOnce() {
+ const int kMinimumProfilePeriod = 250;
if (!FLAG_profile) {
return;
}
- NativeSymbolResolver::InitOnce();
ASSERT(!initialized_);
- monitor_ = new Monitor();
- start_stop_monitor_ = new Monitor();
initialized_ = true;
- ResizeIsolates(16);
- if (FLAG_trace_profiled_isolates) {
- OS::Print("ProfilerManager starting up.\n");
+ monitor_ = new Monitor();
+ sample_buffer_ = new SampleBuffer();
+ NativeSymbolResolver::InitOnce();
+ ThreadInterrupter::InitOnce();
+ if (FLAG_profile_period < kMinimumProfilePeriod) {
+ FLAG_profile_period = kMinimumProfilePeriod;
}
- {
- ScopedMonitor startup_lock(start_stop_monitor_);
- Thread::Start(ThreadMain, 0);
- while (!thread_running_) {
- // Wait until profiler thread has started up.
- startup_lock.Wait();
- }
- }
- if (FLAG_trace_profiled_isolates) {
- OS::Print("ProfilerManager running.\n");
- }
+ ThreadInterrupter::SetInterruptPeriod(FLAG_profile_period);
}
-void ProfilerManager::Shutdown() {
+void Profiler::Shutdown() {
if (!FLAG_profile) {
return;
}
ASSERT(initialized_);
- if (FLAG_trace_profiled_isolates) {
- OS::Print("ProfilerManager shutting down.\n");
- }
- intptr_t size_at_shutdown = 0;
- {
- ScopedSignalBlocker ssb;
- {
- ScopedMonitor lock(monitor_);
- shutdown_ = true;
- size_at_shutdown = isolates_size_;
- isolates_size_ = 0;
- free(isolates_);
- isolates_ = NULL;
- lock.Notify();
- }
- }
+ ThreadInterrupter::Shutdown();
NativeSymbolResolver::ShutdownOnce();
- {
- ScopedMonitor shutdown_lock(start_stop_monitor_);
- while (thread_running_) {
- // Wait until profiler thread has exited.
- shutdown_lock.Wait();
- }
- }
- if (FLAG_trace_profiled_isolates) {
- OS::Print("ProfilerManager shut down (%" Pd ").\n", size_at_shutdown);
- }
}
-void ProfilerManager::SetupIsolateForProfiling(Isolate* isolate) {
+void Profiler::InitProfilingForIsolate(Isolate* isolate, bool shared_buffer) {
if (!FLAG_profile) {
return;
}
ASSERT(isolate != NULL);
+ ASSERT(sample_buffer_ != NULL);
+ MonitorLocker ml(monitor_);
{
- ScopedSignalBlocker ssb;
- {
- ScopedMutex profiler_data_lock(isolate->profiler_data_mutex());
- SampleBuffer* sample_buffer = new SampleBuffer();
- ASSERT(sample_buffer != NULL);
- IsolateProfilerData* profiler_data =
- new IsolateProfilerData(isolate, sample_buffer);
- ASSERT(profiler_data != NULL);
- profiler_data->set_sample_interval_micros(1000);
- isolate->set_profiler_data(profiler_data);
- if (FLAG_trace_profiled_isolates) {
- OS::Print("ProfilerManager Setup Isolate %p %s %p\n",
- isolate,
- isolate->name(),
- reinterpret_cast<void*>(Thread::GetCurrentThreadId()));
- }
+ MutexLocker profiler_data_lock(isolate->profiler_data_mutex());
+ SampleBuffer* sample_buffer = sample_buffer_;
+ if (!shared_buffer) {
+ sample_buffer = new SampleBuffer();
+ }
+ IsolateProfilerData* profiler_data =
+ new IsolateProfilerData(sample_buffer, !shared_buffer);
+ ASSERT(profiler_data != NULL);
+ isolate->set_profiler_data(profiler_data);
+ if (FLAG_trace_profiled_isolates) {
+ OS::Print("Profiler Setup %p %s\n", isolate, isolate->name());
}
}
}
-void ProfilerManager::FreeIsolateProfilingData(Isolate* isolate) {
- ScopedMutex profiler_data_lock(isolate->profiler_data_mutex());
- IsolateProfilerData* profiler_data = isolate->profiler_data();
- if (profiler_data == NULL) {
- // Already freed.
- return;
- }
- isolate->set_profiler_data(NULL);
- SampleBuffer* sample_buffer = profiler_data->sample_buffer();
- ASSERT(sample_buffer != NULL);
- profiler_data->set_sample_buffer(NULL);
- delete sample_buffer;
- delete profiler_data;
- if (FLAG_trace_profiled_isolates) {
- OS::Print("ProfilerManager Shutdown Isolate %p %s %p\n",
- isolate,
- isolate->name(),
- reinterpret_cast<void*>(Thread::GetCurrentThreadId()));
- }
-}
-
-
-void ProfilerManager::ShutdownIsolateForProfiling(Isolate* isolate) {
+void Profiler::ShutdownProfilingForIsolate(Isolate* isolate) {
ASSERT(isolate != NULL);
if (!FLAG_profile) {
return;
}
+ // We do not have a current isolate.
+ ASSERT(Isolate::Current() == NULL);
+ MonitorLocker ml(monitor_);
{
- ScopedSignalBlocker ssb;
- FreeIsolateProfilingData(isolate);
- }
-}
-
-
-void ProfilerManager::ScheduleIsolateHelper(Isolate* isolate) {
- ScopedMonitor lock(monitor_);
- {
- if (shutdown_) {
- // Shutdown.
- return;
- }
- ScopedMutex profiler_data_lock(isolate->profiler_data_mutex());
+ MutexLocker profiler_data_lock(isolate->profiler_data_mutex());
IsolateProfilerData* profiler_data = isolate->profiler_data();
if (profiler_data == NULL) {
+ // Already freed.
return;
}
- profiler_data->Scheduled(OS::GetCurrentTimeMicros(),
- Thread::GetCurrentThreadId());
+ isolate->set_profiler_data(NULL);
+ profiler_data->set_sample_buffer(NULL);
+ delete profiler_data;
+ if (FLAG_trace_profiled_isolates) {
+ OS::Print("Profiler Shutdown %p %s\n", isolate, isolate->name());
+ }
}
- intptr_t i = FindIsolate(isolate);
- if (i >= 0) {
- // Already scheduled.
- return;
- }
- AddIsolate(isolate);
- lock.Notify();
}
-void ProfilerManager::ScheduleIsolate(Isolate* isolate, bool inside_signal) {
+void Profiler::BeginExecution(Isolate* isolate) {
+ if (isolate == NULL) {
+ return;
+ }
if (!FLAG_profile) {
return;
}
ASSERT(initialized_);
- ASSERT(isolate != NULL);
- if (!inside_signal) {
- ScopedSignalBlocker ssb;
- {
- ScheduleIsolateHelper(isolate);
- }
- } else {
- // Do not need a signal blocker inside a signal handler.
- {
- ScheduleIsolateHelper(isolate);
- }
+ IsolateProfilerData* profiler_data = isolate->profiler_data();
+ if (profiler_data == NULL) {
+ return;
}
+ SampleBuffer* sample_buffer = profiler_data->sample_buffer();
+ if (sample_buffer == NULL) {
+ return;
+ }
+ Sample* sample = sample_buffer->ReserveSample();
+ sample->Init(Sample::kIsolateStart, isolate, OS::GetCurrentTimeMicros(),
+ Thread::GetCurrentThreadId());
+ ThreadInterrupter::Register(RecordSampleInterruptCallback, isolate);
}
-void ProfilerManager::DescheduleIsolate(Isolate* isolate) {
+void Profiler::EndExecution(Isolate* isolate) {
+ if (isolate == NULL) {
+ return;
+ }
if (!FLAG_profile) {
return;
}
ASSERT(initialized_);
- ASSERT(isolate != NULL);
- {
- ScopedSignalBlocker ssb;
- {
- ScopedMonitor lock(monitor_);
- if (shutdown_) {
- // Shutdown.
- return;
- }
- intptr_t i = FindIsolate(isolate);
- if (i < 0) {
- // Not scheduled.
- return;
- }
- {
- ScopedMutex profiler_data_lock(isolate->profiler_data_mutex());
- IsolateProfilerData* profiler_data = isolate->profiler_data();
- if (profiler_data != NULL) {
- profiler_data->Descheduled();
- }
- }
- RemoveIsolate(i);
- lock.Notify();
- }
+ ThreadInterrupter::Unregister();
+ IsolateProfilerData* profiler_data = isolate->profiler_data();
+ if (profiler_data == NULL) {
+ return;
}
+ SampleBuffer* sample_buffer = profiler_data->sample_buffer();
+ if (sample_buffer == NULL) {
+ return;
+ }
+ Sample* sample = sample_buffer->ReserveSample();
+ sample->Init(Sample::kIsolateStop, isolate, OS::GetCurrentTimeMicros(),
+ Thread::GetCurrentThreadId());
}
-void PrintToJSONStream(Isolate* isolate, JSONStream* stream) {
+void Profiler::RecordTickInterruptCallback(const InterruptedThreadState& state,
+ void* data) {
+ Isolate* isolate = reinterpret_cast<Isolate*>(data);
+ if (isolate == NULL) {
+ return;
+ }
+ IsolateProfilerData* profiler_data = isolate->profiler_data();
+ if (profiler_data == NULL) {
+ return;
+ }
+ SampleBuffer* sample_buffer = profiler_data->sample_buffer();
+ if (sample_buffer == NULL) {
+ return;
+ }
+ Sample* sample = sample_buffer->ReserveSample();
+ sample->Init(Sample::kIsolateSample, isolate, OS::GetCurrentTimeMicros(),
+ state.tid);
+}
+
+
+void Profiler::RecordSampleInterruptCallback(
+ const InterruptedThreadState& state,
+ void* data) {
+ Isolate* isolate = reinterpret_cast<Isolate*>(data);
+ if (isolate == NULL) {
+ return;
+ }
+ IsolateProfilerData* profiler_data = isolate->profiler_data();
+ if (profiler_data == NULL) {
+ return;
+ }
+ SampleBuffer* sample_buffer = profiler_data->sample_buffer();
+ if (sample_buffer == NULL) {
+ return;
+ }
+ Sample* sample = sample_buffer->ReserveSample();
+ sample->Init(Sample::kIsolateSample, isolate, OS::GetCurrentTimeMicros(),
+ state.tid);
+ uintptr_t stack_lower = 0;
+ uintptr_t stack_upper = 0;
+ isolate->GetStackBounds(&stack_lower, &stack_upper);
+ if ((stack_lower == 0) || (stack_upper == 0)) {
+ stack_lower = 0;
+ stack_upper = 0;
+ }
+ ProfilerSampleStackWalker stackWalker(sample, stack_lower, stack_upper,
+ state.pc, state.fp, state.sp);
+ stackWalker.walk();
+}
+
+
+void Profiler::PrintToJSONStream(Isolate* isolate, JSONStream* stream) {
ASSERT(isolate == Isolate::Current());
- {
- // We can't get signals here.
- }
UNIMPLEMENTED();
}
-void ProfilerManager::ResizeIsolates(intptr_t new_capacity) {
- ASSERT(new_capacity < kMaxProfiledIsolates);
- ASSERT(new_capacity > isolates_capacity_);
- Isolate* isolate = NULL;
- isolates_ = reinterpret_cast<Isolate**>(
- realloc(isolates_, sizeof(isolate) * new_capacity));
- isolates_capacity_ = new_capacity;
-}
-
-
-void ProfilerManager::AddIsolate(Isolate* isolate) {
- // Must be called with monitor_ locked.
- if (isolates_ == NULL) {
- // We are shutting down.
- return;
- }
- if (isolates_size_ == isolates_capacity_) {
- ResizeIsolates(isolates_capacity_ == 0 ? 16 : isolates_capacity_ * 2);
- }
- isolates_[isolates_size_] = isolate;
- isolates_size_++;
-}
-
-
-intptr_t ProfilerManager::FindIsolate(Isolate* isolate) {
- // Must be called with monitor_ locked.
- if (isolates_ == NULL) {
- // We are shutting down.
- return -1;
- }
- for (intptr_t i = 0; i < isolates_size_; i++) {
- if (isolates_[i] == isolate) {
- return i;
- }
- }
- return -1;
-}
-
-
-void ProfilerManager::RemoveIsolate(intptr_t i) {
- // Must be called with monitor_ locked.
- if (isolates_ == NULL) {
- // We are shutting down.
- return;
- }
- ASSERT(i < isolates_size_);
- intptr_t last = isolates_size_ - 1;
- if (i != last) {
- isolates_[i] = isolates_[last];
- }
- // Mark last as NULL.
- isolates_[last] = NULL;
- // Pop.
- isolates_size_--;
-}
-
-
-static char* FindSymbolName(uintptr_t pc, bool* native_symbol) {
+static const char* FindSymbolName(uintptr_t pc, bool* symbol_name_allocated) {
// TODO(johnmccutchan): Differentiate between symbols which can't be found
// and symbols which were GCed. (Heap::CodeContains).
- ASSERT(native_symbol != NULL);
+ ASSERT(symbol_name_allocated != NULL);
const char* symbol_name = "Unknown";
- *native_symbol = false;
+ *symbol_name_allocated = false;
+ if (pc == 0) {
+ return const_cast<char*>(Sample::kNoFrame);
+ }
const Code& code = Code::Handle(Code::LookupCode(pc));
- if (code.IsNull()) {
- // Possibly a native symbol.
- char* native_name = NativeSymbolResolver::LookupSymbolName(pc);
- if (native_name != NULL) {
- symbol_name = native_name;
- *native_symbol = true;
- }
- } else {
+ if (!code.IsNull()) {
const Function& function = Function::Handle(code.function());
if (!function.IsNull()) {
const String& name = String::Handle(function.QualifiedUserVisibleName());
if (!name.IsNull()) {
symbol_name = name.ToCString();
+ return symbol_name;
}
}
+ } else {
+ // Possibly a native symbol.
+ char* native_name = NativeSymbolResolver::LookupSymbolName(pc);
+ if (native_name != NULL) {
+ symbol_name = native_name;
+ *symbol_name_allocated = true;
+ return symbol_name;
+ }
}
- return const_cast<char*>(symbol_name);
-}
-
-
-void ProfilerManager::WriteTracing(Isolate* isolate, const char* name,
- Dart_Port port) {
- ASSERT(isolate == Isolate::Current());
+ const intptr_t kBucketSize = 256;
+ const intptr_t kBucketMask = ~(kBucketSize - 1);
+ // Not a Dart symbol or a native symbol. Bin into buckets by PC.
+ pc &= kBucketMask;
{
- ScopedSignalBlocker ssb;
- {
- ScopedMutex profiler_data_lock(isolate->profiler_data_mutex());
- IsolateProfilerData* profiler_data = isolate->profiler_data();
- if (profiler_data == NULL) {
- return;
- }
- SampleBuffer* sample_buffer = profiler_data->sample_buffer();
- ASSERT(sample_buffer != NULL);
- JSONStream stream(10 * MB);
- intptr_t tid = reinterpret_cast<intptr_t>(sample_buffer);
- intptr_t pid = 1;
- {
- JSONArray events(&stream);
- {
- JSONObject thread_name(&events);
- thread_name.AddProperty("name", "thread_name");
- thread_name.AddProperty("ph", "M");
- thread_name.AddProperty("tid", tid);
- thread_name.AddProperty("pid", pid);
- {
- JSONObject args(&thread_name, "args");
- args.AddProperty("name", name);
- }
- }
- {
- JSONObject process_name(&events);
- process_name.AddProperty("name", "process_name");
- process_name.AddProperty("ph", "M");
- process_name.AddProperty("tid", tid);
- process_name.AddProperty("pid", pid);
- {
- JSONObject args(&process_name, "args");
- args.AddProperty("name", "Dart VM");
- }
- }
- uint64_t last_time = 0;
- for (Sample* i = sample_buffer->FirstSample();
- i != sample_buffer->LastSample();
- i = sample_buffer->NextSample(i)) {
- if (last_time == 0) {
- last_time = i->timestamp;
- }
- intptr_t delta = i->timestamp - last_time;
- {
- double percentage = static_cast<double>(i->cpu_usage) /
- static_cast<double>(delta) * 100.0;
- if (percentage != percentage) {
- percentage = 0.0;
- }
- percentage = percentage < 0.0 ? 0.0 : percentage;
- percentage = percentage > 100.0 ? 100.0 : percentage;
- {
- JSONObject cpu_usage(&events);
- cpu_usage.AddProperty("name", "CPU Usage");
- cpu_usage.AddProperty("ph", "C");
- cpu_usage.AddProperty("tid", tid);
- cpu_usage.AddProperty("pid", pid);
- cpu_usage.AddProperty("ts", static_cast<double>(last_time));
- {
- JSONObject args(&cpu_usage, "args");
- args.AddProperty("CPU", percentage);
- }
- }
- {
- JSONObject cpu_usage(&events);
- cpu_usage.AddProperty("name", "CPU Usage");
- cpu_usage.AddProperty("ph", "C");
- cpu_usage.AddProperty("tid", tid);
- cpu_usage.AddProperty("pid", pid);
- cpu_usage.AddProperty("ts", static_cast<double>(i->timestamp));
- {
- JSONObject args(&cpu_usage, "args");
- args.AddProperty("CPU", percentage);
- }
- }
- }
- for (int j = 0; j < Sample::kNumStackFrames; j++) {
- if (i->pcs[j] == 0) {
- continue;
- }
- bool native_symbol = false;
- char* symbol_name = FindSymbolName(i->pcs[j], &native_symbol);
- {
- JSONObject begin(&events);
- begin.AddProperty("ph", "B");
- begin.AddProperty("tid", tid);
- begin.AddProperty("pid", pid);
- begin.AddProperty("name", symbol_name);
- begin.AddProperty("ts", static_cast<double>(last_time));
- }
- if (native_symbol) {
- NativeSymbolResolver::FreeSymbolName(symbol_name);
- }
- }
- for (int j = Sample::kNumStackFrames-1; j >= 0; j--) {
- if (i->pcs[j] == 0) {
- continue;
- }
- bool native_symbol = false;
- char* symbol_name = FindSymbolName(i->pcs[j], &native_symbol);
- {
- JSONObject end(&events);
- end.AddProperty("ph", "E");
- end.AddProperty("tid", tid);
- end.AddProperty("pid", pid);
- end.AddProperty("name", symbol_name);
- end.AddProperty("ts", static_cast<double>(i->timestamp));
- }
- if (native_symbol) {
- NativeSymbolResolver::FreeSymbolName(symbol_name);
- }
- }
- last_time = i->timestamp;
- }
- }
- char fname[1024];
- #if defined(TARGET_OS_WINDOWS)
- snprintf(fname, sizeof(fname)-1, "c:\\tmp\\isolate-%d.prof",
- static_cast<int>(port));
- #else
- snprintf(fname, sizeof(fname)-1, "/tmp/isolate-%d.prof",
- static_cast<int>(port));
- #endif
- printf("%s\n", fname);
- FILE* f = fopen(fname, "wb");
- ASSERT(f != NULL);
- fputs(stream.ToCString(), f);
- fclose(f);
+ const intptr_t kBuffSize = 256;
+ char buff[kBuffSize];
+ OS::SNPrint(&buff[0], kBuffSize-1, "Unknown [%" Px ", %" Px ")",
+ pc, pc + kBucketSize);
+ symbol_name = strdup(buff);
+ *symbol_name_allocated = true;
+ }
+ return symbol_name;
+}
+
+
+void Profiler::WriteTracingSample(Isolate* isolate, intptr_t pid,
+ Sample* sample, JSONArray& events) {
+ Sample::SampleType type = sample->type;
+ intptr_t tid = Thread::ThreadIdToIntPtr(sample->tid);
+ double timestamp = static_cast<double>(sample->timestamp);
+ const char* isolate_name = isolate->name();
+ switch (type) {
+ case Sample::kIsolateStart: {
+ JSONObject begin(&events);
+ begin.AddProperty("ph", "B");
+ begin.AddProperty("tid", tid);
+ begin.AddProperty("pid", pid);
+ begin.AddProperty("name", isolate_name);
+ begin.AddProperty("ts", timestamp);
}
+ break;
+ case Sample::kIsolateStop: {
+ JSONObject begin(&events);
+ begin.AddProperty("ph", "E");
+ begin.AddProperty("tid", tid);
+ begin.AddProperty("pid", pid);
+ begin.AddProperty("name", isolate_name);
+ begin.AddProperty("ts", timestamp);
+ }
+ break;
+ case Sample::kIsolateSample:
+ // Write "B" events.
+ for (int i = Sample::kNumStackFrames - 1; i >= 0; i--) {
+ bool symbol_name_allocated = false;
+ const char* symbol_name = FindSymbolName(sample->pcs[i],
+ &symbol_name_allocated);
+ {
+ JSONObject begin(&events);
+ begin.AddProperty("ph", "B");
+ begin.AddProperty("tid", tid);
+ begin.AddProperty("pid", pid);
+ begin.AddProperty("name", symbol_name);
+ begin.AddProperty("ts", timestamp);
+ }
+ if (symbol_name_allocated) {
+ free(const_cast<char*>(symbol_name));
+ }
+ }
+ // Write "E" events.
+ for (int i = 0; i < Sample::kNumStackFrames; i++) {
+ bool symbol_name_allocated = false;
+ const char* symbol_name = FindSymbolName(sample->pcs[i],
+ &symbol_name_allocated);
+ {
+ JSONObject begin(&events);
+ begin.AddProperty("ph", "E");
+ begin.AddProperty("tid", tid);
+ begin.AddProperty("pid", pid);
+ begin.AddProperty("name", symbol_name);
+ begin.AddProperty("ts", timestamp);
+ }
+ if (symbol_name_allocated) {
+ free(const_cast<char*>(symbol_name));
+ }
+ }
+ break;
+ default:
+ UNIMPLEMENTED();
}
}
-IsolateProfilerData::IsolateProfilerData(Isolate* isolate,
- SampleBuffer* sample_buffer) {
- isolate_ = isolate;
+void Profiler::WriteTracing(Isolate* isolate) {
+ if (isolate == NULL) {
+ return;
+ }
+ if (!FLAG_profile) {
+ return;
+ }
+ ASSERT(initialized_);
+ if (FLAG_profile_dir == NULL) {
+ return;
+ }
+ Dart_FileOpenCallback file_open = Isolate::file_open_callback();
+ Dart_FileCloseCallback file_close = Isolate::file_close_callback();
+ Dart_FileWriteCallback file_write = Isolate::file_write_callback();
+ if ((file_open == NULL) || (file_close == NULL) || (file_write == NULL)) {
+ // Embedder has not provided necessary callbacks.
+ return;
+ }
+ // We will be looking up code objects within the isolate.
+ ASSERT(Isolate::Current() != NULL);
+ // We do not want to be interrupted while processing the buffer.
+ EndExecution(isolate);
+ MutexLocker profiler_data_lock(isolate->profiler_data_mutex());
+ IsolateProfilerData* profiler_data = isolate->profiler_data();
+ if (profiler_data == NULL) {
+ return;
+ }
+ SampleBuffer* sample_buffer = profiler_data->sample_buffer();
+ ASSERT(sample_buffer != NULL);
+ JSONStream stream(10 * MB);
+ intptr_t pid = OS::ProcessId();
+ {
+ JSONArray events(&stream);
+ {
+ JSONObject process_name(&events);
+ process_name.AddProperty("name", "process_name");
+ process_name.AddProperty("ph", "M");
+ process_name.AddProperty("pid", pid);
+ {
+ JSONObject args(&process_name, "args");
+ args.AddProperty("name", "Dart VM");
+ }
+ }
+ for (intptr_t i = 0; i < sample_buffer->capacity(); i++) {
+ Sample* sample = sample_buffer->GetSample(i);
+ if (sample->isolate != isolate) {
+ continue;
+ }
+ if (sample->timestamp == 0) {
+ continue;
+ }
+ WriteTracingSample(isolate, pid, sample, events);
+ }
+ }
+ const char* format = "%s/dart-profile-%" Pd "-%" Pd ".json";
+ intptr_t len = OS::SNPrint(NULL, 0, format,
+ FLAG_profile_dir, pid, isolate->main_port());
+ char* filename = Isolate::Current()->current_zone()->Alloc<char>(len + 1);
+ OS::SNPrint(filename, len + 1, format,
+ FLAG_profile_dir, pid, isolate->main_port());
+ void* f = file_open(filename, true);
+ if (f == NULL) {
+ // Cannot write.
+ return;
+ }
+ TextBuffer* buffer = stream.buffer();
+ ASSERT(buffer != NULL);
+ file_write(buffer->buf(), buffer->length(), f);
+ file_close(f);
+ BeginExecution(isolate);
+}
+
+
+IsolateProfilerData::IsolateProfilerData(SampleBuffer* sample_buffer,
+ bool own_sample_buffer) {
sample_buffer_ = sample_buffer;
- timer_expiration_micros_ = kNoExpirationTime;
- last_sampled_micros_ = 0;
- thread_id_ = 0;
+ own_sample_buffer_ = own_sample_buffer;
}
IsolateProfilerData::~IsolateProfilerData() {
-}
-
-
-void IsolateProfilerData::SampledAt(int64_t current_time) {
- last_sampled_micros_ = current_time;
-}
-
-
-void IsolateProfilerData::Scheduled(int64_t current_time, ThreadId thread_id) {
- timer_expiration_micros_ = current_time + sample_interval_micros_;
- thread_id_ = thread_id;
- Thread::GetThreadCpuUsage(thread_id_, &cpu_usage_);
-}
-
-
-void IsolateProfilerData::Descheduled() {
- // TODO(johnmccutchan): Track when we ran for a fraction of our sample
- // interval and incorporate the time difference when scheduling the
- // isolate again.
- cpu_usage_ = kDescheduledCpuUsage;
- timer_expiration_micros_ = kNoExpirationTime;
- Sample* sample = sample_buffer_->ReserveSample();
- ASSERT(sample != NULL);
- sample->timestamp = OS::GetCurrentTimeMicros();
- sample->cpu_usage = 0;
- sample->vm_tags = Sample::kIdle;
+ if (own_sample_buffer_) {
+ delete sample_buffer_;
+ sample_buffer_ = NULL;
+ own_sample_buffer_ = false;
+ }
}
const char* Sample::kLookupSymbol = "Symbol Not Looked Up";
const char* Sample::kNoSymbol = "No Symbol Found";
+const char* Sample::kNoFrame = "<no frame>";
-Sample::Sample() {
- timestamp = 0;
- cpu_usage = 0;
- for (int i = 0; i < kNumStackFrames; i++) {
+void Sample::Init(SampleType type, Isolate* isolate, int64_t timestamp,
+ ThreadId tid) {
+ this->timestamp = timestamp;
+ this->tid = tid;
+ this->isolate = isolate;
+ for (intptr_t i = 0; i < kNumStackFrames; i++) {
pcs[i] = 0;
}
- vm_tags = kIdle;
+ this->type = type;
+ vm_tags = 0;
runtime_tags = 0;
}
-
SampleBuffer::SampleBuffer(intptr_t capacity) {
- start_ = 0;
- end_ = 0;
capacity_ = capacity;
samples_ = reinterpret_cast<Sample*>(calloc(capacity, sizeof(Sample)));
+ cursor_ = 0;
}
@@ -587,8 +452,7 @@
if (samples_ != NULL) {
free(samples_);
samples_ = NULL;
- start_ = 0;
- end_ = 0;
+ cursor_ = 0;
capacity_ = 0;
}
}
@@ -596,40 +460,10 @@
Sample* SampleBuffer::ReserveSample() {
ASSERT(samples_ != NULL);
- intptr_t index = end_;
- end_ = WrapIncrement(end_);
- if (end_ == start_) {
- start_ = WrapIncrement(start_);
- }
- ASSERT(index >= 0);
- ASSERT(index < capacity_);
- // Reset.
- samples_[index] = Sample();
- return &samples_[index];
-}
-
-
-Sample* SampleBuffer::FirstSample() const {
- return &samples_[start_];
-}
-
-
-Sample* SampleBuffer::NextSample(Sample* sample) const {
- ASSERT(sample >= &samples_[0]);
- ASSERT(sample < &samples_[capacity_]);
- intptr_t index = sample - samples_;
- index = WrapIncrement(index);
- return &samples_[index];
-}
-
-
-Sample* SampleBuffer::LastSample() const {
- return &samples_[end_];
-}
-
-
-intptr_t SampleBuffer::WrapIncrement(intptr_t i) const {
- return (i + 1) % capacity_;
+ uintptr_t cursor = AtomicOperations::FetchAndIncrement(&cursor_);
+ // Map back into sample buffer range.
+ cursor = cursor % capacity_;
+ return &samples_[cursor];
}
@@ -651,10 +485,22 @@
int ProfilerSampleStackWalker::walk() {
+ const intptr_t kMaxStep = 0x1000; // 4K.
uword* pc = reinterpret_cast<uword*>(original_pc_);
+#define WALK_STACK
#if defined(WALK_STACK)
uword* fp = reinterpret_cast<uword*>(original_fp_);
uword* previous_fp = fp;
+ if (original_sp_ > original_fp_) {
+ // Stack pointer should not be above frame pointer.
+ return 0;
+ }
+ intptr_t gap = original_fp_ - original_sp_;
+ if (gap >= kMaxStep) {
+ // Gap between frame pointer and stack pointer is
+ // too large.
+ return 0;
+ }
if (original_sp_ < lower_bound_) {
// The stack pointer gives us a better lower bound than
// the isolates stack limit.
@@ -669,8 +515,11 @@
pc = CallerPC(fp);
previous_fp = fp;
fp = CallerFP(fp);
- if ((fp <= previous_fp) || !ValidFramePointer(fp)) {
- // Frame pointers should only move to higher addresses.
+ intptr_t step = fp - previous_fp;
+ if ((step >= kMaxStep) || (fp <= previous_fp) || !ValidFramePointer(fp)) {
+ // Frame pointer step is too large.
+ // Frame pointer did not move to a higher address.
+ // Frame pointer is outside of isolate stack bounds.
break;
}
// Move the lower bound up.
diff --git a/runtime/vm/profiler.h b/runtime/vm/profiler.h
index bec51e6..1e0ab73 100644
--- a/runtime/vm/profiler.h
+++ b/runtime/vm/profiler.h
@@ -5,110 +5,62 @@
#ifndef VM_PROFILER_H_
#define VM_PROFILER_H_
-#include "platform/hashmap.h"
-#include "platform/thread.h"
#include "vm/allocation.h"
#include "vm/code_observers.h"
#include "vm/globals.h"
+#include "vm/thread.h"
+#include "vm/thread_interrupter.h"
namespace dart {
// Forward declarations.
+class JSONArray;
class JSONStream;
+struct Sample;
-// Profiler manager.
-class ProfilerManager : public AllStatic {
+// Profiler
+class Profiler : public AllStatic {
public:
static void InitOnce();
static void Shutdown();
- static void SetupIsolateForProfiling(Isolate* isolate);
- static void ShutdownIsolateForProfiling(Isolate* isolate);
- static void ScheduleIsolate(Isolate* isolate, bool inside_signal = false);
- static void DescheduleIsolate(Isolate* isolate);
+ static void InitProfilingForIsolate(Isolate* isolate,
+ bool shared_buffer = false);
+ static void ShutdownProfilingForIsolate(Isolate* isolate);
+
+ static void BeginExecution(Isolate* isolate);
+ static void EndExecution(Isolate* isolate);
static void PrintToJSONStream(Isolate* isolate, JSONStream* stream);
- static void WriteTracing(Isolate* isolate, const char* name, Dart_Port port);
+ static void WriteTracing(Isolate* isolate);
+
+ static SampleBuffer* sample_buffer() {
+ return sample_buffer_;
+ }
private:
- static const intptr_t kMaxProfiledIsolates = 4096;
static bool initialized_;
- static bool shutdown_;
- static bool thread_running_;
static Monitor* monitor_;
- static Monitor* start_stop_monitor_;
- static Isolate** isolates_;
- static intptr_t isolates_capacity_;
- static intptr_t isolates_size_;
+ static void WriteTracingSample(Isolate* isolate, intptr_t pid,
+ Sample* sample, JSONArray& events);
- static void ScheduleIsolateHelper(Isolate* isolate);
- static void ResizeIsolates(intptr_t new_capacity);
- static void AddIsolate(Isolate* isolate);
- static intptr_t FindIsolate(Isolate* isolate);
- static void RemoveIsolate(intptr_t i);
+ static void RecordTickInterruptCallback(const InterruptedThreadState& state,
+ void* data);
- // Returns the microseconds until the next live timer fires.
- static int64_t SampleAndRescheduleIsolates(int64_t current_time);
- static void FreeIsolateProfilingData(Isolate* isolate);
- static void ThreadMain(uword parameters);
+ static void RecordSampleInterruptCallback(const InterruptedThreadState& state,
+ void* data);
+
+ static SampleBuffer* sample_buffer_;
};
class IsolateProfilerData {
public:
- static const int64_t kDescheduledCpuUsage = -1;
- static const int64_t kNoExpirationTime = -2;
-
- IsolateProfilerData(Isolate* isolate, SampleBuffer* sample_buffer);
+ IsolateProfilerData(SampleBuffer* sample_buffer, bool own_sample_buffer);
~IsolateProfilerData();
- int64_t sample_interval_micros() const { return sample_interval_micros_; }
-
- void set_sample_interval_micros(int64_t sample_interval) {
- sample_interval_micros_ = sample_interval;
- }
-
- bool CanExpire() const {
- return timer_expiration_micros_ != kNoExpirationTime;
- }
-
- bool ShouldSample(int64_t current_time) const {
- return CanExpire() && TimeUntilExpiration(current_time) <= 0;
- }
-
- int64_t TimeUntilExpiration(int64_t current_time_micros) const {
- ASSERT(CanExpire());
- return timer_expiration_micros_ - current_time_micros;
- }
-
- void set_cpu_usage(int64_t cpu_usage) {
- cpu_usage_ = cpu_usage;
- }
-
- void SampledAt(int64_t current_time);
-
- void Scheduled(int64_t current_time, ThreadId thread);
-
- void Descheduled();
-
- int64_t cpu_usage() const { return cpu_usage_; }
-
- int64_t ComputeDeltaAndSetCpuUsage(int64_t cpu_usage) {
- int64_t delta = 0;
- if (cpu_usage_ != kDescheduledCpuUsage) {
- // Only compute the real delta if we are being sampled regularly.
- delta = cpu_usage - cpu_usage_;
- }
- set_cpu_usage(cpu_usage);
- return delta;
- }
-
- ThreadId thread_id() const { return thread_id_; }
-
- Isolate* isolate() const { return isolate_; }
-
SampleBuffer* sample_buffer() const { return sample_buffer_; }
void set_sample_buffer(SampleBuffer* sample_buffer) {
@@ -116,13 +68,8 @@
}
private:
- int64_t last_sampled_micros_;
- int64_t timer_expiration_micros_;
- int64_t sample_interval_micros_;
- int64_t cpu_usage_;
- ThreadId thread_id_;
- Isolate* isolate_;
SampleBuffer* sample_buffer_;
+ bool own_sample_buffer_;
DISALLOW_COPY_AND_ASSIGN(IsolateProfilerData);
};
@@ -131,22 +78,26 @@
struct Sample {
static const char* kLookupSymbol;
static const char* kNoSymbol;
- static const intptr_t kNumStackFrames = 4;
- enum SampleState {
- kIdle = 0,
- kExecuting = 1,
- kNumSampleStates
+ static const char* kNoFrame;
+ static const intptr_t kNumStackFrames = 6;
+ enum SampleType {
+ kIsolateStart,
+ kIsolateStop,
+ kIsolateSample,
};
int64_t timestamp;
- int64_t cpu_usage;
+ ThreadId tid;
+ Isolate* isolate;
uintptr_t pcs[kNumStackFrames];
+ SampleType type;
uint16_t vm_tags;
uint16_t runtime_tags;
- Sample();
+
+ void Init(SampleType type, Isolate* isolate, int64_t timestamp, ThreadId tid);
};
-// Ring buffer of samples. One per isolate.
+// Ring buffer of samples.
class SampleBuffer {
public:
static const intptr_t kDefaultBufferCapacity = 120000; // 2 minutes @ 1000hz.
@@ -158,16 +109,17 @@
Sample* ReserveSample();
- Sample* FirstSample() const;
- Sample* NextSample(Sample* sample) const;
- Sample* LastSample() const;
+ Sample* GetSample(intptr_t i) const {
+ ASSERT(i >= 0);
+ ASSERT(i < capacity_);
+ return &samples_[i];
+ }
+
private:
Sample* samples_;
intptr_t capacity_;
- intptr_t start_;
- intptr_t end_;
+ uintptr_t cursor_;
- intptr_t WrapIncrement(intptr_t i) const;
DISALLOW_COPY_AND_ASSIGN(SampleBuffer);
};
diff --git a/runtime/vm/profiler_android.cc b/runtime/vm/profiler_android.cc
deleted file mode 100644
index f1d5704..0000000
--- a/runtime/vm/profiler_android.cc
+++ /dev/null
@@ -1,129 +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.
-
-#include "platform/globals.h"
-#if defined(TARGET_OS_ANDROID)
-
-#include "vm/isolate.h"
-#include "vm/json_stream.h"
-#include "vm/profiler.h"
-#include "vm/signal_handler.h"
-
-namespace dart {
-
-DECLARE_FLAG(bool, profile);
-DECLARE_FLAG(bool, trace_profiled_isolates);
-
-static void ProfileSignalAction(int signal, siginfo_t* info, void* context_) {
- if (signal != SIGPROF) {
- return;
- }
- Isolate* isolate = Isolate::Current();
- if (isolate == NULL) {
- return;
- }
- // Thread owns no profiler locks at this point.
- {
- // Thread owns isolate profiler data mutex.
- ScopedMutex profiler_data_lock(isolate->profiler_data_mutex());
- IsolateProfilerData* profiler_data = isolate->profiler_data();
- if ((profiler_data == NULL) || !profiler_data->CanExpire() ||
- (profiler_data->sample_buffer() == NULL)) {
- // Descheduled.
- return;
- }
- if (profiler_data->thread_id() == Thread::GetCurrentThreadId()) {
- // Still scheduled on this thread.
- // TODO(johnmccutchan): Perform sample on Android.
- }
- }
- // Thread owns no profiler locks at this point.
- // This call will acquire both ProfilerManager::monitor and the
- // isolate's profiler data mutex.
- ProfilerManager::ScheduleIsolate(isolate, true);
-}
-
-
-int64_t ProfilerManager::SampleAndRescheduleIsolates(int64_t current_time) {
- if (isolates_size_ == 0) {
- return 0;
- }
- static const int64_t max_time = 0x7fffffffffffffffLL;
- int64_t lowest = max_time;
- intptr_t i = 0;
- while (i < isolates_size_) {
- Isolate* isolate = isolates_[i];
- ScopedMutex isolate_lock(isolate->profiler_data_mutex());
- IsolateProfilerData* profiler_data = isolate->profiler_data();
- if (profiler_data == NULL) {
- // Isolate has been shutdown for profiling.
- RemoveIsolate(i);
- // Remove moves the last element into i, do not increment i.
- continue;
- }
- ASSERT(profiler_data != NULL);
- if (profiler_data->ShouldSample(current_time)) {
- pthread_kill(profiler_data->thread_id(), SIGPROF);
- RemoveIsolate(i);
- // Remove moves the last element into i, do not increment i.
- continue;
- }
- if (profiler_data->CanExpire()) {
- int64_t isolate_time_left =
- profiler_data->TimeUntilExpiration(current_time);
- if (isolate_time_left < 0) {
- continue;
- }
- if (isolate_time_left < lowest) {
- lowest = isolate_time_left;
- }
- }
- i++;
- }
- if (isolates_size_ == 0) {
- return 0;
- }
- if (lowest == max_time) {
- return 0;
- }
- ASSERT(lowest != max_time);
- ASSERT(lowest > 0);
- return lowest;
-}
-
-
-void ProfilerManager::ThreadMain(uword parameters) {
- ASSERT(initialized_);
- ASSERT(FLAG_profile);
- SignalHandler::Install(ProfileSignalAction);
- if (FLAG_trace_profiled_isolates) {
- OS::Print("ProfilerManager Android ready.\n");
- }
- {
- // Signal to main thread we are ready.
- ScopedMonitor startup_lock(start_stop_monitor_);
- thread_running_ = true;
- startup_lock.Notify();
- }
- ScopedMonitor lock(monitor_);
- while (!shutdown_) {
- int64_t current_time = OS::GetCurrentTimeMicros();
- int64_t next_sample = SampleAndRescheduleIsolates(current_time);
- lock.WaitMicros(next_sample);
- }
- if (FLAG_trace_profiled_isolates) {
- OS::Print("ProfilerManager Android exiting.\n");
- }
- {
- // Signal to main thread we are exiting.
- ScopedMonitor shutdown_lock(start_stop_monitor_);
- thread_running_ = false;
- shutdown_lock.Notify();
- }
-}
-
-
-} // namespace dart
-
-#endif // defined(TARGET_OS_ANDROID)
diff --git a/runtime/vm/profiler_linux.cc b/runtime/vm/profiler_linux.cc
deleted file mode 100644
index 6489a43..0000000
--- a/runtime/vm/profiler_linux.cc
+++ /dev/null
@@ -1,162 +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.
-
-#include "platform/globals.h"
-#if defined(TARGET_OS_LINUX)
-
-#include "vm/isolate.h"
-#include "vm/json_stream.h"
-#include "vm/profiler.h"
-#include "vm/signal_handler.h"
-
-namespace dart {
-
-DECLARE_FLAG(bool, profile);
-DECLARE_FLAG(bool, trace_profiled_isolates);
-
-static void CollectSample(IsolateProfilerData* profiler_data,
- uintptr_t pc,
- uintptr_t fp,
- uintptr_t sp,
- uintptr_t stack_lower,
- uintptr_t stack_upper) {
- SampleBuffer* sample_buffer = profiler_data->sample_buffer();
- Sample* sample = sample_buffer->ReserveSample();
- ASSERT(sample != NULL);
- sample->timestamp = OS::GetCurrentTimeMicros();
- // TODO(johnmccutchan): Make real use of vm_tags and runtime_tags.
- // Issue # 14777
- sample->vm_tags = Sample::kExecuting;
- sample->runtime_tags = 0;
- int64_t cpu_usage;
- Thread::GetThreadCpuUsage(profiler_data->thread_id(), &cpu_usage);
- sample->cpu_usage = profiler_data->ComputeDeltaAndSetCpuUsage(cpu_usage);
- ProfilerSampleStackWalker stackWalker(sample, stack_lower, stack_upper,
- pc, fp, sp);
- stackWalker.walk();
-}
-
-
-static void ProfileSignalAction(int signal, siginfo_t* info, void* context_) {
- if (signal != SIGPROF) {
- return;
- }
- ucontext_t* context = reinterpret_cast<ucontext_t*>(context_);
- mcontext_t mcontext = context->uc_mcontext;
- Isolate* isolate = Isolate::Current();
- if (isolate == NULL) {
- return;
- }
- // Thread owns no profiler locks at this point.
- {
- // Thread owns isolate profiler data mutex.
- ScopedMutex profiler_data_lock(isolate->profiler_data_mutex());
- IsolateProfilerData* profiler_data = isolate->profiler_data();
- if ((profiler_data == NULL) || !profiler_data->CanExpire() ||
- (profiler_data->sample_buffer() == NULL)) {
- // Descheduled.
- return;
- }
- if (profiler_data->thread_id() == Thread::GetCurrentThreadId()) {
- // Still scheduled on this thread.
- uintptr_t stack_lower = 0;
- uintptr_t stack_upper = 0;
- isolate->GetStackBounds(&stack_lower, &stack_upper);
- uintptr_t PC = SignalHandler::GetProgramCounter(mcontext);
- uintptr_t FP = SignalHandler::GetFramePointer(mcontext);
- uintptr_t SP = SignalHandler::GetStackPointer(mcontext);
- int64_t sample_time = OS::GetCurrentTimeMicros();
- profiler_data->SampledAt(sample_time);
- CollectSample(profiler_data, PC, FP, SP, stack_lower, stack_upper);
- }
- }
- // Thread owns no profiler locks at this point.
- // This call will acquire both ProfilerManager::monitor and the
- // isolate's profiler data mutex.
- ProfilerManager::ScheduleIsolate(isolate, true);
-}
-
-
-int64_t ProfilerManager::SampleAndRescheduleIsolates(int64_t current_time) {
- if (isolates_size_ == 0) {
- return 0;
- }
- static const int64_t max_time = 0x7fffffffffffffffLL;
- int64_t lowest = max_time;
- intptr_t i = 0;
- while (i < isolates_size_) {
- Isolate* isolate = isolates_[i];
- ScopedMutex isolate_lock(isolate->profiler_data_mutex());
- IsolateProfilerData* profiler_data = isolate->profiler_data();
- if (profiler_data == NULL) {
- // Isolate has been shutdown for profiling.
- RemoveIsolate(i);
- // Remove moves the last element into i, do not increment i.
- continue;
- }
- ASSERT(profiler_data != NULL);
- if (profiler_data->ShouldSample(current_time)) {
- pthread_kill(profiler_data->thread_id(), SIGPROF);
- RemoveIsolate(i);
- // Remove moves the last element into i, do not increment i.
- continue;
- }
- if (profiler_data->CanExpire()) {
- int64_t isolate_time_left =
- profiler_data->TimeUntilExpiration(current_time);
- if (isolate_time_left < 0) {
- continue;
- }
- if (isolate_time_left < lowest) {
- lowest = isolate_time_left;
- }
- }
- i++;
- }
- if (isolates_size_ == 0) {
- return 0;
- }
- if (lowest == max_time) {
- return 0;
- }
- ASSERT(lowest != max_time);
- ASSERT(lowest > 0);
- return lowest;
-}
-
-
-void ProfilerManager::ThreadMain(uword parameters) {
- ASSERT(initialized_);
- ASSERT(FLAG_profile);
- SignalHandler::Install(ProfileSignalAction);
- if (FLAG_trace_profiled_isolates) {
- OS::Print("ProfilerManager Linux ready.\n");
- }
- {
- // Signal to main thread we are ready.
- ScopedMonitor startup_lock(start_stop_monitor_);
- thread_running_ = true;
- startup_lock.Notify();
- }
- ScopedMonitor lock(monitor_);
- while (!shutdown_) {
- int64_t current_time = OS::GetCurrentTimeMicros();
- int64_t next_sample = SampleAndRescheduleIsolates(current_time);
- lock.WaitMicros(next_sample);
- }
- if (FLAG_trace_profiled_isolates) {
- OS::Print("ProfilerManager Linux exiting.\n");
- }
- {
- // Signal to main thread we are exiting.
- ScopedMonitor shutdown_lock(start_stop_monitor_);
- thread_running_ = false;
- shutdown_lock.Notify();
- }
-}
-
-
-} // namespace dart
-
-#endif // defined(TARGET_OS_LINUX)
diff --git a/runtime/vm/profiler_macos.cc b/runtime/vm/profiler_macos.cc
deleted file mode 100644
index e1ae399..0000000
--- a/runtime/vm/profiler_macos.cc
+++ /dev/null
@@ -1,162 +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.
-
-#include "platform/globals.h"
-#if defined(TARGET_OS_MACOS)
-
-#include "vm/isolate.h"
-#include "vm/json_stream.h"
-#include "vm/profiler.h"
-#include "vm/signal_handler.h"
-
-namespace dart {
-
-DECLARE_FLAG(bool, profile);
-DECLARE_FLAG(bool, trace_profiled_isolates);
-
-static void CollectSample(IsolateProfilerData* profiler_data,
- uintptr_t pc,
- uintptr_t fp,
- uintptr_t sp,
- uintptr_t stack_lower,
- uintptr_t stack_upper) {
- SampleBuffer* sample_buffer = profiler_data->sample_buffer();
- Sample* sample = sample_buffer->ReserveSample();
- ASSERT(sample != NULL);
- sample->timestamp = OS::GetCurrentTimeMicros();
- // TODO(johnmccutchan): Make real use of vm_tags and runtime_tags.
- // Issue # 14777
- sample->vm_tags = Sample::kExecuting;
- sample->runtime_tags = 0;
- int64_t cpu_usage = 0;
- Thread::GetThreadCpuUsage(profiler_data->thread_id(), &cpu_usage);
- sample->cpu_usage = profiler_data->ComputeDeltaAndSetCpuUsage(cpu_usage);
- ProfilerSampleStackWalker stackWalker(sample, stack_lower, stack_upper,
- pc, fp, sp);
- stackWalker.walk();
-}
-
-
-static void ProfileSignalAction(int signal, siginfo_t* info, void* context_) {
- if (signal != SIGPROF) {
- return;
- }
- ucontext_t* context = reinterpret_cast<ucontext_t*>(context_);
- mcontext_t mcontext = context->uc_mcontext;
- Isolate* isolate = Isolate::Current();
- if (isolate == NULL) {
- return;
- }
- // Thread owns no profiler locks at this point.
- {
- // Thread owns isolate profiler data mutex.
- ScopedMutex profiler_data_lock(isolate->profiler_data_mutex());
- IsolateProfilerData* profiler_data = isolate->profiler_data();
- if ((profiler_data == NULL) || !profiler_data->CanExpire() ||
- (profiler_data->sample_buffer() == NULL)) {
- // Descheduled.
- return;
- }
- if (profiler_data->thread_id() == Thread::GetCurrentThreadId()) {
- // Still scheduled on this thread.
- uintptr_t stack_lower = 0;
- uintptr_t stack_upper = 0;
- isolate->GetStackBounds(&stack_lower, &stack_upper);
- uintptr_t PC = SignalHandler::GetProgramCounter(mcontext);
- uintptr_t FP = SignalHandler::GetFramePointer(mcontext);
- uintptr_t SP = SignalHandler::GetStackPointer(mcontext);
- int64_t sample_time = OS::GetCurrentTimeMicros();
- profiler_data->SampledAt(sample_time);
- CollectSample(profiler_data, PC, FP, SP, stack_lower, stack_upper);
- }
- }
- // Thread owns no profiler locks at this point.
- // This call will acquire both ProfilerManager::monitor and the
- // isolate's profiler data mutex.
- ProfilerManager::ScheduleIsolate(isolate, true);
-}
-
-
-int64_t ProfilerManager::SampleAndRescheduleIsolates(int64_t current_time) {
- if (isolates_size_ == 0) {
- return 0;
- }
- static const int64_t max_time = 0x7fffffffffffffffLL;
- int64_t lowest = max_time;
- intptr_t i = 0;
- while (i < isolates_size_) {
- Isolate* isolate = isolates_[i];
- ScopedMutex isolate_lock(isolate->profiler_data_mutex());
- IsolateProfilerData* profiler_data = isolate->profiler_data();
- if (profiler_data == NULL) {
- // Isolate has been shutdown for profiling.
- RemoveIsolate(i);
- // Remove moves the last element into i, do not increment i.
- continue;
- }
- ASSERT(profiler_data != NULL);
- if (profiler_data->ShouldSample(current_time)) {
- pthread_kill(profiler_data->thread_id(), SIGPROF);
- RemoveIsolate(i);
- // Remove moves the last element into i, do not increment i.
- continue;
- }
- if (profiler_data->CanExpire()) {
- int64_t isolate_time_left =
- profiler_data->TimeUntilExpiration(current_time);
- if (isolate_time_left < 0) {
- continue;
- }
- if (isolate_time_left < lowest) {
- lowest = isolate_time_left;
- }
- }
- i++;
- }
- if (isolates_size_ == 0) {
- return 0;
- }
- if (lowest == max_time) {
- return 0;
- }
- ASSERT(lowest != max_time);
- ASSERT(lowest > 0);
- return lowest;
-}
-
-
-void ProfilerManager::ThreadMain(uword parameters) {
- ASSERT(initialized_);
- ASSERT(FLAG_profile);
- SignalHandler::Install(ProfileSignalAction);
- if (FLAG_trace_profiled_isolates) {
- OS::Print("ProfilerManager MacOS ready.\n");
- }
- {
- // Signal to main thread we are ready.
- ScopedMonitor startup_lock(start_stop_monitor_);
- thread_running_ = true;
- startup_lock.Notify();
- }
- ScopedMonitor lock(monitor_);
- while (!shutdown_) {
- int64_t current_time = OS::GetCurrentTimeMicros();
- int64_t next_sample = SampleAndRescheduleIsolates(current_time);
- lock.WaitMicros(next_sample);
- }
- if (FLAG_trace_profiled_isolates) {
- OS::Print("ProfilerManager MacOS exiting.\n");
- }
- {
- // Signal to main thread we are exiting.
- ScopedMonitor shutdown_lock(start_stop_monitor_);
- thread_running_ = false;
- shutdown_lock.Notify();
- }
-}
-
-
-} // namespace dart
-
-#endif // defined(TARGET_OS_MACOS)
diff --git a/runtime/vm/profiler_test.cc b/runtime/vm/profiler_test.cc
index a974b85..610fa41 100644
--- a/runtime/vm/profiler_test.cc
+++ b/runtime/vm/profiler_test.cc
@@ -14,23 +14,29 @@
class ProfileSampleBufferTestHelper {
public:
- static intptr_t IterateCount(const SampleBuffer& sample_buffer) {
+ static intptr_t IterateCount(const Isolate* isolate,
+ const SampleBuffer& sample_buffer) {
intptr_t c = 0;
- for (Sample* i = sample_buffer.FirstSample();
- i != sample_buffer.LastSample();
- i = sample_buffer.NextSample(i)) {
+ for (intptr_t i = 0; i < sample_buffer.capacity(); i++) {
+ Sample* sample = sample_buffer.GetSample(i);
+ if (sample->isolate != isolate) {
+ continue;
+ }
c++;
}
return c;
}
- static intptr_t IterateSumPC(const SampleBuffer& sample_buffer) {
+ static intptr_t IterateSumPC(const Isolate* isolate,
+ const SampleBuffer& sample_buffer) {
intptr_t c = 0;
- for (Sample* i = sample_buffer.FirstSample();
- i != sample_buffer.LastSample();
- i = sample_buffer.NextSample(i)) {
- c += i->pcs[0];
+ for (intptr_t i = 0; i < sample_buffer.capacity(); i++) {
+ Sample* sample = sample_buffer.GetSample(i);
+ if (sample->isolate != isolate) {
+ continue;
+ }
+ c += sample->pcs[0];
}
return c;
}
@@ -39,35 +45,46 @@
TEST_CASE(ProfilerSampleBufferWrapTest) {
SampleBuffer* sample_buffer = new SampleBuffer(3);
- EXPECT_EQ(0, ProfileSampleBufferTestHelper::IterateSumPC(*sample_buffer));
+ Isolate* i = reinterpret_cast<Isolate*>(0x1);
+ EXPECT_EQ(0, ProfileSampleBufferTestHelper::IterateSumPC(i, *sample_buffer));
Sample* s;
s = sample_buffer->ReserveSample();
+ s->isolate = i;
s->pcs[0] = 2;
- EXPECT_EQ(2, ProfileSampleBufferTestHelper::IterateSumPC(*sample_buffer));
+ EXPECT_EQ(2, ProfileSampleBufferTestHelper::IterateSumPC(i, *sample_buffer));
s = sample_buffer->ReserveSample();
+ s->isolate = i;
s->pcs[0] = 4;
- EXPECT_EQ(6, ProfileSampleBufferTestHelper::IterateSumPC(*sample_buffer));
+ EXPECT_EQ(6, ProfileSampleBufferTestHelper::IterateSumPC(i, *sample_buffer));
s = sample_buffer->ReserveSample();
+ s->isolate = i;
s->pcs[0] = 6;
- EXPECT_EQ(10, ProfileSampleBufferTestHelper::IterateSumPC(*sample_buffer));
+ EXPECT_EQ(12, ProfileSampleBufferTestHelper::IterateSumPC(i, *sample_buffer));
s = sample_buffer->ReserveSample();
+ s->isolate = i;
s->pcs[0] = 8;
- EXPECT_EQ(14, ProfileSampleBufferTestHelper::IterateSumPC(*sample_buffer));
+ EXPECT_EQ(18, ProfileSampleBufferTestHelper::IterateSumPC(i, *sample_buffer));
delete sample_buffer;
}
TEST_CASE(ProfilerSampleBufferIterateTest) {
SampleBuffer* sample_buffer = new SampleBuffer(3);
- EXPECT_EQ(0, ProfileSampleBufferTestHelper::IterateCount(*sample_buffer));
- sample_buffer->ReserveSample();
- EXPECT_EQ(1, ProfileSampleBufferTestHelper::IterateCount(*sample_buffer));
- sample_buffer->ReserveSample();
- EXPECT_EQ(2, ProfileSampleBufferTestHelper::IterateCount(*sample_buffer));
- sample_buffer->ReserveSample();
- EXPECT_EQ(2, ProfileSampleBufferTestHelper::IterateCount(*sample_buffer));
- sample_buffer->ReserveSample();
- EXPECT_EQ(2, ProfileSampleBufferTestHelper::IterateCount(*sample_buffer));
+ Isolate* i = reinterpret_cast<Isolate*>(0x1);
+ EXPECT_EQ(0, ProfileSampleBufferTestHelper::IterateCount(i, *sample_buffer));
+ Sample* s;
+ s = sample_buffer->ReserveSample();
+ s->isolate = i;
+ EXPECT_EQ(1, ProfileSampleBufferTestHelper::IterateCount(i, *sample_buffer));
+ s = sample_buffer->ReserveSample();
+ s->isolate = i;
+ EXPECT_EQ(2, ProfileSampleBufferTestHelper::IterateCount(i, *sample_buffer));
+ s = sample_buffer->ReserveSample();
+ s->isolate = i;
+ EXPECT_EQ(3, ProfileSampleBufferTestHelper::IterateCount(i, *sample_buffer));
+ s = sample_buffer->ReserveSample();
+ s->isolate = i;
+ EXPECT_EQ(3, ProfileSampleBufferTestHelper::IterateCount(i, *sample_buffer));
delete sample_buffer;
}
diff --git a/runtime/vm/profiler_win.cc b/runtime/vm/profiler_win.cc
deleted file mode 100644
index 3bc9e41..0000000
--- a/runtime/vm/profiler_win.cc
+++ /dev/null
@@ -1,170 +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.
-
-#include "platform/globals.h"
-#if defined(TARGET_OS_WINDOWS)
-
-#include "vm/isolate.h"
-#include "vm/profiler.h"
-
-namespace dart {
-
-#define kThreadError -1
-
-DECLARE_FLAG(bool, profile);
-DECLARE_FLAG(bool, trace_profiled_isolates);
-
-static void CollectSample(IsolateProfilerData* profiler_data,
- uintptr_t pc,
- uintptr_t fp,
- uintptr_t stack_lower,
- uintptr_t stack_upper) {
- uintptr_t sp = stack_lower;
- ASSERT(profiler_data != NULL);
- SampleBuffer* sample_buffer = profiler_data->sample_buffer();
- ASSERT(sample_buffer != NULL);
- Sample* sample = sample_buffer->ReserveSample();
- ASSERT(sample != NULL);
- sample->timestamp = OS::GetCurrentTimeMicros();
- // TODO(johnmccutchan): Make real use of vm_tags and runtime_tags.
- // Issue # 14777
- sample->vm_tags = Sample::kExecuting;
- sample->runtime_tags = 0;
- int64_t cpu_usage;
- Thread::GetThreadCpuUsage(profiler_data->thread_id(), &cpu_usage);
- sample->cpu_usage = profiler_data->ComputeDeltaAndSetCpuUsage(cpu_usage);
- ProfilerSampleStackWalker stackWalker(sample, stack_lower, stack_upper,
- pc, fp, sp);
- stackWalker.walk();
-}
-
-
-static bool GrabRegisters(ThreadId thread, uintptr_t* pc, uintptr_t* fp,
- uintptr_t* sp) {
- CONTEXT context;
- memset(&context, 0, sizeof(context));
- context.ContextFlags = CONTEXT_FULL;
- if (GetThreadContext(thread, &context) != 0) {
-#if defined(TARGET_ARCH_IA32)
- *pc = static_cast<uintptr_t>(context.Eip);
- *fp = static_cast<uintptr_t>(context.Ebp);
- *sp = static_cast<uintptr_t>(context.Esp);
-#elif defined(TARGET_ARCH_X64)
- *pc = reinterpret_cast<uintptr_t>(context.Rip);
- *fp = reinterpret_cast<uintptr_t>(context.Rbp);
- *sp = reinterpret_cast<uintptr_t>(context.Rsp);
-#else
- UNIMPLEMENTED();
-#endif
- return true;
- }
- return false;
-}
-
-
-static void SuspendAndSample(Isolate* isolate,
- IsolateProfilerData* profiler_data) {
- ASSERT(GetCurrentThread() != profiler_data->thread_id());
- DWORD result = SuspendThread(profiler_data->thread_id());
- if (result == kThreadError) {
- return;
- }
- uintptr_t PC;
- uintptr_t FP;
- uintptr_t stack_lower;
- uintptr_t stack_upper;
- bool r = isolate->GetStackBounds(&stack_lower, &stack_upper);
- if (r) {
- r = GrabRegisters(profiler_data->thread_id(), &PC, &FP, &stack_lower);
- if (r) {
- int64_t sample_time = OS::GetCurrentTimeMicros();
- profiler_data->SampledAt(sample_time);
- CollectSample(profiler_data, PC, FP, stack_lower, stack_upper);
- }
- }
-
- ResumeThread(profiler_data->thread_id());
-}
-
-
-static void Reschedule(IsolateProfilerData* profiler_data) {
- profiler_data->Scheduled(OS::GetCurrentTimeMicros(),
- profiler_data->thread_id());
-}
-
-
-int64_t ProfilerManager::SampleAndRescheduleIsolates(int64_t current_time) {
- if (isolates_size_ == 0) {
- return 0;
- }
- static const int64_t max_time = 0x7fffffffffffffffLL;
- int64_t lowest = max_time;
- for (intptr_t i = 0; i < isolates_size_; i++) {
- Isolate* isolate = isolates_[i];
- ScopedMutex isolate_lock(isolate->profiler_data_mutex());
- IsolateProfilerData* profiler_data = isolate->profiler_data();
- if ((profiler_data == NULL) || !profiler_data->CanExpire() ||
- (profiler_data->sample_buffer() == NULL)) {
- // Descheduled.
- continue;
- }
- if (profiler_data->ShouldSample(current_time)) {
- SuspendAndSample(isolate, profiler_data);
- Reschedule(profiler_data);
- }
- if (profiler_data->CanExpire()) {
- int64_t isolate_time_left =
- profiler_data->TimeUntilExpiration(current_time);
- if (isolate_time_left < 0) {
- continue;
- }
- if (isolate_time_left < lowest) {
- lowest = isolate_time_left;
- }
- }
- }
- if (isolates_size_ == 0) {
- return 0;
- }
- if (lowest == max_time) {
- return 0;
- }
- ASSERT(lowest != max_time);
- ASSERT(lowest > 0);
- return lowest;
-}
-
-
-void ProfilerManager::ThreadMain(uword parameters) {
- ASSERT(initialized_);
- ASSERT(FLAG_profile);
- if (FLAG_trace_profiled_isolates) {
- OS::Print("ProfilerManager Windows ready.\n");
- }
- {
- // Signal to main thread we are ready.
- ScopedMonitor startup_lock(start_stop_monitor_);
- thread_running_ = true;
- startup_lock.Notify();
- }
- ScopedMonitor lock(monitor_);
- while (!shutdown_) {
- int64_t current_time = OS::GetCurrentTimeMicros();
- int64_t next_sample = SampleAndRescheduleIsolates(current_time);
- lock.WaitMicros(next_sample);
- }
- if (FLAG_trace_profiled_isolates) {
- OS::Print("ProfilerManager Windows exiting.\n");
- }
- {
- // Signal to main thread we are exiting.
- ScopedMonitor shutdown_lock(start_stop_monitor_);
- thread_running_ = false;
- shutdown_lock.Notify();
- }
-}
-
-} // namespace dart
-
-#endif // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index b5514df..0ac92dc 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -490,7 +490,8 @@
RawClass* patch_class_;
RawFunction* signature_function_; // Associated function for signature class.
RawArray* constants_; // Canonicalized values of this class.
- RawArray* canonical_types_; // Canonicalized types of this class.
+ RawObject* canonical_types_; // An array of canonicalized types of this class
+ // or the canonical type.
RawArray* invocation_dispatcher_cache_; // Cache for dispatcher functions.
RawCode* allocation_stub_; // Stub code for allocation of instances.
RawObject** to() {
diff --git a/runtime/vm/scavenger.cc b/runtime/vm/scavenger.cc
index dd63408..7458954 100644
--- a/runtime/vm/scavenger.cc
+++ b/runtime/vm/scavenger.cc
@@ -21,6 +21,9 @@
namespace dart {
+ DEFINE_FLAG(int, early_tenuring_threshold, 66, "Skip TO space when promoting"
+ " above this percentage.");
+
// Scavenger uses RawObject::kMarkBit to distinguish forwaded and non-forwarded
// objects. The kMarkBit does not intersect with the target address because of
// object alignment.
@@ -369,10 +372,22 @@
}
-void Scavenger::Epilogue(Isolate* isolate, bool invoke_api_callbacks) {
+void Scavenger::Epilogue(Isolate* isolate,
+ ScavengerVisitor* visitor,
+ bool invoke_api_callbacks) {
// All objects in the to space have been copied from the from space at this
// moment.
- survivor_end_ = top_;
+ int promotion_ratio = static_cast<int>(
+ (static_cast<double>(visitor->bytes_promoted()) /
+ static_cast<double>(to_->size())) * 100.0);
+ if (promotion_ratio < FLAG_early_tenuring_threshold) {
+ // Remember the limit to which objects have been copied.
+ survivor_end_ = top_;
+ } else {
+ // Move survivor end to the end of the to_ space, making all surviving
+ // objects candidates for promotion.
+ survivor_end_ = end_;
+ }
#if defined(DEBUG)
VerifyStoreBufferPointerVisitor verify_store_buffer_visitor(isolate, to_);
@@ -673,7 +688,7 @@
int64_t end = OS::GetCurrentTimeMicros();
heap_->RecordTime(kProcessToSpace, middle - start);
heap_->RecordTime(kIterateWeaks, end - middle);
- Epilogue(isolate, invoke_api_callbacks);
+ Epilogue(isolate, &visitor, invoke_api_callbacks);
if (FLAG_verify_after_gc) {
OS::PrintErr("Verifying after Scavenge...");
diff --git a/runtime/vm/scavenger.h b/runtime/vm/scavenger.h
index d1405ff..249df65 100644
--- a/runtime/vm/scavenger.h
+++ b/runtime/vm/scavenger.h
@@ -119,7 +119,9 @@
void ProcessToSpace(ScavengerVisitor* visitor);
uword ProcessWeakProperty(RawWeakProperty* raw_weak,
ScavengerVisitor* visitor);
- void Epilogue(Isolate* isolate, bool invoke_api_callbacks);
+ void Epilogue(Isolate* isolate,
+ ScavengerVisitor* visitor,
+ bool invoke_api_callbacks);
bool IsUnreachable(RawObject** p);
diff --git a/runtime/vm/service.cc b/runtime/vm/service.cc
index 2b3e633..087c933 100644
--- a/runtime/vm/service.cc
+++ b/runtime/vm/service.cc
@@ -2,6 +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.
+#include "vm/service.h"
+
+#include "vm/cpu.h"
+#include "vm/dart_entry.h"
#include "vm/debugger.h"
#include "vm/heap_histogram.h"
#include "vm/isolate.h"
@@ -10,7 +14,6 @@
#include "vm/object_id_ring.h"
#include "vm/object_store.h"
#include "vm/port.h"
-#include "vm/service.h"
namespace dart {
@@ -30,36 +33,46 @@
}
-static void PostReply(const String& reply, Dart_Port reply_port) {
+static void PostReply(const String& reply, const Instance& reply_port) {
+ const Object& id_obj = Object::Handle(
+ DartLibraryCalls::PortGetId(reply_port));
+ if (id_obj.IsError()) {
+ Exceptions::PropagateError(Error::Cast(id_obj));
+ }
+ const Integer& id = Integer::Cast(id_obj);
+ Dart_Port port = static_cast<Dart_Port>(id.AsInt64Value());
+ ASSERT(port != ILLEGAL_PORT);
+
uint8_t* data = NULL;
MessageWriter writer(&data, &allocator);
writer.WriteMessage(reply);
- PortMap::PostMessage(new Message(reply_port, Message::kIllegalPort, data,
+ PortMap::PostMessage(new Message(port, data,
writer.BytesWritten(),
Message::kNormalPriority));
}
-void Service::HandleServiceMessage(Isolate* isolate, Dart_Port reply_port,
- const Instance& msg) {
+void Service::HandleServiceMessage(Isolate* isolate, const Instance& msg) {
ASSERT(isolate != NULL);
- ASSERT(reply_port != ILLEGAL_PORT);
ASSERT(!msg.IsNull());
ASSERT(msg.IsGrowableObjectArray());
{
StackZone zone(isolate);
HANDLESCOPE(isolate);
+
const GrowableObjectArray& message = GrowableObjectArray::Cast(msg);
// Message is a list with three entries.
- ASSERT(message.Length() == 3);
+ ASSERT(message.Length() == 4);
- GrowableObjectArray& path = GrowableObjectArray::Handle();
- GrowableObjectArray& option_keys = GrowableObjectArray::Handle();
- GrowableObjectArray& option_values = GrowableObjectArray::Handle();
- path ^= message.At(0);
- option_keys ^= message.At(1);
- option_values ^= message.At(2);
+ Instance& reply_port = Instance::Handle(isolate);
+ GrowableObjectArray& path = GrowableObjectArray::Handle(isolate);
+ GrowableObjectArray& option_keys = GrowableObjectArray::Handle(isolate);
+ GrowableObjectArray& option_values = GrowableObjectArray::Handle(isolate);
+ reply_port ^= message.At(0);
+ path ^= message.At(1);
+ option_keys ^= message.At(2);
+ option_values ^= message.At(3);
ASSERT(!path.IsNull());
ASSERT(!option_keys.IsNull());
@@ -140,19 +153,31 @@
}
-static void PrintCollectionErrorResponse(const char* collection_name,
- JSONStream* js) {
+static void PrintGenericError(JSONStream* js) {
JSONObject jsobj(js);
- jsobj.AddProperty("type", "error");
- jsobj.AddPropertyF("text", "Must specify collection object id: /%s/id",
- collection_name);
+ jsobj.AddProperty("type", "Error");
+ jsobj.AddProperty("text", "Invalid request.");
+ PrintArgumentsAndOptions(jsobj, js);
}
-static void PrintGenericError(JSONStream* js) {
+static void PrintError(JSONStream* js, const char* format, ...) {
+ Isolate* isolate = Isolate::Current();
+
+ va_list args;
+ va_start(args, format);
+ intptr_t len = OS::VSNPrint(NULL, 0, format, args);
+ va_end(args);
+
+ char* buffer = isolate->current_zone()->Alloc<char>(len + 1);
+ va_list args2;
+ va_start(args2, format);
+ OS::VSNPrint(buffer, (len + 1), format, args2);
+ va_end(args2);
+
JSONObject jsobj(js);
- jsobj.AddProperty("type", "error");
- jsobj.AddProperty("text", "Invalid request.");
+ jsobj.AddProperty("type", "Error");
+ jsobj.AddProperty("text", buffer);
PrintArgumentsAndOptions(jsobj, js);
}
@@ -191,7 +216,7 @@
ObjectHistogram* histogram = Isolate::Current()->object_histogram();
if (histogram == NULL) {
JSONObject jsobj(js);
- jsobj.AddProperty("type", "error");
+ jsobj.AddProperty("type", "Error");
jsobj.AddProperty("text", "Run with --print_object_histogram");
return;
}
@@ -207,10 +232,10 @@
// Print an error message if there is no ID argument.
-#define REQUIRE_COLLECTION_ID(collection) \
- if (js->num_arguments() == 1) { \
- PrintCollectionErrorResponse(collection, js); \
- return; \
+#define REQUIRE_COLLECTION_ID(collection) \
+ if (js->num_arguments() == 1) { \
+ PrintError(js, "Must specify collection object id: /%s/id", collection); \
+ return; \
}
@@ -254,20 +279,62 @@
}
+static void HandleDebug(Isolate* isolate, JSONStream* js) {
+ if (js->num_arguments() == 1) {
+ PrintError(js, "Must specify a subcommand");
+ return;
+ }
+ const char* command = js->GetArgument(1);
+ if (!strcmp(command, "breakpoints")) {
+ if (js->num_arguments() == 2) {
+ // Print breakpoint list.
+ JSONObject jsobj(js);
+ jsobj.AddProperty("type", "BreakpointList");
+ JSONArray jsarr(&jsobj, "breakpoints");
+ isolate->debugger()->PrintBreakpointsToJSONArray(&jsarr);
+
+ } else if (js->num_arguments() == 3) {
+ // Print individual breakpoint.
+ intptr_t id = atoi(js->GetArgument(2));
+ SourceBreakpoint* bpt = isolate->debugger()->GetBreakpointById(id);
+ if (bpt != NULL) {
+ bpt->PrintToJSONStream(js);
+ } else {
+ PrintError(js, "Unrecognized breakpoint id %s", js->GetArgument(2));
+ }
+
+ } else {
+ PrintError(js, "Command too long");
+ }
+ } else {
+ PrintError(js, "Unrecognized subcommand '%s'", js->GetArgument(1));
+ }
+}
+
+
+static void HandleCpu(Isolate* isolate, JSONStream* js) {
+ JSONObject jsobj(js);
+ jsobj.AddProperty("type", "CPU");
+ jsobj.AddProperty("architecture", CPU::Id());
+}
+
+
static ServiceMessageHandlerEntry __message_handlers[] = {
- { "name", HandleName },
- { "stacktrace", HandleStackTrace },
- { "objecthistogram", HandleObjectHistogram},
- { "library", HandleLibrary },
- { "classes", HandleClasses },
- { "objects", HandleObjects },
{ "_echo", HandleEcho },
+ { "classes", HandleClasses },
+ { "cpu", HandleCpu },
+ { "debug", HandleDebug },
+ { "library", HandleLibrary },
+ { "name", HandleName },
+ { "objecthistogram", HandleObjectHistogram},
+ { "objects", HandleObjects },
+ { "stacktrace", HandleStackTrace },
};
static void HandleFallthrough(Isolate* isolate, JSONStream* js) {
JSONObject jsobj(js);
- jsobj.AddProperty("type", "error");
+ jsobj.AddProperty("type", "Error");
jsobj.AddProperty("text", "request not understood.");
PrintArgumentsAndOptions(jsobj, js);
}
diff --git a/runtime/vm/service.h b/runtime/vm/service.h
index b7a6d40..84b467b 100644
--- a/runtime/vm/service.h
+++ b/runtime/vm/service.h
@@ -7,6 +7,8 @@
#include "include/dart_api.h"
+#include "vm/allocation.h"
+
namespace dart {
class Instance;
@@ -14,8 +16,7 @@
class Service : public AllStatic {
public:
- static void HandleServiceMessage(Isolate* isolate, Dart_Port reply_port,
- const Instance& message);
+ static void HandleServiceMessage(Isolate* isolate, const Instance& message);
};
} // namespace dart
diff --git a/runtime/vm/service_test.cc b/runtime/vm/service_test.cc
new file mode 100644
index 0000000..1a7bfcb
--- /dev/null
+++ b/runtime/vm/service_test.cc
@@ -0,0 +1,149 @@
+// 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.
+
+#include "include/dart_debugger_api.h"
+#include "vm/dart_api_impl.h"
+#include "vm/dart_entry.h"
+#include "vm/debugger.h"
+#include "vm/globals.h"
+#include "vm/message_handler.h"
+#include "vm/os.h"
+#include "vm/port.h"
+#include "vm/service.h"
+#include "vm/unit_test.h"
+
+namespace dart {
+
+class ServiceTestMessageHandler : public MessageHandler {
+ public:
+ ServiceTestMessageHandler() : _msg(NULL) {}
+
+ ~ServiceTestMessageHandler() {
+ free(_msg);
+ }
+
+ bool HandleMessage(Message* message) {
+ if (_msg != NULL) {
+ free(_msg);
+ }
+
+ // Parse the message.
+ SnapshotReader reader(message->data(), message->len(),
+ Snapshot::kMessage, Isolate::Current());
+ const Object& response_obj = Object::Handle(reader.ReadObject());
+ String& response = String::Handle();
+ response ^= response_obj.raw();
+ _msg = strdup(response.ToCString());
+ return true;
+ }
+
+ const char* msg() const { return _msg; }
+
+ private:
+ char* _msg;
+};
+
+
+static RawInstance* Eval(Dart_Handle lib, const char* expr) {
+ Dart_Handle result = Dart_EvaluateExpr(lib, NewString(expr));
+ EXPECT_VALID(result);
+ Isolate* isolate = Isolate::Current();
+ const Instance& instance = Api::UnwrapInstanceHandle(isolate, result);
+ return instance.raw();
+}
+
+
+TEST_CASE(Service_DebugBreakpoints) {
+ const char* kScript =
+ "var port;\n" // Set to our mock port by C++.
+ "\n"
+ "main() {\n" // We set breakpoint here.
+ "}";
+
+ Isolate* isolate = Isolate::Current();
+ Dart_Handle lib = TestCase::LoadTestScript(kScript, NULL);
+ EXPECT_VALID(lib);
+
+ // Build a mock message handler and wrap it in a dart port.
+ ServiceTestMessageHandler handler;
+ Dart_Port port_id = PortMap::CreatePort(&handler);
+ Dart_Handle port =
+ Api::NewHandle(isolate, DartLibraryCalls::NewSendPort(port_id));
+ EXPECT_VALID(port);
+ EXPECT_VALID(Dart_SetField(lib, NewString("port"), port));
+
+ Instance& service_msg = Instance::Handle();
+
+ // Add a breakpoint.
+ const String& url = String::Handle(String::New(TestCase::url()));
+ isolate->debugger()->SetBreakpointAtLine(url, 3);
+
+ // Get the breakpoint list.
+ service_msg = Eval(lib, "[port, ['debug', 'breakpoints'], [], []]");
+ Service::HandleServiceMessage(isolate, service_msg);
+ handler.HandleNextMessage();
+ EXPECT_STREQ(
+ "{\"type\":\"BreakpointList\",\"breakpoints\":[{"
+ "\"type\":\"Breakpoint\",\"id\":1,\"enabled\":true,"
+ "\"resolved\":false,"
+ "\"location\":{\"type\":\"Location\",\"libId\":12,"
+ "\"script\":\"dart:test-lib\",\"tokenPos\":5}}]}",
+ handler.msg());
+
+ // Individual breakpoint.
+ service_msg = Eval(lib, "[port, ['debug', 'breakpoints', '1'], [], []]");
+ Service::HandleServiceMessage(isolate, service_msg);
+ handler.HandleNextMessage();
+ EXPECT_STREQ(
+ "{\"type\":\"Breakpoint\",\"id\":1,\"enabled\":true,"
+ "\"resolved\":false,"
+ "\"location\":{\"type\":\"Location\",\"libId\":12,"
+ "\"script\":\"dart:test-lib\",\"tokenPos\":5}}",
+ handler.msg());
+
+ // Missing sub-command.
+ service_msg = Eval(lib, "[port, ['debug'], [], []]");
+ Service::HandleServiceMessage(isolate, service_msg);
+ handler.HandleNextMessage();
+ EXPECT_STREQ(
+ "{\"type\":\"Error\","
+ "\"text\":\"Must specify a subcommand\","
+ "\"message\":{\"arguments\":[\"debug\"],\"option_keys\":[],"
+ "\"option_values\":[]}}",
+ handler.msg());
+
+ // Unrecognized breakpoint.
+ service_msg = Eval(lib, "[port, ['debug', 'breakpoints', '1111'], [], []]");
+ Service::HandleServiceMessage(isolate, service_msg);
+ handler.HandleNextMessage();
+ EXPECT_STREQ("{\"type\":\"Error\","
+ "\"text\":\"Unrecognized breakpoint id 1111\","
+ "\"message\":{"
+ "\"arguments\":[\"debug\",\"breakpoints\",\"1111\"],"
+ "\"option_keys\":[],\"option_values\":[]}}",
+ handler.msg());
+
+ // Command too long.
+ service_msg =
+ Eval(lib, "[port, ['debug', 'breakpoints', '1111', 'green'], [], []]");
+ Service::HandleServiceMessage(isolate, service_msg);
+ handler.HandleNextMessage();
+ EXPECT_STREQ("{\"type\":\"Error\",\"text\":\"Command too long\","
+ "\"message\":{\"arguments\":[\"debug\",\"breakpoints\","
+ "\"1111\",\"green\"],"
+ "\"option_keys\":[],\"option_values\":[]}}",
+ handler.msg());
+
+ // Unrecognized subcommand.
+ service_msg = Eval(lib, "[port, ['debug', 'nosferatu'], [], []]");
+ Service::HandleServiceMessage(isolate, service_msg);
+ handler.HandleNextMessage();
+ EXPECT_STREQ("{\"type\":\"Error\","
+ "\"text\":\"Unrecognized subcommand 'nosferatu'\","
+ "\"message\":{\"arguments\":[\"debug\",\"nosferatu\"],"
+ "\"option_keys\":[],\"option_values\":[]}}",
+ handler.msg());
+}
+
+} // namespace dart
diff --git a/runtime/vm/signal_handler.h b/runtime/vm/signal_handler.h
index 67e1cfa..18909cb 100644
--- a/runtime/vm/signal_handler.h
+++ b/runtime/vm/signal_handler.h
@@ -40,16 +40,6 @@
};
-class ScopedSignalBlocker {
- public:
- ScopedSignalBlocker();
- ~ScopedSignalBlocker();
-
- private:
- sigset_t old_;
-};
-
-
} // namespace dart
#endif // VM_SIGNAL_HANDLER_H_
diff --git a/runtime/vm/signal_handler_android.cc b/runtime/vm/signal_handler_android.cc
index 11adfc7..7f04c2fb 100644
--- a/runtime/vm/signal_handler_android.cc
+++ b/runtime/vm/signal_handler_android.cc
@@ -29,18 +29,6 @@
}
-ScopedSignalBlocker::ScopedSignalBlocker() {
- sigset_t set;
- sigemptyset(&set);
- sigaddset(&set, SIGPROF);
- pthread_sigmask(SIG_SETMASK, &set, &old_);
-}
-
-
-ScopedSignalBlocker::~ScopedSignalBlocker() {
- pthread_sigmask(SIG_SETMASK, &old_, NULL);
-}
-
} // namespace dart
#endif // defined(TARGET_OS_ANDROID)
diff --git a/runtime/vm/signal_handler_linux.cc b/runtime/vm/signal_handler_linux.cc
index 4345dd4..7de4697 100644
--- a/runtime/vm/signal_handler_linux.cc
+++ b/runtime/vm/signal_handler_linux.cc
@@ -22,6 +22,8 @@
pc = static_cast<uintptr_t>(mcontext.gregs[REG_EIP]);
#elif defined(TARGET_ARCH_ARM)
pc = static_cast<uintptr_t>(mcontext.arm_pc);
+#elif defined(TARGET_ARCH_MIPS)
+ pc = static_cast<uintptr_t>(mcontext.pc);
#else
UNIMPLEMENTED();
#endif // TARGET_ARCH_...
@@ -42,6 +44,8 @@
fp = static_cast<uintptr_t>(mcontext.gregs[REG_EBP]);
#elif defined(TARGET_ARCH_ARM)
fp = static_cast<uintptr_t>(mcontext.arm_fp);
+#elif defined(TARGET_ARCH_MIPS)
+ fp = static_cast<uintptr_t>(mcontext.gregs[30]);
#else
UNIMPLEMENTED();
#endif // TARGET_ARCH_...
@@ -63,6 +67,8 @@
sp = static_cast<uintptr_t>(mcontext.gregs[REG_ESP]);
#elif defined(TARGET_ARCH_ARM)
sp = static_cast<uintptr_t>(mcontext.arm_sp);
+#elif defined(TARGET_ARCH_MIPS)
+ sp = static_cast<uintptr_t>(mcontext.gregs[29]);
#else
UNIMPLEMENTED();
#endif // TARGET_ARCH_...
@@ -83,18 +89,6 @@
}
-ScopedSignalBlocker::ScopedSignalBlocker() {
- sigset_t set;
- sigemptyset(&set);
- sigaddset(&set, SIGPROF);
- pthread_sigmask(SIG_SETMASK, &set, &old_);
-}
-
-
-ScopedSignalBlocker::~ScopedSignalBlocker() {
- pthread_sigmask(SIG_SETMASK, &old_, NULL);
-}
-
} // namespace dart
#endif // defined(TARGET_OS_LINUX)
diff --git a/runtime/vm/signal_handler_macos.cc b/runtime/vm/signal_handler_macos.cc
index f0e5b15..11e6234 100644
--- a/runtime/vm/signal_handler_macos.cc
+++ b/runtime/vm/signal_handler_macos.cc
@@ -79,18 +79,6 @@
}
-ScopedSignalBlocker::ScopedSignalBlocker() {
- sigset_t set;
- sigemptyset(&set);
- sigaddset(&set, SIGPROF);
- pthread_sigmask(SIG_SETMASK, &set, &old_);
-}
-
-
-ScopedSignalBlocker::~ScopedSignalBlocker() {
- pthread_sigmask(SIG_SETMASK, &old_, NULL);
-}
-
} // namespace dart
#endif // defined(TARGET_OS_MACOS)
diff --git a/runtime/vm/signal_handler_win.cc b/runtime/vm/signal_handler_win.cc
index 8a4b86c..6fc7723 100644
--- a/runtime/vm/signal_handler_win.cc
+++ b/runtime/vm/signal_handler_win.cc
@@ -31,13 +31,6 @@
}
-ScopedSignalBlocker::ScopedSignalBlocker() {
-}
-
-
-ScopedSignalBlocker::~ScopedSignalBlocker() {
-}
-
} // namespace dart
#endif // defined(TARGET_OS_WINDOWS)
diff --git a/runtime/vm/stack_frame_test.cc b/runtime/vm/stack_frame_test.cc
index fc5e269..4a06610 100644
--- a/runtime/vm/stack_frame_test.cc
+++ b/runtime/vm/stack_frame_test.cc
@@ -136,7 +136,10 @@
static Dart_NativeFunction native_lookup(Dart_Handle name,
- int argument_count) {
+ int argument_count,
+ bool* auto_setup_scope) {
+ ASSERT(auto_setup_scope != NULL);
+ *auto_setup_scope = false;
const Object& obj = Object::Handle(Api::UnwrapHandle(name));
ASSERT(obj.IsString());
const char* function_name = obj.ToCString();
diff --git a/runtime/vm/stub_code_arm.cc b/runtime/vm/stub_code_arm.cc
index d921151..11350d3 100644
--- a/runtime/vm/stub_code_arm.cc
+++ b/runtime/vm/stub_code_arm.cc
@@ -181,8 +181,14 @@
// For now, space is reserved on the stack and we pass a pointer to it.
__ stm(IA, SP, (1 << R0) | (1 << R1) | (1 << R2) | (1 << R3));
__ mov(R0, ShifterOperand(SP)); // Pass the pointer to the NativeArguments.
- __ mov(R1, ShifterOperand(R5)); // Pass the function entrypoint to call.
+ // Call native function (setsup scope if not leaf function).
+ Label leaf_call;
+ Label done;
+ __ TestImmediate(R1, NativeArguments::AutoSetupScopeMask());
+ __ b(&leaf_call, EQ);
+
+ __ mov(R1, ShifterOperand(R5)); // Pass the function entrypoint to call.
// Call native function invocation wrapper or redirection via simulator.
#if defined(USING_SIMULATOR)
uword entry = reinterpret_cast<uword>(NativeEntry::NativeCallWrapper);
@@ -193,6 +199,13 @@
#else
__ BranchLink(&NativeEntry::NativeCallWrapperLabel());
#endif
+ __ b(&done);
+
+ __ Bind(&leaf_call);
+ // Call native function or redirection via simulator.
+ __ blx(R5);
+
+ __ Bind(&done);
// Reset exit frame information in Isolate structure.
__ LoadImmediate(R2, 0);
diff --git a/runtime/vm/stub_code_ia32.cc b/runtime/vm/stub_code_ia32.cc
index 49df45c..9a8f88a 100644
--- a/runtime/vm/stub_code_ia32.cc
+++ b/runtime/vm/stub_code_ia32.cc
@@ -163,8 +163,18 @@
__ movl(Address(ESP, retval_offset), EAX); // Set retval in NativeArguments.
__ leal(EAX, Address(ESP, 2 * kWordSize)); // Pointer to the NativeArguments.
__ movl(Address(ESP, 0), EAX); // Pass the pointer to the NativeArguments.
+
+ // Call native function (setsup scope if not leaf function).
+ Label leaf_call;
+ Label done;
+ __ testl(EDX, Immediate(NativeArguments::AutoSetupScopeMask()));
+ __ j(ZERO, &leaf_call, Assembler::kNearJump);
__ movl(Address(ESP, kWordSize), ECX); // Function to call.
__ call(&NativeEntry::NativeCallWrapperLabel());
+ __ jmp(&done);
+ __ Bind(&leaf_call);
+ __ call(ECX);
+ __ Bind(&done);
// Reset exit frame information in Isolate structure.
__ movl(Address(CTX, Isolate::top_exit_frame_info_offset()), Immediate(0));
diff --git a/runtime/vm/stub_code_mips.cc b/runtime/vm/stub_code_mips.cc
index dbec240..33437e4 100644
--- a/runtime/vm/stub_code_mips.cc
+++ b/runtime/vm/stub_code_mips.cc
@@ -192,10 +192,15 @@
__ sw(A1, Address(SP, 1 * kWordSize));
__ sw(A0, Address(SP, 0 * kWordSize));
__ mov(A0, SP); // Pass the pointer to the NativeArguments.
+
+ // Call native function (setup scope if not leaf function).
+ Label leaf_call;
+ Label done;
+ __ AndImmediate(CMPRES1, A1, NativeArguments::AutoSetupScopeMask());
+ __ beq(CMPRES1, ZR, &leaf_call);
+
__ mov(A1, T5); // Pass the function entrypoint.
-
__ ReserveAlignedFrameSpace(2 * kWordSize); // Just passing A0, A1.
-
// Call native wrapper function or redirection via simulator.
#if defined(USING_SIMULATOR)
uword entry = reinterpret_cast<uword>(NativeEntry::NativeCallWrapper);
@@ -207,6 +212,14 @@
__ BranchLink(&NativeEntry::NativeCallWrapperLabel());
#endif
__ TraceSimMsg("CallNativeCFunctionStub return");
+ __ b(&done);
+
+ __ Bind(&leaf_call);
+ // Call native function or redirection via simulator.
+ __ ReserveAlignedFrameSpace(kWordSize); // Just passing A0.
+ __ jalr(T5);
+
+ __ Bind(&done);
// Reset exit frame information in Isolate structure.
__ sw(ZR, Address(CTX, Isolate::top_exit_frame_info_offset()));
diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc
index 5e0b9af..dac3e5c 100644
--- a/runtime/vm/stub_code_x64.cc
+++ b/runtime/vm/stub_code_x64.cc
@@ -161,8 +161,18 @@
__ leaq(RAX, Address(RBP, 2 * kWordSize)); // Compute return value addr.
__ movq(Address(RSP, retval_offset), RAX); // Set retval in NativeArguments.
__ movq(RDI, RSP); // Pass the pointer to the NativeArguments.
+
+ // Call native function (setsup scope if not leaf function).
+ Label leaf_call;
+ Label done;
+ __ testq(R10, Immediate(NativeArguments::AutoSetupScopeMask()));
+ __ j(ZERO, &leaf_call);
__ movq(RSI, RBX); // Pass pointer to function entrypoint.
__ call(&NativeEntry::NativeCallWrapperLabel());
+ __ jmp(&done);
+ __ Bind(&leaf_call);
+ __ call(RBX);
+ __ Bind(&done);
// Reset exit frame information in Isolate structure.
__ movq(Address(CTX, Isolate::top_exit_frame_info_offset()), Immediate(0));
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 4527379..c636537 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -184,8 +184,8 @@
V(_Uint64ArrayFactory, "_Uint64Array.") \
V(_Float32x4Array, "_Float32x4Array") \
V(_Float32x4ArrayFactory, "_Float32x4Array.") \
- V(_Int32x4Array, "_Int32x4Array") \
- V(_Int32x4ArrayFactory, "_Int32x4Array.") \
+ V(_Int32x4Array, "_Int32x4Array") \
+ V(_Int32x4ArrayFactory, "_Int32x4Array.") \
V(_Float32Array, "_Float32Array") \
V(_Float32ArrayFactory, "_Float32Array.") \
V(_Float64Array, "_Float64Array") \
@@ -202,7 +202,7 @@
V(_Float32ArrayView, "_Float32ArrayView") \
V(_Float64ArrayView, "_Float64ArrayView") \
V(_Float32x4ArrayView, "_Float32x4ArrayView") \
- V(_Int32x4ArrayView, "_Int32x4ArrayView") \
+ V(_Int32x4ArrayView, "_Int32x4ArrayView") \
V(_ExternalInt8Array, "_ExternalInt8Array") \
V(_ExternalUint8Array, "_ExternalUint8Array") \
V(_ExternalUint8ClampedArray, "_ExternalUint8ClampedArray") \
@@ -213,7 +213,7 @@
V(_ExternalInt64Array, "_ExternalInt64Array") \
V(_ExternalUint64Array, "_ExternalUint64Array") \
V(_ExternalFloat32x4Array, "_ExternalFloat32x4Array") \
- V(_ExternalInt32x4Array, "_ExternalInt32x4Array") \
+ V(_ExternalInt32x4Array, "_ExternalInt32x4Array") \
V(_ExternalFloat32Array, "_ExternalFloat32Array") \
V(_ExternalFloat64Array, "_ExternalFloat64Array") \
V(ByteData, "ByteData") \
@@ -240,7 +240,7 @@
V(UnsupportedError, "UnsupportedError") \
V(StackOverflowError, "StackOverflowError") \
V(OutOfMemoryError, "OutOfMemoryError") \
- V(InternalError, "InternalError") \
+ V(InternalError, "_InternalError") \
V(NullThrownError, "NullThrownError") \
V(IsolateSpawnException, "IsolateSpawnException") \
V(IsolateUnhandledException, "_IsolateUnhandledException") \
diff --git a/runtime/vm/thread.h b/runtime/vm/thread.h
index c554fb6..debe182 100644
--- a/runtime/vm/thread.h
+++ b/runtime/vm/thread.h
@@ -54,6 +54,10 @@
return monitor_->Wait(millis);
}
+ Monitor::WaitResult WaitMicros(int64_t micros = dart::Monitor::kNoTimeout) {
+ return monitor_->WaitMicros(micros);
+ }
+
void Notify() {
monitor_->Notify();
}
diff --git a/runtime/vm/thread_interrupter.cc b/runtime/vm/thread_interrupter.cc
new file mode 100644
index 0000000..2d44208
--- /dev/null
+++ b/runtime/vm/thread_interrupter.cc
@@ -0,0 +1,388 @@
+// 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.
+
+#include "vm/simulator.h"
+#include "vm/thread_interrupter.h"
+
+namespace dart {
+
+// Notes:
+//
+// The ThreadInterrupter interrupts all registered threads once per
+// interrupt period (default is every millisecond). While the thread is
+// interrupted, the thread's interrupt callback is invoked. Callbacks cannot
+// rely on being executed on the interrupted thread.
+//
+// There are two mechanisms used to interrupt a thread. The first, used on OSs
+// with pthreads (Android, Linux, and Mac), is thread specific signal delivery.
+// The second, used on Windows, is explicit suspend and resume thread system
+// calls. Signal delivery forbids taking locks and allocating memory (which
+// takes a lock). Explicit suspend and resume means that the interrupt callback
+// will not be executing on the interrupted thread, making it meaningless to
+// access TLS from within the thread interrupt callback. Combining these
+// limitations, thread interrupt callbacks are forbidden from:
+//
+// * Accessing TLS.
+// * Allocating memory.
+// * Taking a lock.
+//
+// The ThreadInterrupter has a single monitor (monitor_). This monitor guards
+// access to the list of threads registered to receive interrupts (threads_).
+//
+// A thread can only register and unregister itself. Each thread has a heap
+// allocated ThreadState. A thread's ThreadState is lazily allocated the first
+// time the thread is registered. A pointer to a thread's ThreadState is stored
+// in the list of threads registered to receive interrupts (threads_) and in
+// thread local storage. When a thread's ThreadState is being modified, the
+// thread local storage pointer is temporarily set to NULL while the
+// modification is occurring. After the ThreadState has been updated, the
+// thread local storage pointer is set again. This has an important side
+// effect: if the thread is interrupted by a signal handler during a ThreadState
+// update the signal handler will immediately return.
+
+DEFINE_FLAG(bool, trace_thread_interrupter, false,
+ "Trace thread interrupter");
+
+bool ThreadInterrupter::initialized_ = false;
+bool ThreadInterrupter::shutdown_ = false;
+bool ThreadInterrupter::thread_running_ = false;
+ThreadId ThreadInterrupter::interrupter_thread_id_ = Thread::kInvalidThreadId;
+Monitor* ThreadInterrupter::monitor_ = NULL;
+intptr_t ThreadInterrupter::interrupt_period_ = 1000;
+ThreadLocalKey ThreadInterrupter::thread_state_key_ =
+ Thread::kUnsetThreadLocalKey;
+ThreadInterrupter::ThreadState** ThreadInterrupter::threads_ = NULL;
+intptr_t ThreadInterrupter::threads_capacity_ = 0;
+intptr_t ThreadInterrupter::threads_size_ = 0;
+
+
+void ThreadInterrupter::InitOnce() {
+ ASSERT(!initialized_);
+ initialized_ = true;
+ ASSERT(thread_state_key_ == Thread::kUnsetThreadLocalKey);
+ thread_state_key_ = Thread::CreateThreadLocal();
+ ASSERT(thread_state_key_ != Thread::kUnsetThreadLocalKey);
+ monitor_ = new Monitor();
+ ResizeThreads(16);
+ if (FLAG_trace_thread_interrupter) {
+ OS::Print("ThreadInterrupter starting up.\n");
+ }
+ ASSERT(interrupter_thread_id_ == Thread::kInvalidThreadId);
+ {
+ MonitorLocker startup_ml(monitor_);
+ Thread::Start(ThreadMain, 0);
+ while (!thread_running_) {
+ startup_ml.Wait();
+ }
+ }
+ ASSERT(interrupter_thread_id_ != Thread::kInvalidThreadId);
+ if (FLAG_trace_thread_interrupter) {
+ OS::Print("ThreadInterrupter running.\n");
+ }
+}
+
+
+void ThreadInterrupter::Shutdown() {
+ if (shutdown_) {
+ // Already shutdown.
+ return;
+ }
+ ASSERT(initialized_);
+ if (FLAG_trace_thread_interrupter) {
+ OS::Print("ThreadInterrupter shutting down.\n");
+ }
+ intptr_t size_at_shutdown = 0;
+ {
+ MonitorLocker ml(monitor_);
+ shutdown_ = true;
+ size_at_shutdown = threads_size_;
+ threads_size_ = 0;
+ threads_capacity_ = 0;
+ free(threads_);
+ threads_ = NULL;
+ }
+ {
+ MonitorLocker shutdown_ml(monitor_);
+ while (thread_running_) {
+ shutdown_ml.Wait();
+ }
+ }
+ interrupter_thread_id_ = Thread::kInvalidThreadId;
+ if (FLAG_trace_thread_interrupter) {
+ OS::Print("ThreadInterrupter shut down (%" Pd ").\n", size_at_shutdown);
+ }
+}
+
+// Delay between interrupts.
+void ThreadInterrupter::SetInterruptPeriod(intptr_t period) {
+ if (shutdown_) {
+ return;
+ }
+ ASSERT(initialized_);
+ ASSERT(period > 0);
+ {
+ MonitorLocker ml(monitor_);
+ interrupt_period_ = period;
+ }
+}
+
+
+// Register the currently running thread for interrupts. If the current thread
+// is already registered, callback and data will be updated.
+void ThreadInterrupter::Register(ThreadInterruptCallback callback, void* data) {
+ if (shutdown_) {
+ return;
+ }
+ ASSERT(initialized_);
+ {
+ MonitorLocker ml(monitor_);
+ _EnsureThreadStateCreated();
+ // Set callback and data.
+ UpdateStateObject(callback, data);
+ _Enable();
+ }
+}
+
+
+// Unregister the currently running thread for interrupts.
+void ThreadInterrupter::Unregister() {
+ if (shutdown_) {
+ return;
+ }
+ ASSERT(initialized_);
+ {
+ MonitorLocker ml(monitor_);
+ _EnsureThreadStateCreated();
+ // Clear callback and data.
+ UpdateStateObject(NULL, NULL);
+ _Disable();
+ }
+}
+
+
+void ThreadInterrupter::Enable() {
+ if (shutdown_) {
+ return;
+ }
+ ASSERT(initialized_);
+ {
+ MonitorLocker ml(monitor_);
+ _EnsureThreadStateCreated();
+ _Enable();
+ }
+}
+
+
+void ThreadInterrupter::Disable() {
+ if (shutdown_) {
+ return;
+ }
+ ASSERT(initialized_);
+ {
+ MonitorLocker ml(monitor_);
+ _EnsureThreadStateCreated();
+ _Disable();
+ }
+}
+
+
+void ThreadInterrupter::_EnsureThreadStateCreated() {
+ ThreadState* state = CurrentThreadState();
+ if (state == NULL) {
+ // Create thread state object lazily.
+ ThreadId current_thread = Thread::GetCurrentThreadId();
+ if (FLAG_trace_thread_interrupter) {
+ intptr_t tid = Thread::ThreadIdToIntPtr(current_thread);
+ OS::Print("ThreadInterrupter Tracking %p\n",
+ reinterpret_cast<void*>(tid));
+ }
+ state = new ThreadState();
+ state->callback = NULL;
+ state->data = NULL;
+ state->id = current_thread;
+ SetCurrentThreadState(state);
+ }
+}
+
+
+void ThreadInterrupter::_Enable() {
+ // Must be called with monitor_ locked.
+ ThreadId current_thread = Thread::GetCurrentThreadId();
+ if (Thread::Compare(current_thread, interrupter_thread_id_)) {
+ return;
+ }
+ intptr_t i = FindThreadIndex(current_thread);
+ if (i >= 0) {
+ return;
+ }
+ AddThread(current_thread);
+ if (FLAG_trace_thread_interrupter) {
+ intptr_t tid = Thread::ThreadIdToIntPtr(current_thread);
+ OS::Print("ThreadInterrupter Added %p\n", reinterpret_cast<void*>(tid));
+ }
+}
+
+void ThreadInterrupter::_Disable() {
+ // Must be called with monitor_ locked.
+ ThreadId current_thread = Thread::GetCurrentThreadId();
+ if (Thread::Compare(current_thread, interrupter_thread_id_)) {
+ return;
+ }
+ intptr_t index = FindThreadIndex(current_thread);
+ if (index < 0) {
+ // Not registered.
+ return;
+ }
+ ThreadState* state = RemoveThread(index);
+ ASSERT(state != NULL);
+ ASSERT(state == ThreadInterrupter::CurrentThreadState());
+ if (FLAG_trace_thread_interrupter) {
+ intptr_t tid = Thread::ThreadIdToIntPtr(current_thread);
+ OS::Print("ThreadInterrupter Removed %p\n", reinterpret_cast<void*>(tid));
+ }
+}
+
+void ThreadInterrupter::UpdateStateObject(ThreadInterruptCallback callback,
+ void* data) {
+ // Must be called with monitor_ locked.
+ ThreadState* state = CurrentThreadState();
+ ThreadId current_thread = Thread::GetCurrentThreadId();
+ ASSERT(state != NULL);
+ ASSERT(Thread::Compare(state->id, Thread::GetCurrentThreadId()));
+ SetCurrentThreadState(NULL);
+ // It is now safe to modify the state object. If an interrupt occurs,
+ // the current thread state will be NULL.
+ state->callback = callback;
+ state->data = data;
+ SetCurrentThreadState(state);
+ if (FLAG_trace_thread_interrupter) {
+ intptr_t tid = Thread::ThreadIdToIntPtr(current_thread);
+ if (callback == NULL) {
+ OS::Print("ThreadInterrupter Cleared %p\n", reinterpret_cast<void*>(tid));
+ } else {
+ OS::Print("ThreadInterrupter Updated %p\n", reinterpret_cast<void*>(tid));
+ }
+ }
+}
+
+
+ThreadInterrupter::ThreadState* ThreadInterrupter::CurrentThreadState() {
+ ThreadState* state = reinterpret_cast<ThreadState*>(
+ Thread::GetThreadLocal(thread_state_key_));
+ return state;
+}
+
+
+void ThreadInterrupter::SetCurrentThreadState(ThreadState* state) {
+ Thread::SetThreadLocal(thread_state_key_, reinterpret_cast<uword>(state));
+}
+
+
+void ThreadInterrupter::ResizeThreads(intptr_t new_capacity) {
+ // Must be called with monitor_ locked.
+ ASSERT(new_capacity < kMaxThreads);
+ ASSERT(new_capacity > threads_capacity_);
+ ThreadState* state = NULL;
+ threads_ = reinterpret_cast<ThreadState**>(
+ realloc(threads_, sizeof(state) * new_capacity));
+ for (intptr_t i = threads_capacity_; i < new_capacity; i++) {
+ threads_[i] = NULL;
+ }
+ threads_capacity_ = new_capacity;
+}
+
+
+void ThreadInterrupter::AddThread(ThreadId id) {
+ // Must be called with monitor_ locked.
+ if (threads_ == NULL) {
+ // We are shutting down.
+ return;
+ }
+ ThreadState* state = CurrentThreadState();
+ if (state->callback == NULL) {
+ // No callback.
+ return;
+ }
+ if (threads_size_ == threads_capacity_) {
+ ResizeThreads(threads_capacity_ == 0 ? 16 : threads_capacity_ * 2);
+ }
+ threads_[threads_size_] = state;
+ threads_size_++;
+}
+
+
+intptr_t ThreadInterrupter::FindThreadIndex(ThreadId id) {
+ // Must be called with monitor_ locked.
+ if (threads_ == NULL) {
+ // We are shutting down.
+ return -1;
+ }
+ for (intptr_t i = 0; i < threads_size_; i++) {
+ if (threads_[i]->id == id) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+
+ThreadInterrupter::ThreadState* ThreadInterrupter::RemoveThread(intptr_t i) {
+ // Must be called with monitor_ locked.
+ if (threads_ == NULL) {
+ // We are shutting down.
+ return NULL;
+ }
+ ASSERT(i < threads_size_);
+ ThreadState* state = threads_[i];
+ ASSERT(state != NULL);
+ intptr_t last = threads_size_ - 1;
+ if (i != last) {
+ threads_[i] = threads_[last];
+ }
+ // Mark last as NULL.
+ threads_[last] = NULL;
+ // Pop.
+ threads_size_--;
+ return state;
+}
+
+
+void ThreadInterruptNoOp(const InterruptedThreadState& state, void* data) {
+ // NoOp.
+}
+
+
+void ThreadInterrupter::ThreadMain(uword parameters) {
+ ASSERT(initialized_);
+ InstallSignalHandler();
+ if (FLAG_trace_thread_interrupter) {
+ OS::Print("ThreadInterrupter thread running.\n");
+ }
+ {
+ // Signal to main thread we are ready.
+ MonitorLocker startup_ml(monitor_);
+ thread_running_ = true;
+ interrupter_thread_id_ = Thread::GetCurrentThreadId();
+ startup_ml.Notify();
+ }
+ {
+ MonitorLocker ml(monitor_);
+ while (!shutdown_) {
+ int64_t current_time = OS::GetCurrentTimeMicros();
+ InterruptThreads(current_time);
+ ml.WaitMicros(interrupt_period_);
+ }
+ }
+ if (FLAG_trace_thread_interrupter) {
+ OS::Print("ThreadInterrupter thread exiting.\n");
+ }
+ {
+ // Signal to main thread we are exiting.
+ MonitorLocker shutdown_ml(monitor_);
+ thread_running_ = false;
+ shutdown_ml.Notify();
+ }
+}
+
+} // namespace dart
diff --git a/runtime/vm/thread_interrupter.h b/runtime/vm/thread_interrupter.h
new file mode 100644
index 0000000..3a31683
--- /dev/null
+++ b/runtime/vm/thread_interrupter.h
@@ -0,0 +1,99 @@
+// 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.
+
+#ifndef VM_THREAD_INTERRUPTER_H_
+#define VM_THREAD_INTERRUPTER_H_
+
+#include "vm/allocation.h"
+#include "vm/signal_handler.h"
+#include "vm/thread.h"
+
+
+namespace dart {
+
+struct InterruptedThreadState {
+ ThreadId tid;
+ uintptr_t pc;
+ uintptr_t sp;
+ uintptr_t fp;
+};
+
+// When a thread is interrupted the thread specific interrupt
+// callback will be invoked at the interrupt period. Each callback is given an
+// InterruptedThreadState and the thread specific data pointer. When inside a
+// thread interrupt callback doing any of the following
+// is forbidden:
+// * Accessing TLS.
+// * Allocating memory.
+// * Taking a lock.
+typedef void (*ThreadInterruptCallback)(const InterruptedThreadState& state,
+ void* data);
+
+class ThreadInterrupter : public AllStatic {
+ public:
+ static void InitOnce();
+ static void Shutdown();
+
+ // Delay between interrupts.
+ static void SetInterruptPeriod(intptr_t period);
+
+ // Register the currently running thread for interrupts. If the current thread
+ // is already registered, callback and data will be updated.
+ static void Register(ThreadInterruptCallback callback, void* data);
+ // Unregister the currently running thread for interrupts.
+ static void Unregister();
+
+ // Enable interrupts for this thread. Does not alter callback.
+ static void Enable();
+ // Disable interrupts for this thread. Does not alter callback.
+ static void Disable();
+
+ private:
+ static const intptr_t kMaxThreads = 4096;
+ static bool initialized_;
+ static bool shutdown_;
+ static bool thread_running_;
+ static ThreadId interrupter_thread_id_;
+ static Monitor* monitor_;
+ static intptr_t interrupt_period_;
+ static ThreadLocalKey thread_state_key_;
+ // State stored per registered thread.
+ struct ThreadState {
+ ThreadId id;
+ ThreadInterruptCallback callback;
+ void* data;
+ };
+
+ static void UpdateStateObject(ThreadInterruptCallback callback, void* data);
+ static ThreadState* CurrentThreadState();
+ static void SetCurrentThreadState(ThreadState* state);
+
+ // Registered thread table.
+ static ThreadState** threads_;
+ static intptr_t threads_capacity_;
+ static intptr_t threads_size_;
+ static void _EnsureThreadStateCreated();
+ static void _Enable();
+ static void _Disable();
+ static void ResizeThreads(intptr_t new_capacity);
+ static void AddThread(ThreadId id);
+ static intptr_t FindThreadIndex(ThreadId id);
+ static ThreadState* RemoveThread(intptr_t i);
+
+ friend class ThreadInterrupterAndroid;
+ friend class ThreadInterrupterMacOS;
+ friend class ThreadInterrupterLinux;
+ friend class ThreadInterrupterWin;
+
+ static void InterruptThreads(int64_t current_time);
+ static void ThreadMain(uword parameters);
+
+ static void InstallSignalHandler();
+};
+
+void ThreadInterruptNoOp(const InterruptedThreadState& state, void* data);
+
+} // namespace dart
+
+#endif // VM_THREAD_INTERRUPTER_H_
diff --git a/runtime/vm/thread_interrupter_android.cc b/runtime/vm/thread_interrupter_android.cc
new file mode 100644
index 0000000..a5a4f8a
--- /dev/null
+++ b/runtime/vm/thread_interrupter_android.cc
@@ -0,0 +1,55 @@
+// 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.
+
+#include "platform/globals.h"
+#if defined(TARGET_OS_ANDROID)
+
+#include "vm/signal_handler.h"
+#include "vm/thread_interrupter.h"
+
+namespace dart {
+
+DECLARE_FLAG(bool, thread_interrupter);
+DECLARE_FLAG(bool, trace_thread_interrupter);
+
+class ThreadInterrupterAndroid : public AllStatic {
+ public:
+ static void ThreadInterruptSignalHandler(int signal, siginfo_t* info,
+ void* context_) {
+ if (signal != SIGPROF) {
+ return;
+ }
+ ThreadInterrupter::ThreadState* state =
+ ThreadInterrupter::CurrentThreadState();
+ if ((state == NULL) || (state->callback == NULL)) {
+ // No interrupter state or callback.
+ return;
+ }
+ ASSERT(Thread::Compare(state->id, Thread::GetCurrentThreadId()));
+ }
+};
+
+
+void ThreadInterrupter::InterruptThreads(int64_t current_time) {
+ for (intptr_t i = 0; i < threads_size_; i++) {
+ ThreadState* state = threads_[i];
+ ASSERT(state->id != Thread::kInvalidThreadId);
+ if (FLAG_trace_thread_interrupter) {
+ OS::Print("ThreadInterrupter interrupting %p\n",
+ reinterpret_cast<void*>(state->id));
+ }
+ pthread_kill(state->id, SIGPROF);
+ }
+}
+
+
+void ThreadInterrupter::InstallSignalHandler() {
+ SignalHandler::Install(
+ ThreadInterrupterAndroid::ThreadInterruptSignalHandler);
+}
+
+
+} // namespace dart
+
+#endif // defined(TARGET_OS_ANDROID)
diff --git a/runtime/vm/thread_interrupter_linux.cc b/runtime/vm/thread_interrupter_linux.cc
new file mode 100644
index 0000000..ee6b4a7
--- /dev/null
+++ b/runtime/vm/thread_interrupter_linux.cc
@@ -0,0 +1,63 @@
+// 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.
+
+#include "platform/globals.h"
+#if defined(TARGET_OS_LINUX)
+
+#include "vm/signal_handler.h"
+#include "vm/thread_interrupter.h"
+
+namespace dart {
+
+DECLARE_FLAG(bool, thread_interrupter);
+DECLARE_FLAG(bool, trace_thread_interrupter);
+
+class ThreadInterrupterLinux : public AllStatic {
+ public:
+ static void ThreadInterruptSignalHandler(int signal, siginfo_t* info,
+ void* context_) {
+ if (signal != SIGPROF) {
+ return;
+ }
+ ThreadInterrupter::ThreadState* state =
+ ThreadInterrupter::CurrentThreadState();
+ if ((state == NULL) || (state->callback == NULL)) {
+ // No interrupter state or callback.
+ return;
+ }
+ ASSERT(Thread::Compare(state->id, Thread::GetCurrentThreadId()));
+ // Extract thread state.
+ ucontext_t* context = reinterpret_cast<ucontext_t*>(context_);
+ mcontext_t mcontext = context->uc_mcontext;
+ InterruptedThreadState its;
+ its.tid = state->id;
+ its.pc = SignalHandler::GetProgramCounter(mcontext);
+ its.fp = SignalHandler::GetFramePointer(mcontext);
+ its.sp = SignalHandler::GetStackPointer(mcontext);
+ state->callback(its, state->data);
+ }
+};
+
+
+void ThreadInterrupter::InterruptThreads(int64_t current_time) {
+ for (intptr_t i = 0; i < threads_size_; i++) {
+ ThreadState* state = threads_[i];
+ ASSERT(state->id != Thread::kInvalidThreadId);
+ if (FLAG_trace_thread_interrupter) {
+ OS::Print("ThreadInterrupter interrupting %p\n",
+ reinterpret_cast<void*>(state->id));
+ }
+ pthread_kill(state->id, SIGPROF);
+ }
+}
+
+
+void ThreadInterrupter::InstallSignalHandler() {
+ SignalHandler::Install(ThreadInterrupterLinux::ThreadInterruptSignalHandler);
+}
+
+
+} // namespace dart
+
+#endif // defined(TARGET_OS_LINUX)
diff --git a/runtime/vm/thread_interrupter_macos.cc b/runtime/vm/thread_interrupter_macos.cc
new file mode 100644
index 0000000..f9deca5
--- /dev/null
+++ b/runtime/vm/thread_interrupter_macos.cc
@@ -0,0 +1,64 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "platform/globals.h"
+#if defined(TARGET_OS_MACOS)
+
+#include "vm/signal_handler.h"
+#include "vm/thread_interrupter.h"
+
+namespace dart {
+
+DECLARE_FLAG(bool, thread_interrupter);
+DECLARE_FLAG(bool, trace_thread_interrupter);
+
+class ThreadInterrupterMacOS : public AllStatic {
+ public:
+ static void ThreadInterruptSignalHandler(int signal, siginfo_t* info,
+ void* context_) {
+ if (signal != SIGPROF) {
+ return;
+ }
+ ThreadInterrupter::ThreadState* state =
+ ThreadInterrupter::CurrentThreadState();
+ if ((state == NULL) || (state->callback == NULL)) {
+ // No interrupter state or callback.
+ return;
+ }
+ ASSERT(Thread::Compare(state->id, Thread::GetCurrentThreadId()));
+
+ // Extract thread state.
+ ucontext_t* context = reinterpret_cast<ucontext_t*>(context_);
+ mcontext_t mcontext = context->uc_mcontext;
+ InterruptedThreadState its;
+ its.tid = state->id;
+ its.pc = SignalHandler::GetProgramCounter(mcontext);
+ its.fp = SignalHandler::GetFramePointer(mcontext);
+ its.sp = SignalHandler::GetStackPointer(mcontext);
+ state->callback(its, state->data);
+ }
+};
+
+
+void ThreadInterrupter::InterruptThreads(int64_t current_time) {
+ for (intptr_t i = 0; i < threads_size_; i++) {
+ ThreadState* state = threads_[i];
+ ASSERT(state->id != Thread::kInvalidThreadId);
+ if (FLAG_trace_thread_interrupter) {
+ OS::Print("ThreadInterrupter interrupting %p\n", state->id);
+ }
+ pthread_kill(state->id, SIGPROF);
+ }
+}
+
+
+void ThreadInterrupter::InstallSignalHandler() {
+ SignalHandler::Install(ThreadInterrupterMacOS::ThreadInterruptSignalHandler);
+}
+
+
+} // namespace dart
+
+#endif // defined(TARGET_OS_MACOS)
+
diff --git a/runtime/vm/thread_interrupter_test.cc b/runtime/vm/thread_interrupter_test.cc
new file mode 100644
index 0000000..4d69edd
--- /dev/null
+++ b/runtime/vm/thread_interrupter_test.cc
@@ -0,0 +1,65 @@
+// 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.
+
+#include "platform/assert.h"
+
+#include "vm/dart_api_impl.h"
+#include "vm/dart_api_state.h"
+#include "vm/globals.h"
+#include "vm/thread_interrupter.h"
+#include "vm/unit_test.h"
+
+namespace dart {
+
+class ThreadInterrupterTestHelper : public AllStatic {
+ public:
+ static void InterruptTest(const intptr_t run_time, const intptr_t period) {
+ const double allowed_error = 0.25; // +/- 25%
+ intptr_t count = 0;
+ ThreadInterrupter::Unregister();
+ ThreadInterrupter::SetInterruptPeriod(period);
+ ThreadInterrupter::Register(IncrementCallback, &count);
+ OS::Sleep(run_time * kMillisecondsPerSecond);
+ ThreadInterrupter::Unregister();
+ intptr_t run_time_micros = run_time * kMicrosecondsPerSecond;
+ intptr_t expected_interrupts = run_time_micros / period;
+ intptr_t error = allowed_error * expected_interrupts;
+ intptr_t low_bar = expected_interrupts - error;
+ intptr_t high_bar = expected_interrupts + error;
+ EXPECT_GE(count, low_bar);
+ EXPECT_LE(count, high_bar);
+ }
+
+ static void IncrementCallback(const InterruptedThreadState& state,
+ void* data) {
+ ASSERT(data != NULL);
+ intptr_t* counter = reinterpret_cast<intptr_t*>(data);
+ *counter = *counter + 1;
+ }
+};
+
+
+TEST_CASE(ThreadInterrupterHigh) {
+ const intptr_t kRunTimeSeconds = 5;
+ const intptr_t kInterruptPeriodMicros = 250;
+ ThreadInterrupterTestHelper::InterruptTest(kRunTimeSeconds,
+ kInterruptPeriodMicros);
+}
+
+TEST_CASE(ThreadInterrupterMedium) {
+ const intptr_t kRunTimeSeconds = 5;
+ const intptr_t kInterruptPeriodMicros = 500;
+ ThreadInterrupterTestHelper::InterruptTest(kRunTimeSeconds,
+ kInterruptPeriodMicros);
+}
+
+TEST_CASE(ThreadInterrupterLow) {
+ const intptr_t kRunTimeSeconds = 5;
+ const intptr_t kInterruptPeriodMicros = 1000;
+ ThreadInterrupterTestHelper::InterruptTest(kRunTimeSeconds,
+ kInterruptPeriodMicros);
+}
+
+
+} // namespace dart
diff --git a/runtime/vm/thread_interrupter_win.cc b/runtime/vm/thread_interrupter_win.cc
new file mode 100644
index 0000000..c933cbb
--- /dev/null
+++ b/runtime/vm/thread_interrupter_win.cc
@@ -0,0 +1,98 @@
+// 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.
+
+#include "platform/globals.h"
+#if defined(TARGET_OS_WINDOWS)
+
+#include "vm/thread_interrupter.h"
+
+namespace dart {
+
+DECLARE_FLAG(bool, thread_interrupter);
+DECLARE_FLAG(bool, trace_thread_interrupter);
+
+#define kThreadError -1
+
+class ThreadInterrupterWin : public AllStatic {
+ public:
+ static bool GrabRegisters(ThreadId thread, InterruptedThreadState* state) {
+ CONTEXT context;
+ memset(&context, 0, sizeof(context));
+ context.ContextFlags = CONTEXT_FULL;
+ if (GetThreadContext(thread, &context) != 0) {
+#if defined(TARGET_ARCH_IA32)
+ state->pc = static_cast<uintptr_t>(context.Eip);
+ state->fp = static_cast<uintptr_t>(context.Ebp);
+ state->sp = static_cast<uintptr_t>(context.Esp);
+#elif defined(TARGET_ARCH_X64)
+ state->pc = reinterpret_cast<uintptr_t>(context.Rip);
+ state->fp = reinterpret_cast<uintptr_t>(context.Rbp);
+ state->sp = reinterpret_cast<uintptr_t>(context.Rsp);
+#else
+ UNIMPLEMENTED();
+#endif
+ return true;
+ }
+ return false;
+ }
+
+
+ static void Interrupt(ThreadInterrupter::ThreadState* state) {
+ ASSERT(GetCurrentThread() != state->id);
+ DWORD result = SuspendThread(state->id);
+ if (result == kThreadError) {
+ if (FLAG_trace_thread_interrupter) {
+ OS::Print("ThreadInterrupted failed to suspend thread %p\n",
+ reinterpret_cast<void*>(state->id));
+ }
+ return;
+ }
+ InterruptedThreadState its;
+ its.tid = state->id;
+ if (!GrabRegisters(state->id, &its)) {
+ // Failed to get thread registers.
+ ResumeThread(state->id);
+ if (FLAG_trace_thread_interrupter) {
+ OS::Print("ThreadInterrupted failed to get registers for %p\n",
+ reinterpret_cast<void*>(state->id));
+ }
+ return;
+ }
+ if (state->callback == NULL) {
+ // No callback registered.
+ ResumeThread(state->id);
+ return;
+ }
+ state->callback(its, state->data);
+ ResumeThread(state->id);
+ }
+};
+
+
+void ThreadInterrupter::InterruptThreads(int64_t current_time) {
+ for (intptr_t i = 0; i < threads_size_; i++) {
+ ThreadState* state = threads_[i];
+ ASSERT(state->id != Thread::kInvalidThreadId);
+ if (FLAG_trace_thread_interrupter) {
+ OS::Print("ThreadInterrupter suspending %p\n",
+ reinterpret_cast<void*>(state->id));
+ }
+ ThreadInterrupterWin::Interrupt(state);
+ if (FLAG_trace_thread_interrupter) {
+ OS::Print("ThreadInterrupter resuming %p\n",
+ reinterpret_cast<void*>(state->id));
+ }
+ }
+}
+
+
+void ThreadInterrupter::InstallSignalHandler() {
+ // Nothing to do on Windows.
+}
+
+
+} // namespace dart
+
+#endif // defined(TARGET_OS_WINDOWS)
+
diff --git a/runtime/vm/thread_test.cc b/runtime/vm/thread_test.cc
index 1305a1c..0c0c912 100644
--- a/runtime/vm/thread_test.cc
+++ b/runtime/vm/thread_test.cc
@@ -5,7 +5,7 @@
#include "platform/assert.h"
#include "vm/isolate.h"
#include "vm/unit_test.h"
-#include "vm/signal_handler.h"
+#include "vm/profiler.h"
#include "vm/thread.h"
namespace dart {
@@ -35,7 +35,8 @@
UNIT_TEST_CASE(Monitor) {
// This unit test case needs a running isolate.
Isolate* isolate = Isolate::Init(NULL);
-
+ // Profiler interrupts interfere with this test.
+ Profiler::EndExecution(isolate);
Monitor* monitor = new Monitor();
monitor->Enter();
monitor->Exit();
@@ -43,10 +44,6 @@
const int kNumAttempts = 5;
int attempts = 0;
while (attempts < kNumAttempts) {
- // This test verifies that a monitor returns after the specified timeout. If
- // a signal is delivered to this thread, the monitor may return early.
- // Block signal delivery in this scope.
- ScopedSignalBlocker ssb;
MonitorLocker ml(monitor);
int64_t start = OS::GetCurrentTimeMillis();
int64_t wait_time = 2017;
diff --git a/runtime/vm/vm_sources.gypi b/runtime/vm/vm_sources.gypi
index 10f4950..92c5524 100644
--- a/runtime/vm/vm_sources.gypi
+++ b/runtime/vm/vm_sources.gypi
@@ -31,6 +31,11 @@
'ast_printer.h',
'ast_printer_test.cc',
'ast_test.cc',
+ 'atomic.h',
+ 'atomic_android.cc',
+ 'atomic_linux.cc',
+ 'atomic_macos.cc',
+ 'atomic_win.cc',
'base_isolate.h',
'benchmark_test.cc',
'benchmark_test.h',
@@ -107,6 +112,7 @@
'dart_entry.h',
'dart_entry_test.cc',
'debugger.cc',
+ 'debugger_test.cc',
'debugger.h',
'debugger_api_impl_test.cc',
'debugger_arm.cc',
@@ -277,11 +283,7 @@
'port_test.cc',
'profiler.cc',
'profiler.h',
- 'profiler_android.cc',
- 'profiler_linux.cc',
- 'profiler_macos.cc',
'profiler_test.cc',
- 'profiler_win.cc',
'random.cc',
'random.h',
'raw_object.cc',
@@ -306,6 +308,7 @@
'scopes.h',
'scopes_test.cc',
'service.cc',
+ 'service_test.cc',
'service.h',
'signal_handler_android.cc',
'signal_handler_linux.cc',
@@ -343,6 +346,13 @@
'symbols.cc',
'symbols.h',
'thread.h',
+ 'thread_interrupter.cc',
+ 'thread_interrupter.h',
+ 'thread_interrupter_android.cc',
+ 'thread_interrupter_linux.cc',
+ 'thread_interrupter_macos.cc',
+ 'thread_interrupter_test.cc',
+ 'thread_interrupter_win.cc',
'thread_pool.cc',
'thread_pool.h',
'thread_pool_test.cc',
diff --git a/sdk/bin/pub.bat b/sdk/bin/pub.bat
index 03213fd..9294231 100644
--- a/sdk/bin/pub.bat
+++ b/sdk/bin/pub.bat
@@ -18,16 +18,16 @@
IF %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
set PUB=%SDK_DIR%\lib\_internal\pub\bin\pub.dart
-set BUILD_DIR=%SDK_DIR%\..\build\ReleaseIA32
-set PACKAGES_DIR=%BUILD_DIR%\packages\
set DART=%BIN_DIR%\dart
-set DART_IN_BUILT_SDK=%BUILD_DIR%\dart-sdk\bin\dart
set SNAPSHOT=%BIN_DIR%\snapshots\pub.dart.snapshot
+set BUILD_DIR=%SDK_DIR%\..\build\ReleaseIA32
+set PACKAGES_DIR=%BUILD_DIR%\packages
+set DART_IN_BUILT_SDK=%BUILD_DIR%\dart-sdk\bin\dart
if exist "%SNAPSHOT%" (
"%DART%" "%SNAPSHOT%" %*
) else (
- "%DART_IN_BUILT_SDK%" --package-root=%PACKAGES_DIR% "%PUB%" %*
+ "%DART_IN_BUILT_SDK%" --package-root="%PACKAGES_DIR%" "%PUB%" %*
)
endlocal
@@ -38,8 +38,8 @@
setlocal
for %%i in (%1) do set result=%%~fi
set current=
-for /f "tokens=2 delims=[]" %%i in ('dir /a:l ^"%~dp1^" 2^>nul ^
- ^| find "> %~n1 ["') do (
+for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
+ ^| find "> %~n1 ["`) do (
set current=%%i
)
if not "%current%"=="" call :follow_links "%current%", result
diff --git a/sdk/bin/pub_developer.bat b/sdk/bin/pub_developer.bat
index 6f0d4e0..9c77b79 100644
--- a/sdk/bin/pub_developer.bat
+++ b/sdk/bin/pub_developer.bat
@@ -18,16 +18,16 @@
IF %SDK_DIR:~-1%==\ set SDK_DIR=%SDK_DIR:~0,-1%
set PUB=%SDK_DIR%\lib\_internal\pub\bin\pub.dart
-set BUILD_DIR=%SDK_DIR%\..\build\ReleaseIA32
-set PACKAGES_DIR=%BUILD_DIR%\packages\
set DART=%BIN_DIR%\dart
-set DART_IN_BUILT_SDK=%BUILD_DIR%\dart-sdk\bin\dart
set SNAPSHOT=%BIN_DIR%\snapshots\pub.dart.snapshot
+set BUILD_DIR=%SDK_DIR%\..\build\ReleaseIA32
+set PACKAGES_DIR=%BUILD_DIR%\packages
+set DART_IN_BUILT_SDK=%BUILD_DIR%\dart-sdk\bin\dart
if exist "%SNAPSHOT%" (
"%DART%" --checked "%SNAPSHOT%" %*
) else (
- "%DART_IN_BUILT_SDK%" --checked --package-root=%PACKAGES_DIR% "%PUB%" %*
+ "%DART_IN_BUILT_SDK%" --checked --package-root="%PACKAGES_DIR%" "%PUB%" %*
)
endlocal
@@ -38,8 +38,8 @@
setlocal
for %%i in (%1) do set result=%%~fi
set current=
-for /f "tokens=2 delims=[]" %%i in ('dir /a:l ^"%~dp1^" 2^>nul ^
- ^| find "> %~n1 ["') do (
+for /f "usebackq tokens=2 delims=[]" %%i in (`dir /a:l "%~dp1" 2^>nul ^
+ ^| find "> %~n1 ["`) do (
set current=%%i
)
if not "%current%"=="" call :follow_links "%current%", result
diff --git a/sdk/lib/_collection_dev/collection_dev.dart b/sdk/lib/_collection_dev/collection_dev.dart
index 6e883f6..9902b0e 100644
--- a/sdk/lib/_collection_dev/collection_dev.dart
+++ b/sdk/lib/_collection_dev/collection_dev.dart
@@ -10,9 +10,9 @@
import 'dart:core' as core;
import 'dart:math' show Random;
-part 'arrays.dart';
part 'iterable.dart';
part 'list.dart';
+part 'lists.dart';
part 'print.dart';
part 'sort.dart';
part 'symbol.dart';
diff --git a/sdk/lib/_collection_dev/collection_dev_sources.gypi b/sdk/lib/_collection_dev/collection_dev_sources.gypi
index c85469d..bb25742 100644
--- a/sdk/lib/_collection_dev/collection_dev_sources.gypi
+++ b/sdk/lib/_collection_dev/collection_dev_sources.gypi
@@ -7,9 +7,9 @@
'sources': [
'collection_dev.dart',
# The above file needs to be first as it lists the parts below.
- 'arrays.dart',
'iterable.dart',
'list.dart',
+ 'lists.dart',
'print.dart',
'sort.dart',
'symbol.dart',
diff --git a/sdk/lib/_collection_dev/iterable.dart b/sdk/lib/_collection_dev/iterable.dart
index 651e346..4bcc7b8 100644
--- a/sdk/lib/_collection_dev/iterable.dart
+++ b/sdk/lib/_collection_dev/iterable.dart
@@ -1016,12 +1016,12 @@
}
static int indexOfList(List list, var element, int start) {
- return Arrays.indexOf(list, element, start, list.length);
+ return Lists.indexOf(list, element, start, list.length);
}
static int lastIndexOfList(List list, var element, int start) {
if (start == null) start = list.length - 1;
- return Arrays.lastIndexOf(list, element, start);
+ return Lists.lastIndexOf(list, element, start);
}
static void _rangeCheck(List list, int start, int end) {
@@ -1060,7 +1060,7 @@
if (otherStart + length > otherList.length) {
throw new StateError("Not enough elements");
}
- Arrays.copy(otherList, otherStart, list, start, length);
+ Lists.copy(otherList, otherStart, list, start, length);
}
static void replaceRangeList(List list, int start, int end,
diff --git a/sdk/lib/_collection_dev/arrays.dart b/sdk/lib/_collection_dev/lists.dart
similarity index 97%
rename from sdk/lib/_collection_dev/arrays.dart
rename to sdk/lib/_collection_dev/lists.dart
index deaa169..eed1df5 100644
--- a/sdk/lib/_collection_dev/arrays.dart
+++ b/sdk/lib/_collection_dev/lists.dart
@@ -4,8 +4,7 @@
part of dart._collection.dev;
-// TODO(ngeoffray): Rename to Lists.
-class Arrays {
+class Lists {
static void copy(List src, int srcStart,
List dst, int dstStart, int count) {
if (srcStart < dstStart) {
diff --git a/sdk/lib/_internal/compiler/implementation/constants.dart b/sdk/lib/_internal/compiler/implementation/constants.dart
index d030524..272fd6a 100644
--- a/sdk/lib/_internal/compiler/implementation/constants.dart
+++ b/sdk/lib/_internal/compiler/implementation/constants.dart
@@ -17,6 +17,7 @@
R visitConstructed(ConstructedConstant constant);
R visitType(TypeConstant constant);
R visitInterceptor(InterceptorConstant constant);
+ R visitDummyReceiver(DummyReceiverConstant constant);
}
abstract class Constant {
@@ -41,6 +42,7 @@
bool isType() => false;
bool isSentinel() => false;
bool isInterceptor() => false;
+ bool isDummyReceiver() => false;
bool isNaN() => false;
bool isMinusZero() => false;
@@ -538,6 +540,33 @@
}
}
+class DummyReceiverConstant extends Constant {
+ final ti.TypeMask typeMask;
+
+ DummyReceiverConstant(this.typeMask);
+
+ bool isDummyReceiver() => true;
+
+ bool operator ==(other) {
+ return other is DummyReceiverConstant
+ && typeMask == other.typeMask;
+ }
+
+ get hashCode => typeMask.hashCode;
+
+ List<Constant> getDependencies() => const <Constant>[];
+
+ accept(ConstantVisitor visitor) => visitor.visitDummyReceiver(this);
+
+ DartType computeType(Compiler compiler) => compiler.types.dynamicType;
+
+ ti.TypeMask computeMask(Compiler compiler) => typeMask;
+
+ String toString() {
+ return 'DummyReceiverConstant($typeMask)';
+ }
+}
+
class ConstructedConstant extends ObjectConstant {
final List<Constant> fields;
final int hashCode;
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/closure_tracer.dart b/sdk/lib/_internal/compiler/implementation/inferrer/closure_tracer.dart
new file mode 100644
index 0000000..3d41263
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/closure_tracer.dart
@@ -0,0 +1,79 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of type_graph_inferrer;
+
+class ClosureTracerVisitor extends TracerVisitor {
+ ClosureTracerVisitor(tracedType, inferrer) : super(tracedType, inferrer);
+
+ void run() {
+ ClosureTypeInformation closure = tracedType;
+ FunctionElement element = closure.element;
+ element.functionSignature.forEachParameter((Element parameter) {
+ ElementTypeInformation info = inferrer.types.getInferredTypeOf(parameter);
+ info.abandonInferencing = false;
+ });
+ analyze();
+ element.functionSignature.forEachParameter((Element parameter) {
+ ElementTypeInformation info = inferrer.types.getInferredTypeOf(parameter);
+ if (continueAnalyzing) {
+ info.disableHandleSpecialCases = true;
+ } else {
+ info.giveUp(inferrer);
+ }
+ });
+ }
+
+ visitMapTypeInformation(MapTypeInformation info) {
+ bailout('Stored in a map');
+ }
+
+ void analyzeCall(CallSiteTypeInformation info) {
+ ClosureTypeInformation closure = tracedType;
+ FunctionElement element = closure.element;
+ Selector selector = info.selector;
+ if (!selector.signatureApplies(element, compiler)) return;
+ inferrer.updateParameterAssignments(
+ info, element, info.arguments, selector, remove: false,
+ addToQueue: false);
+ }
+
+ visitClosureCallSiteTypeInformation(ClosureCallSiteTypeInformation info) {
+ super.visitClosureCallSiteTypeInformation(info);
+ if (info.closure == currentUser) {
+ analyzeCall(info);
+ } else {
+ bailout('Passed to a closure');
+ }
+ }
+
+ visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) {
+ super.visitStaticCallSiteTypeInformation(info);
+ Element called = info.calledElement;
+ if (called.isForeign(compiler) && called.name == 'JS') {
+ bailout('Used in JS ${info.call}');
+ }
+ if (inferrer.types.getInferredTypeOf(called) == currentUser) {
+ // This node can be a closure call as well. For example, `foo()`
+ // where `foo` is a getter.
+ analyzeCall(info);
+ }
+ }
+
+ bool checkIfCurrentUser(element) {
+ return inferrer.types.getInferredTypeOf(element) == currentUser;
+ }
+
+ visitDynamicCallSiteTypeInformation(DynamicCallSiteTypeInformation info) {
+ super.visitDynamicCallSiteTypeInformation(info);
+ if (info.selector.isCall()) {
+ if (info.arguments.contains(currentUser)
+ && !info.targets.every((element) => element.isFunction())) {
+ bailout('Passed to a closure');
+ } else if (info.targets.any((element) => checkIfCurrentUser(element))) {
+ analyzeCall(info);
+ }
+ }
+ }
+}
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/container_tracer.dart b/sdk/lib/_internal/compiler/implementation/inferrer/container_tracer.dart
deleted file mode 100644
index bc1dc7f..0000000
--- a/sdk/lib/_internal/compiler/implementation/inferrer/container_tracer.dart
+++ /dev/null
@@ -1,404 +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.
-
-part of type_graph_inferrer;
-
-/**
- * A set of selector names that [List] implements, that we know do not
- * change the element type of the list, or let the list escape to code
- * that might change the element type.
- */
-Set<String> okSelectorsSet = new Set<String>.from(
- const <String>[
- // From Object.
- '==',
- 'hashCode',
- 'toString',
- 'noSuchMethod',
- 'runtimeType',
-
- // From Iterable.
- 'iterator',
- 'map',
- 'where',
- 'expand',
- 'contains',
- 'forEach',
- 'reduce',
- 'fold',
- 'every',
- 'join',
- 'any',
- 'toList',
- 'toSet',
- 'length',
- 'isEmpty',
- 'isNotEmpty',
- 'take',
- 'takeWhile',
- 'skip',
- 'skipWhile',
- 'first',
- 'last',
- 'single',
- 'firstWhere',
- 'lastWhere',
- 'singleWhere',
- 'elementAt',
-
- // From List.
- '[]',
- 'length',
- 'reversed',
- 'sort',
- 'indexOf',
- 'lastIndexOf',
- 'clear',
- 'remove',
- 'removeAt',
- 'removeLast',
- 'removeWhere',
- 'retainWhere',
- 'sublist',
- 'getRange',
- 'removeRange',
- 'asMap',
-
- // From JSArray.
- 'checkMutable',
- 'checkGrowable',
- ]);
-
-Set<String> doNotChangeLengthSelectorsSet = new Set<String>.from(
- const <String>[
- // From Object.
- '==',
- 'hashCode',
- 'toString',
- 'noSuchMethod',
- 'runtimeType',
-
- // From Iterable.
- 'iterator',
- 'map',
- 'where',
- 'expand',
- 'contains',
- 'forEach',
- 'reduce',
- 'fold',
- 'every',
- 'join',
- 'any',
- 'toList',
- 'toSet',
- 'length',
- 'isEmpty',
- 'isNotEmpty',
- 'take',
- 'takeWhile',
- 'skip',
- 'skipWhile',
- 'first',
- 'last',
- 'single',
- 'firstWhere',
- 'lastWhere',
- 'singleWhere',
- 'elementAt',
-
- // From List.
- '[]',
- '[]=',
- 'length',
- 'reversed',
- 'sort',
- 'indexOf',
- 'lastIndexOf',
- 'sublist',
- 'getRange',
- 'asMap',
-
- // From JSArray.
- 'checkMutable',
- 'checkGrowable',
- ]);
-
-// A set of selectors we know do not escape the elements inside the
-// list.
-Set<String> doesNotEscapeElementSet = new Set<String>.from(
- const <String>[
- // From Object.
- '==',
- 'hashCode',
- 'toString',
- 'noSuchMethod',
- 'runtimeType',
-
- // From Iterable.
- 'isEmpty',
- 'isNotEmpty',
- 'length',
- 'any',
- 'contains',
- 'every',
- 'join',
-
- // From List.
- 'add',
- 'addAll',
- 'clear',
- 'fillRange',
- 'indexOf',
- 'insert',
- 'insertAll',
- 'lastIndexOf',
- 'remove',
- 'removeRange',
- 'replaceRange',
- 'setAll',
- 'setRange',
- 'shuffle',
- '[]=',
-
- // From JSArray.
- 'checkMutable',
- 'checkGrowable',
- ]);
-
-bool _VERBOSE = false;
-
-class ContainerTracerVisitor implements TypeInformationVisitor {
- final ListTypeInformation container;
- final TypeGraphInferrerEngine inferrer;
- final Compiler compiler;
-
-
- // Work list that gets populated with [TypeInformation] that could
- // contain the container.
- final List<TypeInformation> workList = <TypeInformation>[];
-
- // Work list of containers to analyze after analyzing the users of a
- // [TypeInformation] that may be [container]. We know [container]
- // has been stored in these containers and we must check how
- // [container] escapes from these containers.
- final List<ListTypeInformation> containersToAnalyze =
- <ListTypeInformation>[];
-
- // The current [TypeInformation] in the analysis.
- TypeInformation currentUser;
-
- // The list of found assignments to the container.
- final List<TypeInformation> assignments = <TypeInformation>[];
-
- bool callsGrowableMethod = false;
- bool continueAnalyzing = true;
-
- static const int MAX_ANALYSIS_COUNT = 16;
- final Setlet<Element> analyzedElements = new Setlet<Element>();
-
- ContainerTracerVisitor(this.container, inferrer)
- : this.inferrer = inferrer, this.compiler = inferrer.compiler;
-
- void addNewEscapeInformation(TypeInformation info) {
- if (container.flowsInto.contains(info)) return;
- container.flowsInto.add(info);
- workList.add(info);
- }
-
- List<TypeInformation> run() {
- // Collect the [TypeInformation] where the container can flow in,
- // as well as the operations done on all these [TypeInformation]s.
- addNewEscapeInformation(container);
- while (!workList.isEmpty) {
- currentUser = workList.removeLast();
- currentUser.users.forEach((TypeInformation info) {
- analyzedElements.add(info.owner);
- info.accept(this);
- });
- while (!containersToAnalyze.isEmpty) {
- analyzeStoredIntoContainer(containersToAnalyze.removeLast());
- }
- if (!continueAnalyzing) break;
- if (analyzedElements.length > MAX_ANALYSIS_COUNT) {
- bailout('Too many users');
- break;
- }
- }
-
- if (continueAnalyzing) {
- if (!callsGrowableMethod && container.inferredLength == null) {
- container.inferredLength = container.originalLength;
- }
- return assignments;
- }
- return null;
- }
-
- void bailout(String reason) {
- if (_VERBOSE) {
- ContainerTypeMask mask = container.type;
- print('Bailing out on ${mask.allocationNode} ${mask.allocationElement} '
- 'because: $reason');
- }
- continueAnalyzing = false;
- callsGrowableMethod = true;
- }
-
- visitNarrowTypeInformation(NarrowTypeInformation info) {
- addNewEscapeInformation(info);
- }
-
- visitPhiElementTypeInformation(PhiElementTypeInformation info) {
- addNewEscapeInformation(info);
- }
-
- visitElementInContainerTypeInformation(
- ElementInContainerTypeInformation info) {
- addNewEscapeInformation(info);
- }
-
- visitListTypeInformation(ListTypeInformation info) {
- containersToAnalyze.add(info);
- }
-
- visitMapTypeInformation(MapTypeInformation info) {
- bailout('Stored in a map');
- }
-
- visitConcreteTypeInformation(ConcreteTypeInformation info) {}
-
- visitClosureCallSiteTypeInformation(ClosureCallSiteTypeInformation info) {
- bailout('Passed to a closure');
- }
-
- visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) {
- Element called = info.calledElement;
- if (called.isForeign(compiler) && called.name == 'JS') {
- bailout('Used in JS ${info.call}');
- }
- if (inferrer.types.getInferredTypeOf(called) == currentUser) {
- addNewEscapeInformation(info);
- }
- }
-
- void analyzeStoredIntoContainer(ListTypeInformation container) {
- inferrer.analyzeContainer(container);
- if (container.bailedOut) {
- bailout('Stored in a container that bailed out');
- } else {
- container.flowsInto.forEach((flow) {
- flow.users.forEach((user) {
- if (user is !DynamicCallSiteTypeInformation) return;
- if (user.receiver != flow) return;
- if (returnsElementTypeSet.contains(user.selector)) {
- addNewEscapeInformation(user);
- } else if (!doesNotEscapeElementSet.contains(user.selector.name)) {
- bailout('Escape from a container');
- }
- });
- });
- }
- }
-
- bool isAddedToContainer(DynamicCallSiteTypeInformation info) {
- var receiverType = info.receiver.type;
- if (!receiverType.isContainer) return false;
- String selectorName = info.selector.name;
- List<TypeInformation> arguments = info.arguments.positional;
- return (selectorName == '[]=' && currentUser == arguments[1])
- || (selectorName == 'insert' && currentUser == arguments[0])
- || (selectorName == 'add' && currentUser == arguments[0]);
- }
-
- visitDynamicCallSiteTypeInformation(DynamicCallSiteTypeInformation info) {
- Selector selector = info.selector;
- String selectorName = selector.name;
- if (currentUser == info.receiver) {
- if (!okSelectorsSet.contains(selectorName)) {
- if (selector.isCall()) {
- int positionalLength = info.arguments.positional.length;
- if (selectorName == 'add') {
- if (positionalLength == 1) {
- assignments.add(info.arguments.positional[0]);
- }
- } else if (selectorName == 'insert') {
- if (positionalLength == 2) {
- assignments.add(info.arguments.positional[1]);
- }
- } else {
- bailout('Used in a not-ok selector');
- return;
- }
- } else if (selector.isIndexSet()) {
- assignments.add(info.arguments.positional[1]);
- } else if (!selector.isIndex()) {
- bailout('Used in a not-ok selector');
- return;
- }
- }
- if (!doNotChangeLengthSelectorsSet.contains(selectorName)) {
- callsGrowableMethod = true;
- }
- if (selectorName == 'length' && selector.isSetter()) {
- callsGrowableMethod = true;
- assignments.add(inferrer.types.nullType);
- }
- } else if (selector.isCall()
- && !info.targets.every((element) => element.isFunction())) {
- bailout('Passed to a closure');
- return;
- } else if (isAddedToContainer(info)) {
- ContainerTypeMask mask = info.receiver.type;
- if (mask.allocationNode != null) {
- ListTypeInformation container =
- inferrer.types.allocatedLists[mask.allocationNode];
- containersToAnalyze.add(container);
- } else {
- // The [ContainerTypeMask] is a union of two containers, and
- // we lose track of where these containers have been allocated
- // at this point.
- bailout('Stored in too many containers');
- }
- }
-
- if (info.targets
- .map((element) => inferrer.types.getInferredTypeOf(element))
- .any((other) => other == currentUser)) {
- addNewEscapeInformation(info);
- }
- }
-
- bool isClosure(Element element) {
- if (!element.isFunction()) return false;
- Element outermost = element.getOutermostEnclosingMemberOrTopLevel();
- return outermost.declaration != element.declaration;
- }
-
- bool isParameterOfListAddingMethod(Element element) {
- if (!element.isParameter()) return false;
- if (element.getEnclosingClass() != compiler.backend.listImplementation) {
- return false;
- }
- Element method = element.enclosingElement;
- return (method.name == '[]=')
- || (method.name == 'add')
- || (method.name == 'insert');
- }
-
- visitElementTypeInformation(ElementTypeInformation info) {
- if (isClosure(info.element)) {
- bailout('Returned from a closure');
- }
- if (compiler.backend.isNeededForReflection(info.element)) {
- bailout('Escape in reflection');
- }
- if (isParameterOfListAddingMethod(info.element)) {
- // These elements are being handled in
- // [visitDynamicCallSiteTypeInformation].
- return;
- }
- addNewEscapeInformation(info);
- }
-}
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/inferrer_visitor.dart b/sdk/lib/_internal/compiler/implementation/inferrer/inferrer_visitor.dart
index 7db8c95..6890de7 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/inferrer_visitor.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/inferrer_visitor.dart
@@ -49,6 +49,8 @@
T allocateMap(T keyType, T valueType, T type);
+ T allocateClosure(Node node, Element element);
+
/**
* Returns the least upper bound between [firstType] and
* [secondType].
@@ -271,6 +273,10 @@
bool every(bool f(T type)) {
return positional.every(f) && named.values.every(f);
}
+
+ bool contains(T type) {
+ return positional.contains(type) || named.containsValue(type);
+ }
}
abstract class MinimalInferrerEngine<T> {
@@ -734,6 +740,11 @@
return thisType;
} else if (node.isSuper()) {
return superType;
+ } else {
+ Element element = elements[node];
+ if (Elements.isLocal(element)) {
+ return locals.use(element);
+ }
}
}
@@ -847,6 +858,9 @@
|| '!==' == op.source) {
node.visitChildren(this);
return types.boolType;
+ } else if ('!=' == op.source) {
+ visitDynamicSend(node);
+ return types.boolType;
} else {
// Binary operator.
return visitDynamicSend(node);
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/list_tracer.dart b/sdk/lib/_internal/compiler/implementation/inferrer/list_tracer.dart
new file mode 100644
index 0000000..1d2d063
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/list_tracer.dart
@@ -0,0 +1,207 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of type_graph_inferrer;
+
+/**
+ * A set of selector names that [List] implements, that we know do not
+ * change the element type of the list, or let the list escape to code
+ * that might change the element type.
+ */
+Set<String> okSelectorsSet = new Set<String>.from(
+ const <String>[
+ // From Object.
+ '==',
+ 'hashCode',
+ 'toString',
+ 'noSuchMethod',
+ 'runtimeType',
+
+ // From Iterable.
+ 'iterator',
+ 'map',
+ 'where',
+ 'expand',
+ 'contains',
+ 'forEach',
+ 'reduce',
+ 'fold',
+ 'every',
+ 'join',
+ 'any',
+ 'toList',
+ 'toSet',
+ 'length',
+ 'isEmpty',
+ 'isNotEmpty',
+ 'take',
+ 'takeWhile',
+ 'skip',
+ 'skipWhile',
+ 'first',
+ 'last',
+ 'single',
+ 'firstWhere',
+ 'lastWhere',
+ 'singleWhere',
+ 'elementAt',
+
+ // From List.
+ '[]',
+ 'length',
+ 'reversed',
+ 'sort',
+ 'indexOf',
+ 'lastIndexOf',
+ 'clear',
+ 'remove',
+ 'removeAt',
+ 'removeLast',
+ 'removeWhere',
+ 'retainWhere',
+ 'sublist',
+ 'getRange',
+ 'removeRange',
+ 'asMap',
+
+ // From JSArray.
+ 'checkMutable',
+ 'checkGrowable',
+ ]);
+
+Set<String> doNotChangeLengthSelectorsSet = new Set<String>.from(
+ const <String>[
+ // From Object.
+ '==',
+ 'hashCode',
+ 'toString',
+ 'noSuchMethod',
+ 'runtimeType',
+
+ // From Iterable.
+ 'iterator',
+ 'map',
+ 'where',
+ 'expand',
+ 'contains',
+ 'forEach',
+ 'reduce',
+ 'fold',
+ 'every',
+ 'join',
+ 'any',
+ 'toList',
+ 'toSet',
+ 'length',
+ 'isEmpty',
+ 'isNotEmpty',
+ 'take',
+ 'takeWhile',
+ 'skip',
+ 'skipWhile',
+ 'first',
+ 'last',
+ 'single',
+ 'firstWhere',
+ 'lastWhere',
+ 'singleWhere',
+ 'elementAt',
+
+ // From List.
+ '[]',
+ '[]=',
+ 'length',
+ 'reversed',
+ 'sort',
+ 'indexOf',
+ 'lastIndexOf',
+ 'sublist',
+ 'getRange',
+ 'asMap',
+
+ // From JSArray.
+ 'checkMutable',
+ 'checkGrowable',
+ ]);
+
+
+class ListTracerVisitor extends TracerVisitor {
+ // The list of found assignments to the container.
+ final List<TypeInformation> assignments = <TypeInformation>[];
+ bool callsGrowableMethod = false;
+
+ ListTracerVisitor(tracedType, inferrer) : super(tracedType, inferrer);
+
+ List<TypeInformation> run() {
+ analyze();
+ ListTypeInformation container = tracedType;
+ if (continueAnalyzing) {
+ if (!callsGrowableMethod && container.inferredLength == null) {
+ container.inferredLength = container.originalLength;
+ }
+ container.flowsInto.addAll(flowsInto);
+ return assignments;
+ } else {
+ callsGrowableMethod = true;
+ return null;
+ }
+ }
+
+ visitMapTypeInformation(MapTypeInformation info) {
+ bailout('Stored in a map');
+ }
+
+ visitClosureCallSiteTypeInformation(ClosureCallSiteTypeInformation info) {
+ bailout('Passed to a closure');
+ }
+
+ visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) {
+ super.visitStaticCallSiteTypeInformation(info);
+ Element called = info.calledElement;
+ if (called.isForeign(compiler) && called.name == 'JS') {
+ bailout('Used in JS ${info.call}');
+ }
+ }
+
+ visitDynamicCallSiteTypeInformation(DynamicCallSiteTypeInformation info) {
+ super.visitDynamicCallSiteTypeInformation(info);
+ Selector selector = info.selector;
+ String selectorName = selector.name;
+ if (currentUser == info.receiver) {
+ if (!okSelectorsSet.contains(selectorName)) {
+ if (selector.isCall()) {
+ int positionalLength = info.arguments.positional.length;
+ if (selectorName == 'add') {
+ if (positionalLength == 1) {
+ assignments.add(info.arguments.positional[0]);
+ }
+ } else if (selectorName == 'insert') {
+ if (positionalLength == 2) {
+ assignments.add(info.arguments.positional[1]);
+ }
+ } else {
+ bailout('Used in a not-ok selector');
+ return;
+ }
+ } else if (selector.isIndexSet()) {
+ assignments.add(info.arguments.positional[1]);
+ } else if (!selector.isIndex()) {
+ bailout('Used in a not-ok selector');
+ return;
+ }
+ }
+ if (!doNotChangeLengthSelectorsSet.contains(selectorName)) {
+ callsGrowableMethod = true;
+ }
+ if (selectorName == 'length' && selector.isSetter()) {
+ callsGrowableMethod = true;
+ assignments.add(inferrer.types.nullType);
+ }
+ } else if (selector.isCall()
+ && !info.targets.every((element) => element.isFunction())) {
+ bailout('Passed to a closure');
+ return;
+ }
+ }
+}
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/node_tracer.dart b/sdk/lib/_internal/compiler/implementation/inferrer/node_tracer.dart
new file mode 100644
index 0000000..380a472
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/node_tracer.dart
@@ -0,0 +1,235 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of type_graph_inferrer;
+
+// A set of selectors we know do not escape the elements inside the
+// list.
+Set<String> doesNotEscapeElementSet = new Set<String>.from(
+ const <String>[
+ // From Object.
+ '==',
+ 'hashCode',
+ 'toString',
+ 'noSuchMethod',
+ 'runtimeType',
+
+ // From Iterable.
+ 'isEmpty',
+ 'isNotEmpty',
+ 'length',
+ 'any',
+ 'contains',
+ 'every',
+ 'join',
+
+ // From List.
+ 'add',
+ 'addAll',
+ 'clear',
+ 'fillRange',
+ 'indexOf',
+ 'insert',
+ 'insertAll',
+ 'lastIndexOf',
+ 'remove',
+ 'removeRange',
+ 'replaceRange',
+ 'setAll',
+ 'setRange',
+ 'shuffle',
+ '[]=',
+
+ // From JSArray.
+ 'checkMutable',
+ 'checkGrowable',
+ ]);
+
+abstract class TracerVisitor implements TypeInformationVisitor {
+ final TypeInformation tracedType;
+ final TypeGraphInferrerEngine inferrer;
+ final Compiler compiler;
+
+ static const int MAX_ANALYSIS_COUNT = 16;
+ final Setlet<Element> analyzedElements = new Setlet<Element>();
+
+ TracerVisitor(this.tracedType, inferrer)
+ : this.inferrer = inferrer, this.compiler = inferrer.compiler;
+
+ // Work list that gets populated with [TypeInformation] that could
+ // contain the container.
+ final List<TypeInformation> workList = <TypeInformation>[];
+
+ // Work list of containers to analyze after analyzing the users of a
+ // [TypeInformation] that may be [container]. We know [container]
+ // has been stored in these containers and we must check how
+ // [container] escapes from these containers.
+ final List<ListTypeInformation> containersToAnalyze =
+ <ListTypeInformation>[];
+
+ final Setlet<TypeInformation> flowsInto = new Setlet<TypeInformation>();
+
+ // The current [TypeInformation] in the analysis.
+ TypeInformation currentUser;
+ bool continueAnalyzing = true;
+
+ void addNewEscapeInformation(TypeInformation info) {
+ if (flowsInto.contains(info)) return;
+ flowsInto.add(info);
+ workList.add(info);
+ }
+
+ void analyze() {
+ // Collect the [TypeInformation] where the container can flow in,
+ // as well as the operations done on all these [TypeInformation]s.
+ addNewEscapeInformation(tracedType);
+ while (!workList.isEmpty) {
+ currentUser = workList.removeLast();
+ currentUser.users.forEach((TypeInformation info) {
+ analyzedElements.add(info.owner);
+ info.accept(this);
+ });
+ while (!containersToAnalyze.isEmpty) {
+ analyzeStoredIntoContainer(containersToAnalyze.removeLast());
+ }
+ if (!continueAnalyzing) break;
+ if (analyzedElements.length > MAX_ANALYSIS_COUNT) {
+ bailout('Too many users');
+ break;
+ }
+ }
+ }
+
+ void bailout(String reason) {
+ if (_VERBOSE) {
+ print('Bailing out on $tracedType because: $reason');
+ }
+ continueAnalyzing = false;
+ }
+
+ void visitNarrowTypeInformation(NarrowTypeInformation info) {
+ addNewEscapeInformation(info);
+ }
+
+ void visitPhiElementTypeInformation(PhiElementTypeInformation info) {
+ addNewEscapeInformation(info);
+ }
+
+ void visitElementInContainerTypeInformation(
+ ElementInContainerTypeInformation info) {
+ addNewEscapeInformation(info);
+ }
+
+ visitListTypeInformation(ListTypeInformation info) {
+ containersToAnalyze.add(info);
+ }
+
+ void visitConcreteTypeInformation(ConcreteTypeInformation info) {}
+
+ void visitClosureTypeInformation(ClosureTypeInformation info) {}
+
+ void visitClosureCallSiteTypeInformation(
+ ClosureCallSiteTypeInformation info) {}
+
+ visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info) {
+ Element called = info.calledElement;
+ if (inferrer.types.getInferredTypeOf(called) == currentUser) {
+ addNewEscapeInformation(info);
+ }
+ }
+
+ void analyzeStoredIntoContainer(ListTypeInformation container) {
+ inferrer.analyzeContainer(container);
+ if (container.bailedOut) {
+ bailout('Stored in a container that bailed out');
+ } else {
+ container.flowsInto.forEach((flow) {
+ flow.users.forEach((user) {
+ if (user is !DynamicCallSiteTypeInformation) return;
+ if (user.receiver != flow) return;
+ if (returnsElementTypeSet.contains(user.selector)) {
+ addNewEscapeInformation(user);
+ } else if (!doesNotEscapeElementSet.contains(user.selector.name)) {
+ bailout('Escape from a container');
+ }
+ });
+ });
+ }
+ }
+
+ bool isAddedToContainer(DynamicCallSiteTypeInformation info) {
+ if (info.arguments == null) return false;
+ var receiverType = info.receiver.type;
+ if (!receiverType.isContainer) return false;
+ String selectorName = info.selector.name;
+ List<TypeInformation> arguments = info.arguments.positional;
+ return (selectorName == '[]=' && currentUser == arguments[1])
+ || (selectorName == 'insert' && currentUser == arguments[0])
+ || (selectorName == 'add' && currentUser == arguments[0]);
+ }
+
+ void visitDynamicCallSiteTypeInformation(
+ DynamicCallSiteTypeInformation info) {
+ if (isAddedToContainer(info)) {
+ ContainerTypeMask mask = info.receiver.type;
+ if (mask.allocationNode != null) {
+ ListTypeInformation container =
+ inferrer.types.allocatedLists[mask.allocationNode];
+ containersToAnalyze.add(container);
+ } else {
+ // The [ContainerTypeMask] is a union of two containers, and
+ // we lose track of where these containers have been allocated
+ // at this point.
+ bailout('Stored in too many containers');
+ }
+ }
+
+ Iterable<Element> inferredTargetTypes = info.targets.map((element) {
+ return inferrer.types.getInferredTypeOf(element);
+ });
+ if (inferredTargetTypes.any((user) => user == currentUser)) {
+ addNewEscapeInformation(info);
+ }
+ }
+
+ bool isParameterOfListAddingMethod(Element element) {
+ if (!element.isParameter()) return false;
+ if (element.getEnclosingClass() != compiler.backend.listImplementation) {
+ return false;
+ }
+ Element method = element.enclosingElement;
+ return (method.name == '[]=')
+ || (method.name == 'add')
+ || (method.name == 'insert');
+ }
+
+ bool isClosure(Element element) {
+ if (!element.isFunction()) return false;
+ Element outermost = element.getOutermostEnclosingMemberOrTopLevel();
+ return outermost.declaration != element.declaration;
+ }
+
+ void visitElementTypeInformation(ElementTypeInformation info) {
+ Element element = info.element;
+ if (element.isParameter()
+ && inferrer.isNativeElement(element.enclosingElement)) {
+ bailout('Passed to a native method');
+ }
+ if (info.isClosurized()) {
+ bailout('Returned from a closurized method');
+ }
+ if (isClosure(info.element)) {
+ bailout('Returned from a closure');
+ }
+ if (compiler.backend.isNeededForReflection(info.element)) {
+ bailout('Escape in reflection');
+ }
+ if (isParameterOfListAddingMethod(info.element)) {
+ // These elements are being handled in
+ // [visitDynamicCallSiteTypeInformation].
+ return;
+ }
+ addNewEscapeInformation(info);
+ }
+}
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/simple_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/inferrer/simple_types_inferrer.dart
index 29c46fa..b54ae28 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/simple_types_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/simple_types_inferrer.dart
@@ -111,6 +111,10 @@
return type;
}
+ TypeMask allocateClosure(Node node, Element element) {
+ return functionType;
+ }
+
Selector newTypedSelector(TypeMask receiver, Selector selector) {
return new TypedSelector(receiver, selector);
}
@@ -566,10 +570,7 @@
// Record the types of captured non-boxed variables. Types of
// these variables may already be there, because of an analysis of
- // a previous closure. Note that analyzing the same closure multiple
- // times closure will refine the type of those variables, therefore
- // [:inferrer.typeOf[variable]:] is not necessarilly null, nor the
- // same as [newType].
+ // a previous closure.
ClosureClassMap nestedClosureData =
compiler.closureToClassMapper.getMappingForNestedFunction(node);
nestedClosureData.forEachCapturedVariable((variable, field) {
@@ -584,7 +585,19 @@
capturedVariables.add(variable);
});
- return types.functionType;
+ return inferrer.concreteTypes.putIfAbsent(node, () {
+ return types.allocateClosure(node, element);
+ });
+ }
+
+ T visitFunctionDeclaration(FunctionDeclaration node) {
+ Element element = elements[node];
+ T type = inferrer.concreteTypes.putIfAbsent(node.function, () {
+ return types.allocateClosure(node.function, element);
+ });
+ locals.update(element, type, node);
+ visit(node.function);
+ return type;
}
T visitLiteralList(LiteralList node) {
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_inferrer.dart b/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_inferrer.dart
index c31b2c0..6f17205 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_inferrer.dart
@@ -20,7 +20,11 @@
import '../dart2jslib.dart' show invariant, Constant;
part 'type_graph_nodes.dart';
-part 'container_tracer.dart';
+part 'closure_tracer.dart';
+part 'list_tracer.dart';
+part 'node_tracer.dart';
+
+bool _VERBOSE = false;
/**
* A set of selector names that [List] implements, that we know return
@@ -55,6 +59,10 @@
final Map<Node, TypeInformation> allocatedLists =
new Map<Node, TypeInformation>();
+ /// [ClosureTypeInformation] for allocated closures.
+ final Map<Node, TypeInformation> allocatedClosures =
+ new Map<Node, TypeInformation>();
+
/// Cache of [ConcreteTypeInformation].
final Map<TypeMask, TypeInformation> concreteTypes =
new Map<TypeMask, TypeInformation>();
@@ -298,6 +306,11 @@
new ListTypeInformation(mask, element, length);
}
+ TypeInformation allocateClosure(Node node, Element element) {
+ return allocatedClosures[node] =
+ new ClosureTypeInformation(node, element);
+ }
+
TypeInformation allocateMap(TypeInformation keyType,
TypeInformation valueType,
ConcreteTypeInformation type) {
@@ -406,12 +419,6 @@
* [TypeInformation] nodes by visiting the AST of the application, and
* then does the inferencing on the graph.
*
- * The inferencing is currently done in three steps:
- *
- * 1) Compute the call graph.
- * 2) Refine all nodes in a way that avoids cycles.
- * 3) Refine all nodes.
- *
*/
class TypeGraphInferrerEngine
extends InferrerEngine<TypeInformation, TypeInformationSystem> {
@@ -437,7 +444,7 @@
void analyzeContainer(ListTypeInformation info) {
if (info.analyzed) return;
info.analyzed = true;
- ContainerTracerVisitor tracer = new ContainerTracerVisitor(info, this);
+ ListTracerVisitor tracer = new ListTracerVisitor(info, this);
List<TypeInformation> newAssignments = tracer.run();
if (newAssignments == null) {
return;
@@ -479,6 +486,16 @@
workQueue.add(info.elementType);
});
+ types.allocatedClosures.values.forEach((ClosureTypeInformation info) {
+ ClosureTracerVisitor tracer = new ClosureTracerVisitor(info, this);
+ tracer.run();
+ if (!tracer.continueAnalyzing) return;
+ FunctionElement element = info.element;
+ element.functionSignature.forEachParameter((parameter) {
+ workQueue.add(types.getInferredTypeOf(parameter));
+ });
+ });
+
// Reset all nodes that use lists that have been inferred, as well
// as nodes that use elements fetched from these lists. The
// workset for a new run of the analysis will be these nodes.
@@ -609,6 +626,7 @@
void buildWorkQueue() {
workQueue.addAll(types.typeInformations.values);
workQueue.addAll(types.allocatedTypes);
+ workQueue.addAll(types.allocatedClosures.values);
workQueue.addAll(allocatedCalls);
}
@@ -621,7 +639,7 @@
Element callee,
ArgumentsTypes arguments,
Selector selector,
- {bool remove, bool init: false}) {
+ {bool remove, bool addToQueue: true}) {
if (callee.name == Compiler.NO_SUCH_METHOD) return;
if (callee.isField()) {
if (selector.isSetter()) {
@@ -631,18 +649,22 @@
} else {
info.addAssignment(arguments.positional[0]);
}
- if (!init) workQueue.add(info);
+ if (addToQueue) workQueue.add(info);
}
} else if (callee.isGetter()) {
return;
} else if (selector != null && selector.isGetter()) {
- if (!remove) {
+ ElementTypeInformation info = types.getInferredTypeOf(callee);
+ if (remove) {
+ info.closurizedCount--;
+ } else {
+ info.closurizedCount++;
FunctionElement function = callee.implementation;
FunctionSignature signature = function.computeSignature(compiler);
signature.forEachParameter((Element parameter) {
ElementTypeInformation info = types.getInferredTypeOf(parameter);
info.giveUp(this);
- if (!init) workQueue.addAll(info.users);
+ if (addToQueue) workQueue.addAll(info.users);
});
}
} else {
@@ -669,7 +691,7 @@
info.addAssignment(type);
}
parameterIndex++;
- if (!init) workQueue.add(info);
+ if (addToQueue) workQueue.add(info);
});
}
}
@@ -813,7 +835,7 @@
}
// Sorts the resolved elements by size. We do this for this inferrer
- // to get the same results for [ContainerTracer] compared to the
+ // to get the same results for [ListTracer] compared to the
// [SimpleTypesInferrer].
Iterable<Element> sortResolvedElements() {
int max = 0;
@@ -856,6 +878,7 @@
types.typeInformations.values.forEach((info) => info.clear());
types.allocatedTypes.clear();
types.concreteTypes.clear();
+ types.allocatedClosures.clear();
analyzedElements.clear();
generativeConstructorsExposingThis.clear();
}
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_nodes.dart b/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_nodes.dart
index 3f4dc37..fa0082a 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/type_graph_nodes.dart
@@ -92,13 +92,13 @@
return type;
}
- void giveUp(TypeGraphInferrerEngine inferrer) {
+ void giveUp(TypeGraphInferrerEngine inferrer, {bool clearAssignments: true}) {
abandonInferencing = true;
type = inferrer.types.dynamicType.type;
// Do not remove [this] as a user of nodes in [assignments],
// because our tracing analysis could be interested in tracing
// this node.
- assignments = const <TypeInformation>[];
+ if (clearAssignments) assignments = const <TypeInformation>[];
// Do not remove users because our tracing analysis could be
// interested in tracing the users of this node.
}
@@ -209,6 +209,16 @@
class ElementTypeInformation extends TypeInformation {
final Element element;
+ // Marker to disable [handleSpecialCases]. For example, parameters
+ // of closures that are traced can be inferred.
+ bool disableHandleSpecialCases = false;
+
+ /**
+ * If [element] is a function, [closurizedCount] is the number of
+ * times it is closurized. The value gets updated while infering.
+ */
+ int closurizedCount = 0;
+
/**
* This map contains the callers of [element]. It stores all unique call sites
* to enable counting the global number of call sites of [element].
@@ -256,15 +266,19 @@
return count == 1;
}
+ bool isClosurized() => closurizedCount > 0;
+
TypeMask handleSpecialCases(TypeGraphInferrerEngine inferrer) {
- if (abandonInferencing) {
- return type;
- }
+ if (abandonInferencing) return type;
+ if (disableHandleSpecialCases) return null;
+
if (element.isParameter()) {
Element enclosing = element.enclosingElement;
if (Elements.isLocal(enclosing)) {
- // Do not infer types for parameters of closures.
- giveUp(inferrer);
+ // Do not infer types for parameters of closures. We do not
+ // clear the assignments in case the closure is successfully
+ // traced.
+ giveUp(inferrer, clearAssignments: false);
return type;
} else if (enclosing.isInstanceMember()
&& (enclosing.name == Compiler.NO_SUCH_METHOD
@@ -433,7 +447,8 @@
arguments.forEach((info) => info.addUser(this));
}
inferrer.updateParameterAssignments(
- this, calledElement, arguments, selector, remove: false, init: true);
+ this, calledElement, arguments, selector, remove: false,
+ addToQueue: false);
}
bool get isSynthesized {
@@ -502,7 +517,8 @@
callee.addCall(caller, call);
callee.addUser(this);
inferrer.updateParameterAssignments(
- this, element, arguments, typedSelector, remove: false, init: true);
+ this, element, arguments, typedSelector, remove: false,
+ addToQueue: false);
}
}
@@ -626,7 +642,8 @@
callee.addCall(caller, call);
callee.addUser(this);
inferrer.updateParameterAssignments(
- this, element, arguments, typedSelector, remove: false);
+ this, element, arguments, typedSelector, remove: false,
+ addToQueue: true);
}
// If [canReachAll] is true, then we are iterating over all
@@ -658,14 +675,15 @@
callee.removeCall(caller, call);
callee.removeUser(this);
inferrer.updateParameterAssignments(
- this, element, arguments, typedSelector, remove: true);
+ this, element, arguments, typedSelector, remove: true,
+ addToQueue: true);
}
});
return newType;
}
- void giveUp(TypeGraphInferrerEngine inferrer) {
+ void giveUp(TypeGraphInferrerEngine inferrer, {bool clearAssignments: true}) {
inferrer.updateSelectorInTree(caller, call, selector);
Iterable<Element> oldTargets = targets;
targets = inferrer.compiler.world.allFunctions.filter(selector);
@@ -675,10 +693,11 @@
inferrer.types.getInferredTypeOf(element);
callee.addCall(caller, call);
inferrer.updateParameterAssignments(
- this, element, arguments, selector, remove: false);
+ this, element, arguments, selector, remove: false,
+ addToQueue: true);
}
}
- super.giveUp(inferrer);
+ super.giveUp(inferrer, clearAssignments: clearAssignments);
}
void removeAndClearReferences(TypeGraphInferrerEngine inferrer) {
@@ -720,6 +739,7 @@
void addToGraph(TypeGraphInferrerEngine inferrer) {
arguments.forEach((info) => info.addUser(this));
+ closure.addUser(this);
}
TypeMask refine(TypeGraphInferrerEngine inferrer) {
@@ -975,6 +995,27 @@
}
}
+class ClosureTypeInformation extends TypeInformation {
+ final Node node;
+ final Element element;
+
+ ClosureTypeInformation(this.node, this.element);
+
+ TypeMask refine(TypeGraphInferrerEngine inferrer) {
+ return inferrer.types.functionType.type;
+ }
+
+ String toString() => 'Closure $element';
+
+ accept(TypeInformationVisitor visitor) {
+ return visitor.visitClosureTypeInformation(this);
+ }
+
+ bool hasStableType(TypeGraphInferrerEngine inferrer) {
+ return false;
+ }
+}
+
abstract class TypeInformationVisitor<T> {
T visitNarrowTypeInformation(NarrowTypeInformation info);
T visitPhiElementTypeInformation(PhiElementTypeInformation info);
@@ -987,4 +1028,5 @@
T visitStaticCallSiteTypeInformation(StaticCallSiteTypeInformation info);
T visitDynamicCallSiteTypeInformation(DynamicCallSiteTypeInformation info);
T visitElementTypeInformation(ElementTypeInformation info);
+ T visitClosureTypeInformation(ClosureTypeInformation info);
}
diff --git a/sdk/lib/_internal/compiler/implementation/ir/ir_builder.dart b/sdk/lib/_internal/compiler/implementation/ir/ir_builder.dart
index 0a747e5..925841e 100644
--- a/sdk/lib/_internal/compiler/implementation/ir/ir_builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/ir/ir_builder.dart
@@ -83,6 +83,7 @@
unlinkTreeAndToken(element);
}
}
+ ensureIr(element);
});
});
}
@@ -114,15 +115,69 @@
// TODO(lry): support native functions (also in [visitReturn]).
if (function.isNative()) return false;
+ // Methods annotated @IrRepresentation(false).
+ if (enforceAstRepresentation(function)) return false;
+
return true;
}
+ bool get inCheckedMode {
+ bool result = false;
+ assert((result = true));
+ return result;
+ }
+
+ bool enforceAstRepresentation(Element element) {
+ return irRepresentationValue(element, false);
+ }
+
+ bool enforceIrRepresentation(Element element) {
+ return irRepresentationValue(element, true);
+ }
+
+ /**
+ * In host-checked mode, the @IrRepresentation annotation can be used to
+ * enforce the internal representation of a function.
+ */
+ bool irRepresentationValue(Element element, bool expected) {
+ if (!inCheckedMode || compiler.backend is !JavaScriptBackend) return false;
+ JavaScriptBackend backend = compiler.backend;
+ for (MetadataAnnotation metadata in element.metadata) {
+ if (metadata.value == null ||
+ !metadata.value.isConstructedObject()) {
+ continue;
+ }
+ ObjectConstant value = metadata.value;
+ ClassElement cls = value.type.element;
+ if (cls == backend.irRepresentationClass) {
+ ConstructedConstant classConstant = value;
+ BoolConstant constant = classConstant.fields[0];
+ return constant.value == expected;
+ }
+ }
+ return false;
+ }
+
+ void ensureIr(Element element) {
+ // If no IR was built for [element], ensure it is not annotated
+ // @IrRepresentation(true).
+ if (inCheckedMode &&
+ !compiler.irBuilder.hasIr(element) &&
+ enforceIrRepresentation(element)) {
+ compiler.reportFatalError(
+ element,
+ MessageKind.GENERIC,
+ {'text': "Error: cannot build IR for $element."});
+ }
+ }
+
void unlinkTreeAndToken(element) {
- // Ensure the funciton signature has been computed (requires the AST).
+ // Ensure the function signature has been computed (requires the AST).
assert(element is !FunctionElementX || element.functionSignature != null);
- element.beginToken.next = null;
- // TODO(lry): Mark [element] so that parseNode will fail an assertion.
- // element.cachedNode = null;
+ if (inCheckedMode) {
+ element.beginToken.next = null;
+ element.cachedNode = null;
+ }
}
SourceFile elementSourceFile(Element element) {
diff --git a/sdk/lib/_internal/compiler/implementation/ir/ir_nodes.dart b/sdk/lib/_internal/compiler/implementation/ir/ir_nodes.dart
index 1aeeca8..dfdadaf 100644
--- a/sdk/lib/_internal/compiler/implementation/ir/ir_nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/ir/ir_nodes.dart
@@ -94,6 +94,15 @@
accept(IrNodesVisitor visitor) => visitor.visitIrInvokeStatic(this);
}
+/**
+ * This class is only used during SSA generation, its instances never appear in
+ * the representation of a function. See [SsaFromAstInliner.enterInlinedMethod].
+ */
+class IrInlinedInvocationDummy extends IrExpression {
+ IrInlinedInvocationDummy() : super(0);
+ accept(IrNodesVisitor visitor) => throw "IrInlinedInvocationDummy.accept";
+}
+
abstract class IrNodesVisitor<T> {
T visit(IrNode node) => node.accept(this);
diff --git a/sdk/lib/_internal/compiler/implementation/ir/ir_pickler.dart b/sdk/lib/_internal/compiler/implementation/ir/ir_pickler.dart
index 317940c..bd79382 100644
--- a/sdk/lib/_internal/compiler/implementation/ir/ir_pickler.dart
+++ b/sdk/lib/_internal/compiler/implementation/ir/ir_pickler.dart
@@ -8,7 +8,8 @@
import '../dart2jslib.dart' show
Constant, FalseConstant, TrueConstant, IntConstant, DoubleConstant,
StringConstant, NullConstant, ListConstant, MapConstant,
- InterceptorConstant, FunctionConstant, TypeConstant, ConstructedConstant,
+ InterceptorConstant, DummyReceiverConstant, FunctionConstant, TypeConstant,
+ ConstructedConstant,
ConstantVisitor, ConstantSystem,
Compiler;
import 'dart:typed_data' show ByteData, Endianness, Uint8List;
@@ -18,7 +19,7 @@
ConsDartString;
import '../elements/elements.dart' show
Element, LibraryElement, FunctionElement;
-import '../universe/universe.dart' show Selector;
+import '../universe/universe.dart' show Selector, TypedSelector, SelectorKind;
part 'ir_unpickler.dart';
@@ -36,8 +37,8 @@
* int(namePosition) int(statements) {node(statement)}
* | byte(NODE_RETURN) position reference(value)
* | byte(NODE_CONST) position constant
- * | byte(NODE_INVOKE_STATIC) position element int(arguments)
- * {reference(argument)}
+ * | byte(NODE_INVOKE_STATIC) position element selector
+ * int(arguments) {reference(argument)}
*
* reference ::= int(indexDelta)
*
@@ -53,10 +54,17 @@
* | byte(CONST_STRING_CONS) constant(left) constant(right)
* | byte(CONST_NULL)
*
+ * selector ::= byte(BACKREFERENCE) reference
+ * | byte(SELECTOR_UNTYPED) int(kind) string(name) element(library)
+ * int(argumentsCount) int(namedArgumentsCount)
+ * {string(parameterName)}
+ *
* element ::= int(constantPoolIndex)
*/
class Pickles {
- static const int STRING_ASCII = 1;
+ static const int BACKREFERENCE = 1;
+
+ static const int STRING_ASCII = BACKREFERENCE + 1;
static const int STRING_UTF8 = STRING_ASCII + 1;
static const int BEGIN_STATEMENT_NODE = STRING_UTF8 + 1;
@@ -85,11 +93,31 @@
static const int CONST_NULL = CONST_STRING_CONS + 1;
static const int END_CONST = CONST_NULL;
- static const int END_TAG = END_CONST;
+ static const int BEGIN_SELECTOR = END_CONST + 1;
+ static const int SELECTOR_UNTYPED = BEGIN_SELECTOR;
+ static const int END_SELECTOR = SELECTOR_UNTYPED + 1;
+
+ static const int END_TAG = END_SELECTOR;
static bool isExpressionTag(int tag) {
return BEGIN_EXPRESSION_NODE <= tag && tag <= END_EXPRESSION_NODE;
}
+
+ static final List<SelectorKind> selectorKindFromId = _selectorKindFromId();
+
+ static List<SelectorKind> _selectorKindFromId() {
+ List<SelectorKind> result = <SelectorKind>[
+ SelectorKind.GETTER,
+ SelectorKind.SETTER,
+ SelectorKind.CALL,
+ SelectorKind.OPERATOR,
+ SelectorKind.INDEX];
+ for (int i = 0; i < result.length; i++) {
+ assert(result[i].hashCode == i);
+ }
+ return result;
+ }
+
}
class IrConstantPool {
@@ -254,21 +282,21 @@
}
/**
- * This function records [IrExpression] nodes in the [emitted] table. It
- * needs to be invoked for each visited expression node to enable pickling
- * back references to the node in [writeBackReference].
+ * This function records [entry] in the [emitted] table. It needs to be
+ * invoked when pickling an object which might later on be used in a back
+ * reference, for example expression nodes or selectors.
*/
- void recordForBackReference(IrExpression entry) {
+ void recordForBackReference(Object entry) {
assert(emitted[entry] == null);
emitted[entry] = index++;
}
- void writeBackReference(IrExpression entry) {
+ void writeBackReference(Object entry) {
int entryIndex = emitted[entry];
writeInt(index - entryIndex);
}
- void writeBackReferenceList(List<IrExpression> entries) {
+ void writeBackReferenceList(List entries) {
writeInt(entries.length);
for (int i = 0; i < entries.length; i++) {
writeBackReference(entries[i]);
@@ -335,7 +363,23 @@
}
void writeSelector(Selector selector) {
- writeInt(constantPool.add(selector));
+ if (emitted.containsKey(selector)) {
+ writeByte(Pickles.BACKREFERENCE);
+ writeBackReference(selector);
+ } else {
+ recordForBackReference(selector);
+ assert(selector is !TypedSelector);
+ writeByte(Pickles.SELECTOR_UNTYPED);
+ writeInt(selector.kind.hashCode);
+ writeString(selector.name);
+ writeElement(selector.library);
+ writeInt(selector.argumentCount);
+ int namedArgumentsCount = selector.namedArguments.length;
+ writeInt(namedArgumentsCount);
+ for (int i = 0; i < namedArgumentsCount; i++) {
+ writeString(selector.namedArguments[i]);
+ }
+ }
}
void writeNodeList(List<IrNode> nodes) {
@@ -418,6 +462,7 @@
void visitList(ListConstant constant) => abort(constant);
void visitMap(MapConstant constant) => abort(constant);
void visitInterceptor(InterceptorConstant constant) => abort(constant);
+ void visitDummyReceiver(DummyReceiverConstant constant) => abort(constant);
void visitFunction(FunctionConstant constant) => abort(constant);
void visitType(TypeConstant constant) => abort(constant);
void visitConstructed(ConstructedConstant constant) => abort(constant);
diff --git a/sdk/lib/_internal/compiler/implementation/ir/ir_unpickler.dart b/sdk/lib/_internal/compiler/implementation/ir/ir_unpickler.dart
index 6f70d59..04190e6 100644
--- a/sdk/lib/_internal/compiler/implementation/ir/ir_unpickler.dart
+++ b/sdk/lib/_internal/compiler/implementation/ir/ir_unpickler.dart
@@ -35,7 +35,7 @@
int numEntries = readInt();
unpickled = new List<Object>(numEntries);
index = 0;
- return readEntry();
+ return readNode();
}
int readByte() {
@@ -77,18 +77,35 @@
}
Selector readSelector() {
- int elementIndex = readInt();
- return constantPool.get(elementIndex);
+ int tag = readByte();
+ if (tag == Pickles.BACKREFERENCE) {
+ return readBackReference();
+ }
+ assert(tag == Pickles.SELECTOR_UNTYPED);
+ int entryIndex = index++;
+ SelectorKind kind = Pickles.selectorKindFromId[readInt()];
+ String name = readString();
+ Element library = readElement();
+ int argumentsCount = readInt();
+ int namedArgumentsCount = readInt();
+ List<String> namedArguments = new List<String>(namedArgumentsCount);
+ for (int i = 0; i < namedArgumentsCount; i++) {
+ namedArguments[i] = readString();
+ }
+ Selector result = new Selector(
+ kind, name, library, argumentsCount, namedArguments);
+ unpickled[entryIndex] = result;
+ return result;
}
/**
- * Read an entry that might be a back reference, or that might be used
- * in a back reference.
+ * Reads a [IrNode]. Expression nodes are added to the [unpickled] map to
+ * enable unpickling back references.
*/
- IrNode readEntry() {
+ IrNode readNode() {
int tag = readByte();
if (Pickles.isExpressionTag(tag)) {
- return readExpressionEntry(tag);
+ return readExpressionNode(tag);
} else if (tag == Pickles.NODE_RETURN) {
return readReturnNode();
} else {
@@ -96,7 +113,7 @@
}
}
- IrExpression readExpressionEntry(int tag) {
+ IrExpression readExpressionNode(int tag) {
int entryIndex = index++;
IrExpression result;
if (tag == Pickles.NODE_CONST) {
@@ -111,14 +128,14 @@
return unpickled[entryIndex] = result;
}
- IrExpression readBackReference() {
+ Object readBackReference() {
int indexDelta = readInt();
int entryIndex = index - indexDelta;
assert(unpickled[entryIndex] != null);
return unpickled[entryIndex];
}
- List<IrExpression> readBackReferenceList() {
+ List<IrExpression> readExpressionBackReferenceList() {
int length = readInt();
List<IrExpression> result = new List<IrExpression>(length);
for (int i = 0; i < length; i++) {
@@ -129,9 +146,9 @@
List<IrNode> readNodeList() {
int length = readInt();
- List nodes = new List<IrNode>(length);
+ List<IrNode> nodes = new List<IrNode>(length);
for (int i = 0; i < length; i++) {
- nodes[i] = readEntry();
+ nodes[i] = readNode();
}
return nodes;
}
@@ -160,7 +177,7 @@
var position = readPosition();
FunctionElement functionElement = readElement();
Selector selector = readSelector();
- List<IrExpression> arguments = readBackReferenceList();
+ List<IrExpression> arguments = readExpressionBackReferenceList();
return new IrInvokeStatic(position, functionElement, selector, arguments);
}
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
index 9151b71..b9901e4 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
@@ -107,6 +107,7 @@
ClassElement noSideEffectsClass;
ClassElement noThrowsClass;
ClassElement noInlineClass;
+ ClassElement irRepresentationClass;
Element getInterceptorMethod;
Element interceptedNames;
@@ -164,11 +165,17 @@
* know whether a send must be intercepted or not.
*/
final Map<String, Set<Element>> interceptedElements;
- // TODO(sra): Not all methods in the Set always require an interceptor. A
- // method may be mixed into a true interceptor *and* a plain class. For the
- // method to work on the interceptor class it needs to use the explicit
- // receiver. This constrains the call on a known plain receiver to pass the
- // explicit receiver. https://code.google.com/p/dart/issues/detail?id=8942
+
+ /**
+ * The members of mixin classes that are mixed into an instantiated
+ * interceptor class. This is a cached subset of [interceptedElements].
+ * These members must be invoked with a correct explicit receiver even when
+ * the receiver is not an intercepted class because the function uses the
+ * explicit interceptor parameter since it may be called on an intercepted
+ * class.
+ */
+ final Map<String, Set<Element>> interceptedMixinElements =
+ new Map<String, Set<Element>>();
/**
* A map of specialized versions of the [getInterceptorMethod].
@@ -367,6 +374,29 @@
return interceptedElements[selector.name] != null;
}
+ /**
+ * Returns `true` iff [selector] matches an element defined in a class mixed
+ * into an intercepted class. These selectors are not eligible for the 'dummy
+ * explicit receiver' optimization.
+ */
+ bool isInterceptedMixinSelector(Selector selector) {
+ Set<Element> elements = interceptedMixinElements.putIfAbsent(
+ selector.name,
+ () {
+ Set<Element> elements = interceptedElements[selector.name];
+ if (elements == null) return null;
+ return elements
+ .where((element) =>
+ classesMixedIntoNativeClasses.contains(
+ element.getEnclosingClass()))
+ .toSet();
+ });
+
+ if (elements == null) return false;
+ if (elements.isEmpty) return false;
+ return elements.any((element) => selector.applies(element, compiler));
+ }
+
final Map<String, Set<ClassElement>> interceptedClassesCache =
new Map<String, Set<ClassElement>>();
@@ -521,6 +551,7 @@
noSideEffectsClass = compiler.findHelper('NoSideEffects');
noThrowsClass = compiler.findHelper('NoThrows');
noInlineClass = compiler.findHelper('NoInline');
+ irRepresentationClass = compiler.findHelper('IrRepresentation');
}
void validateInterceptorImplementsAllObjectMethods(
@@ -1853,6 +1884,8 @@
void visitInterceptor(InterceptorConstant constant) => copy(constant);
+ void visitDummyReceiver(DummyReceiverConstant constant) => copy(constant);
+
void visitList(ListConstant constant) {
copy(constant.entries);
copy(constant);
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart
index c6ee2e5..c436744 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/constant_emitter.dart
@@ -144,6 +144,10 @@
jsAst.Expression visitInterceptor(InterceptorConstant constant) {
return emitCanonicalVersion(constant);
}
+
+ jsAst.Expression visitDummyReceiver(DummyReceiverConstant constant) {
+ return new jsAst.LiteralNumber('0');
+ }
}
/**
@@ -313,6 +317,10 @@
'prototype');
}
+ jsAst.Expression visitDummyReceiver(DummyReceiverConstant constant) {
+ return _reference(constant);
+ }
+
jsAst.Expression visitConstructed(ConstructedConstant constant) {
Element element = constant.type.element;
if (element.isForeign(compiler)
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart b/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
index 9b18a37..484fa22 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
@@ -1181,6 +1181,10 @@
addRoot(constant.dispatchedType.element.name);
add('methods');
}
+
+ visitDummyReceiver(DummyReceiverConstant constant) {
+ add('dummy_receiver');
+ }
}
/**
@@ -1258,6 +1262,11 @@
return _hashString(5, typeName);
}
+ visitDummyReceiver(DummyReceiverConstant constant) {
+ compiler.internalError(
+ 'DummyReceiverConstant should never be named and never be subconstant');
+ }
+
int _hashString(int hash, String s) {
int length = s.length;
hash = _combine(hash, length);
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/type_variable_handler.dart b/sdk/lib/_internal/compiler/implementation/js_backend/type_variable_handler.dart
index cae5491..5dc0126 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/type_variable_handler.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/type_variable_handler.dart
@@ -66,10 +66,10 @@
InterfaceType typeVariableType = typeVariableClass.computeType(compiler);
List<int> constants = <int>[];
evaluator = new CompileTimeConstantEvaluator(
- compiler.constantHandler,
- compiler.globalDependencies,
+ compiler.constantHandler,
+ compiler.globalDependencies,
compiler);
-
+
for (TypeVariableType currentTypeVariable in cls.typeVariables) {
List<Constant> createArguments(FunctionElement constructor) {
if (constructor != typeVariableConstructor) {
@@ -154,7 +154,8 @@
return typeVariableConstants[variable];
}
- emitter.globalMetadata.add('Placeholder for ${variable}');
+ // TODO(15613): Remove quotes.
+ emitter.globalMetadata.add('"Placeholder for ${variable}"');
return typeVariableConstants[variable] = emitter.globalMetadata.length - 1;
}
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
index 835a673..6b9a62c 100644
--- a/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/code_emitter_task.dart
@@ -909,8 +909,9 @@
}
bool isConstantInlinedOrAlreadyEmitted(Constant constant) {
- if (constant.isFunction()) return true; // Already emitted.
- if (constant.isPrimitive()) return true; // Inlined.
+ if (constant.isFunction()) return true; // Already emitted.
+ if (constant.isPrimitive()) return true; // Inlined.
+ if (constant.isDummyReceiver()) return true; // Inlined.
// The name is null when the constant is already a JS constant.
// TODO(floitsch): every constant should be registered, so that we can
// share the ones that take up too much space (like some strings).
diff --git a/sdk/lib/_internal/compiler/implementation/js_emitter/type_test_emitter.dart b/sdk/lib/_internal/compiler/implementation/js_emitter/type_test_emitter.dart
index 92e4f63..076240a 100644
--- a/sdk/lib/_internal/compiler/implementation/js_emitter/type_test_emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_emitter/type_test_emitter.dart
@@ -56,9 +56,14 @@
void generateFunctionTypeSignature(Element method, FunctionType type) {
assert(method.isImplementation);
jsAst.Expression thisAccess = new jsAst.This();
- Node node = method.parseNode(compiler);
- ClosureClassMap closureData =
- compiler.closureToClassMapper.closureMappingCache[node];
+ ClosureClassMap closureData;
+ // TODO(lry): Once the IR can express methods containing closures, find
+ // a way to get the [:thisName:]. The solution to this problem depends on
+ // how closures are represented in the IR, which is not yet decided.
+ if (!compiler.irBuilder.hasIr(method)) {
+ Node node = method.parseNode(compiler);
+ closureData = compiler.closureToClassMapper.closureMappingCache[node];
+ }
if (closureData != null) {
Element thisElement =
closureData.freeVariableMapping[closureData.thisElement];
diff --git a/sdk/lib/_internal/compiler/implementation/native_handler.dart b/sdk/lib/_internal/compiler/implementation/native_handler.dart
index b4e8016..5a0d890 100644
--- a/sdk/lib/_internal/compiler/implementation/native_handler.dart
+++ b/sdk/lib/_internal/compiler/implementation/native_handler.dart
@@ -1047,10 +1047,10 @@
final RegExp nativeRedirectionRegExp = new RegExp(r'^[a-zA-Z][a-zA-Z_$0-9]*$');
-void handleSsaNative(SsaBuilder builder, Expression nativeBody) {
+void handleSsaNative(SsaFromAstBuilder builder, Expression nativeBody) {
Compiler compiler = builder.compiler;
FunctionElement element = builder.work.element;
- NativeEmitter nativeEmitter = builder.emitter.nativeEmitter;
+ NativeEmitter nativeEmitter = builder.nativeEmitter;
JavaScriptBackend backend = builder.backend;
HInstruction convertDartClosure(Element parameter, FunctionType type) {
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/members.dart b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
index 9f58576..a396889 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/members.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
@@ -1468,14 +1468,16 @@
}
FunctionElement result;
bool resolvedSuper = false;
- for (Link<Node> link = initializers;
- !link.isEmpty;
- link = link.tail) {
+ for (Link<Node> link = initializers; !link.isEmpty; link = link.tail) {
if (link.head.asSendSet() != null) {
final SendSet init = link.head.asSendSet();
resolveFieldInitializer(constructor, init);
} else if (link.head.asSend() != null) {
final Send call = link.head.asSend();
+ if (call.argumentsNode == null) {
+ error(link.head, MessageKind.INVALID_INITIALIZER);
+ continue;
+ }
if (Initializers.isSuperConstructorCall(call)) {
if (resolvedSuper) {
error(call, MessageKind.DUPLICATE_SUPER_INITIALIZER);
@@ -1533,7 +1535,7 @@
/** Convenience method for visiting nodes that may be null. */
R visit(Node node) => (node == null) ? null : node.accept(this);
- void error(Node node, MessageKind kind, [Map arguments = const {}]) {
+ void error(Spannable node, MessageKind kind, [Map arguments = const {}]) {
compiler.reportFatalError(node, kind, arguments);
}
@@ -1551,10 +1553,6 @@
compiler.internalError(message, node: node);
}
- void unimplemented(Node node, String message) {
- compiler.unimplemented(message, node: node);
- }
-
void addDeferredAction(Element element, DeferredAction action) {
compiler.enqueuer.resolution.addDeferredAction(element, action);
}
@@ -2681,8 +2679,6 @@
}
}
- // TODO(ngeoffray): Warn if target is null and the send is
- // unqualified.
useElement(node, target);
registerSend(selector, target);
if (node.isPropertyAccess && Elements.isStaticOrTopLevelFunction(target)) {
@@ -2736,14 +2732,21 @@
compiler.backend.registerThrowNoSuchMethod(mapping);
}
} else if (target.impliesType()) {
+ setter = warnAndCreateErroneousElement(
+ node.selector, target.name, MessageKind.ASSIGNING_TYPE);
compiler.backend.registerThrowNoSuchMethod(mapping);
} else if (target.modifiers.isFinal() ||
target.modifiers.isConst() ||
(target.isFunction() &&
- Elements.isStaticOrTopLevelFunction(target) &&
- !target.isSetter())) {
- setter = warnAndCreateErroneousElement(
- node.selector, target.name, MessageKind.CANNOT_RESOLVE_SETTER);
+ Elements.isStaticOrTopLevelFunction(target) &&
+ !target.isSetter())) {
+ if (target.isFunction()) {
+ setter = warnAndCreateErroneousElement(
+ node.selector, target.name, MessageKind.ASSIGNING_METHOD);
+ } else {
+ setter = warnAndCreateErroneousElement(
+ node.selector, target.name, MessageKind.CANNOT_RESOLVE_SETTER);
+ }
compiler.backend.registerThrowNoSuchMethod(mapping);
}
if (isPotentiallyMutableTarget(target)) {
@@ -2759,10 +2762,6 @@
resolveArguments(node.argumentsNode);
- // TODO(ngeoffray): Check if the target can be assigned.
- // TODO(ngeoffray): Warn if target is null and the send is
- // unqualified.
-
Selector selector = mapping.getSelector(node);
if (isComplex) {
Selector getterSelector;
@@ -2870,7 +2869,7 @@
}
visitOperator(Operator node) {
- unimplemented(node, 'operator');
+ internalError(node, 'operator');
}
visitRethrow(Rethrow node) {
@@ -3166,8 +3165,7 @@
}
visitModifiers(Modifiers node) {
- // TODO(ngeoffray): Implement this.
- unimplemented(node, 'modifiers');
+ internalError(node, 'modifiers');
}
visitLiteralList(LiteralList node) {
@@ -3503,8 +3501,8 @@
mapping.remove(label.label);
}
});
- // TODO(ngeoffray): We should check here instead of the SSA backend if
- // there might be an error.
+ // TODO(15575): We should warn if we can detect a fall through
+ // error.
compiler.backend.registerFallThroughError(mapping);
}
@@ -3520,9 +3518,7 @@
visitTryStatement(TryStatement node) {
visit(node.tryBlock);
if (node.catchBlocks.isEmpty && node.finallyBlock == null) {
- // TODO(ngeoffray): The precise location is
- // node.getEndtoken.next. Adjust when issue #1581 is fixed.
- error(node, MessageKind.NO_CATCH_NOR_FINALLY);
+ error(node.getEndToken().next, MessageKind.NO_CATCH_NOR_FINALLY);
}
visit(node.catchBlocks);
visit(node.finallyBlock);
@@ -3599,7 +3595,7 @@
}
visitTypedef(Typedef node) {
- unimplemented(node, 'typedef');
+ internalError(node, 'typedef');
}
}
@@ -4642,10 +4638,9 @@
resolver.enclosingElement.getLibrary());
}
- // TODO(ngeoffray): method named lookup should not report errors.
- FunctionElement lookupConstructor(ClassElement cls,
- Node diagnosticNode,
- String constructorName) {
+ FunctionElement resolveConstructor(ClassElement cls,
+ Node diagnosticNode,
+ String constructorName) {
cls.ensureResolved(compiler);
Selector selector = createConstructorSelector(constructorName);
Element result = cls.lookupConstructor(selector);
@@ -4689,7 +4684,7 @@
ClassElement cls = element;
cls.ensureResolved(compiler);
// The unnamed constructor may not exist, so [e] may become unresolved.
- element = lookupConstructor(cls, diagnosticNode, '');
+ element = resolveConstructor(cls, diagnosticNode, '');
} else {
element = failOrReturnErroneousElement(
element, diagnosticNode, element.name, MessageKind.NOT_A_TYPE,
@@ -4726,7 +4721,7 @@
if (element.isClass()) {
ClassElement cls = element;
cls.ensureResolved(compiler);
- return lookupConstructor(cls, name, name.source);
+ return resolveConstructor(cls, name, name.source);
} else if (element.isPrefix()) {
PrefixElement prefix = element;
element = prefix.lookupLocalMember(name.source);
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
index 9bf573c..77d6903 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
@@ -35,8 +35,8 @@
Element element = work.element.implementation;
return compiler.withCurrentElement(element, () {
HInstruction.idCounter = 0;
- ConstantSystem constantSystem = compiler.backend.constantSystem;
- SsaBuilder builder = new SsaBuilder(constantSystem, this, work);
+ SsaFromAstBuilder builder =
+ new SsaFromAstBuilder(backend, work, emitter.nativeEmitter);
HGraph graph;
ElementKind kind = element.kind;
if (kind == ElementKind.GENERATIVE_CONSTRUCTOR) {
@@ -91,7 +91,7 @@
});
}
- HGraph compileConstructor(SsaBuilder builder, CodegenWorkItem work) {
+ HGraph compileConstructor(SsaFromAstBuilder builder, CodegenWorkItem work) {
return builder.buildFactory(work.element);
}
}
@@ -114,7 +114,7 @@
*/
Map<Element, HInstruction> directLocals;
Map<Element, Element> redirectionMapping;
- SsaBuilder builder;
+ SsaFromAstMixin builder;
ClosureClassMap closureData;
LocalsHandler(this.builder)
@@ -672,7 +672,7 @@
abstract class JumpHandler {
- factory JumpHandler(SsaBuilder builder, TargetElement target) {
+ factory JumpHandler(SsaFromAstMixin builder, TargetElement target) {
return new TargetJumpHandler(builder, target);
}
void generateBreak([LabelElement label]);
@@ -718,11 +718,11 @@
// Continues in loops are implemented as breaks of the body.
// Continues in switches is currently not handled.
class TargetJumpHandler implements JumpHandler {
- final SsaBuilder builder;
+ final SsaFromAstMixin builder;
final TargetElement target;
final List<JumpHandlerEntry> jumps;
- TargetJumpHandler(SsaBuilder builder, this.target)
+ TargetJumpHandler(SsaFromAstMixin builder, this.target)
: this.builder = builder,
jumps = <JumpHandlerEntry>[] {
assert(builder.jumpTargets[target] == null);
@@ -804,12 +804,12 @@
/// switch case loop.
final Map<TargetElement, int> targetIndexMap = new Map<TargetElement, int>();
- SwitchCaseJumpHandler(SsaBuilder builder,
+ SwitchCaseJumpHandler(SsaFromAstMixin builder,
TargetElement target,
SwitchStatement node)
: super(builder, target) {
// The switch case indices must match those computed in
- // [SsaBuilder.buildSwitchCaseConstants].
+ // [SsaFromAstMixin.buildSwitchCaseConstants].
// Switch indices are 1-based so we can bypass the synthetic loop when no
// cases match simply by branching on the index (which defaults to null).
int switchIndex = 1;
@@ -834,7 +834,7 @@
if (label == null) {
// Creates a special break instruction for the synthetic loop generated
// for a switch statement with continue statements. See
- // [SsaBuilder.buildComplexSwitchStatement] for detail.
+ // [SsaFromAstMixin.buildComplexSwitchStatement] for detail.
HInstruction breakInstruction =
new HBreak(target, breakSwitchContinueLoop: true);
@@ -854,7 +854,7 @@
if (isContinueToSwitchCase(label)) {
// Creates the special instructions 'label = i; continue l;' used in
// switch statements with continue statements. See
- // [SsaBuilder.buildComplexSwitchStatement] for detail.
+ // [SsaFromAstMixin.buildComplexSwitchStatement] for detail.
assert(label != null);
HInstruction value = builder.graph.addConstantInt(
@@ -882,19 +882,60 @@
}
/**
- * This mixin implements functionality that is shared between the [SsaBuilder]
- * and the [SsaFromIrBuilder] classes.
+ * This mixin implements functionality that is shared between [SsaFromIrBuilder]
+ * and [SsaFromAstBuilder].
*
* The type parameter [N] represents the node type from which the SSA form is
* built, either [IrNode] or [Node].
*
- * This class does not define any fields because [SsaFromIrInliner], one of its
- * subclasses, is implemented using delegation and does not need fields. The two
- * other subclasses, [SsaBuilder] and [SsaFromIrBuilder], implement most of the
- * properties as fields. To avoid copy-pasting these definitions, the mixin
- * [SsaGraphBuilderFields] is inserted in between.
+ * The following diagram shows the mixin structure of the AST and IR builders
+ * and inliners, which is explained in the text below.
+ *
+ * SsaBuilderMixin
+ * ___________/ | | \_________
+ * / | | \
+ * SsaBuilderDelegate / \ SsaBuilderFields
+ * | | / \ / |
+ * | | SsaFromAstMixin SsaFromIrMixin / |
+ * | \ _____/ | _____________|____\_____/ |
+ * | \__/__________|______/______ | \______ |
+ * | / | / \ | \ |
+ * SsaFromAstInliner SsaFromAstBuilder SsaFromIrInliner SsaFromIrBuilder
+ *
+ * The entry point to building an SSA graph is either an [SsaFromAstBuilder] or
+ * an [SsaFromIrBuilder]. These builder classes hold the [HGraph] data structure
+ * (inherited from [SsaBuilderFields]) into which blocks and instructions are
+ * inserted. The visitor methods for IR / AST nodes are defined in the
+ * [SsaFromIrMixin] / [SsaFromAstMixin] mixins.
+ *
+ * When inlining a function invocation of the same kind (SSA function in SSA
+ * builder, for example), the state of the builder pushed on the [inliningStack]
+ * and the same builder instance continues visiting the inlined function's body.
+ *
+ * When inlining a function of the other kind, the builder state is also pushed
+ * on the inlining stack, and an inliner instance is created.
+ *
+ * We consider inlining an IR function into an AST builder, which creates an
+ * [SsaFromIrInliner]. The IR inliner implements an IR visitor (defined in the
+ * [SsaFromIrMixin]) and inserts SSA instructions into the [HGraph] of the
+ * AST builder by delegation (inherited from the [SsaBuilderDelegate] mixin).
+ * When encountering the [:return:] instruction (inlining is only performed if
+ * there is exactly one), the IR inliner updates the [returnElement] field of
+ * the AST builder.
+ *
+ * In the opposite case (inlining an AST function into an IR builder), the AST
+ * inliner updates the [emitted] map of the IR builder with the return value.
+ *
+ * Finally, inlining can be nested. For example, we might start with an AST
+ * builder and inline an invocation of an IR function. The IR inliner will
+ * then again inline invocations of functions that are in either IR or AST.
+ *
+ * Note that [SsaBuilderMixin] does not define any fields because the inliner
+ * subclasses are implemented using delegation ([SsaBuilderDelegate]). The
+ * builder subclasses implement most of the properties as fields by extending
+ * [SsaBuilderFields].
*/
-abstract class SsaGraphBuilderMixin<N> {
+abstract class SsaBuilderMixin<N> {
Compiler get compiler;
JavaScriptBackend get backend;
@@ -934,6 +975,8 @@
*/
bool get inThrowExpression;
+ void set inThrowExpression(bool value);
+
/**
* The loop nesting is consulted when inlining a function invocation in
* [tryInlineMethod]. The inlining heuristics take this information into
@@ -941,6 +984,8 @@
*/
int get loopNesting;
+ void set loopNesting(int value);
+
List<InliningState> get inliningStack;
/**
@@ -1031,16 +1076,16 @@
}
/**
- * Prepares the state of the builder for inlining an invocaiton of [function].
+ * Returns a complete argument list for a call of [function].
*/
- void enterInlinedMethod(FunctionElement function,
- Selector selector,
- List<HInstruction> providedArguments,
- N currentNode) {
+ List<HInstruction> completeSendArgumentsList(
+ FunctionElement function,
+ Selector selector,
+ List<HInstruction> providedArguments,
+ N currentNode) {
assert(invariant(function, function.isImplementation));
assert(providedArguments != null);
- List<HInstruction> compiledArguments;
bool isInstanceMember = function.isInstanceMember();
// For static calls, [providedArguments] is complete, default arguments
// have been included if necessary, see [addStaticSendArgumentsToList].
@@ -1050,12 +1095,11 @@
|| function.isGenerativeConstructorBody()
|| selector.isGetter()) {
// For these cases, the provided argument list is known to be complete.
- compiledArguments = providedArguments;
+ return providedArguments;
} else {
- compiledArguments = completeDynamicSendArgumentsList(
+ return completeDynamicSendArgumentsList(
selector, function, providedArguments);
}
- setupInliningState(function, compiledArguments);
}
/**
@@ -1127,7 +1171,11 @@
return compiledArguments;
}
- void setupInliningState(FunctionElement function,
+ /**
+ * Prepares the state of the builder for inlining an invocaiton of [function].
+ */
+ void enterInlinedMethod(FunctionElement function,
+ N currentNode,
List<HInstruction> compiledArguments);
void leaveInlinedMethod();
@@ -1265,10 +1313,15 @@
isAssignable: false),
currentNode);
}
- enterInlinedMethod(function, selector, providedArguments, currentNode);
+ List<HInstruction> compiledArguments = completeSendArgumentsList(
+ function, selector, providedArguments, currentNode);
+ enterInlinedMethod(function, currentNode, compiledArguments);
inlinedFrom(function, () {
- potentiallyCheckInlinedParameterTypes(element);
- doInline(function);
+ if (!isReachable) {
+ emitReturn(graph.addConstantNull(compiler), null);
+ } else {
+ doInline(function);
+ }
});
leaveInlinedMethod();
}
@@ -1281,7 +1334,9 @@
return false;
}
- void doInline(Element element);
+ void emitReturn(HInstruction value, N node);
+
+ void doInline(FunctionElement function);
inlinedFrom(Element element, f()) {
assert(element is FunctionElement || element is VariableElement);
@@ -1315,10 +1370,10 @@
}
/**
- * This class defines the abstract properties of [SsaGraphBuilderMixin] as
- * fields. It is shared between the [SsaBuilder] and the [SsaFromIrBuilder].
+ * This class defines the abstract properties of [SsaBuilderMixin] as fields.
+ * It is mixed into [SsaFromAstBuilder] and [SsaFromIrBuilder].
*/
-abstract class SsaGraphBuilderFields<N> implements SsaGraphBuilderMixin<N> {
+abstract class SsaBuilderFields<N> implements SsaBuilderMixin<N> {
final HGraph graph = new HGraph();
HBasicBlock _current;
@@ -1338,34 +1393,90 @@
int loopNesting = 0;
- final List<InliningState> inliningStack = <InliningState>[];
-
final List<Element> sourceElementStack = <Element>[];
}
-class SsaBuilder extends ResolvedVisitor
- with SsaGraphBuilderMixin<Node>, SsaGraphBuilderFields<Node> {
- final SsaBuilderTask builder;
- final JavaScriptBackend backend;
- final CodegenWorkItem work;
- final ConstantSystem constantSystem;
+/**
+ * This class defines the abstract properties of [SsaBuilderMixin] by
+ * delegation to the [builder], which is either an [SsaFromAstBuilder] or an
+ * [SsaFromIrBuilder].
+ * It is mixed into [SsaFromAstInliner] and [SsaFromIrInliner].
+ */
+abstract class SsaBuilderDelegate<N, M> implements SsaBuilderMixin<N> {
+ SsaBuilderFields<M> get builder;
+
+ Compiler get compiler => builder.compiler;
+
+ JavaScriptBackend get backend => builder.backend;
+
+ Element get sourceElement => builder.sourceElementStack.last;
+
+ HGraph get graph => builder.graph;
+
+ HBasicBlock get current => builder.current;
+
+ void set current(HBasicBlock block) {
+ builder.current = block;
+ }
+
+ HBasicBlock get lastOpenedBlock => builder.lastOpenedBlock;
+
+ void set lastOpenedBlock(HBasicBlock block) {
+ builder.lastOpenedBlock = block;
+ }
+
+ bool get isReachable => builder.isReachable;
+
+ void set isReachable(bool value) {
+ builder.isReachable = value;
+ }
+
+ bool get inThrowExpression => builder.inThrowExpression;
+
+ void set inThrowExpression(bool value) {
+ builder.inThrowExpression = value;
+ }
+
+ int get loopNesting => builder.loopNesting;
+
+ void set loopNesting(int value) {
+ builder.loopNesting = value;
+ }
+
+ List<InliningState> get inliningStack => builder.inliningStack;
+
+ List<Element> get sourceElementStack => builder.sourceElementStack;
+}
+
+/**
+ * This class is a tree visitor which builds SSA nodes. It is mixed into
+ * [SsaFromAstBuilder] and [SsaFromAstInliner].
+ */
+abstract class SsaFromAstMixin
+ implements ResolvedVisitor, SsaBuilderMixin<Node> {
+ CodegenWorkItem get work;
+ ConstantSystem get constantSystem;
+ RuntimeTypes get rti;
+
LocalsHandler localsHandler;
+
HInstruction rethrowableException;
- Map<Element, HInstruction> parameters;
- final RuntimeTypes rti;
+
HParameterValue lastAddedParameter;
- Map<TargetElement, JumpHandler> jumpTargets;
+ Map<Element, HInstruction> parameters = <Element, HInstruction>{};
+
+ Map<TargetElement, JumpHandler> jumpTargets = <TargetElement, JumpHandler>{};
/**
* Variables stored in the current activation. These variables are
* being updated in try/catch blocks, and should be
* accessed indirectly through [HLocalGet] and [HLocalSet].
*/
- Map<Element, HLocalValue> activationVariables;
+ Map<Element, HLocalValue> activationVariables = <Element, HLocalValue>{};
// We build the Ssa graph by simulating a stack machine.
- List<HInstruction> stack;
+ List<HInstruction> stack = <HInstruction>[];
Element get currentNonClosureClass {
ClassElement cls = sourceElement.getEnclosingClass();
@@ -1392,22 +1503,7 @@
// types of the type variables in an environment (like the [LocalsHandler]).
final List<DartType> currentInlinedInstantiations = <DartType>[];
- Compiler get compiler => builder.compiler;
- CodeEmitterTask get emitter => builder.emitter;
-
- SsaBuilder(this.constantSystem, SsaBuilderTask builder, CodegenWorkItem work)
- : this.builder = builder,
- this.backend = builder.backend,
- this.work = work,
- stack = new List<HInstruction>(),
- activationVariables = new Map<Element, HLocalValue>(),
- jumpTargets = new Map<TargetElement, JumpHandler>(),
- parameters = new Map<Element, HInstruction>(),
- rti = builder.backend.rti,
- super(work.resolutionTree, builder.compiler) {
- localsHandler = new LocalsHandler(this);
- sourceElementStack.add(work.element);
- }
+ final List<AstInliningState> inliningStack = <AstInliningState>[];
Element returnElement;
DartType returnType;
@@ -1582,6 +1678,101 @@
return result;
}
+ /**
+ * This method sets up the local state of the builder for inlining [function].
+ * The arguments of the function are inserted into the [localsHandler].
+ *
+ * When inlining a function, [:return:] statements are not emitted as
+ * [HReturn] instructions. Instead, the value of a synthetic element is
+ * updated in the [localsHandler]. This function creates such an element and
+ * stores it in the [returnElement] field.
+ */
+ void setupStateForInlining(FunctionElement function,
+ List<HInstruction> compiledArguments) {
+ bool hasIr = compiler.irBuilder.hasIr(function);
+ localsHandler = new LocalsHandler(this);
+ if (hasIr) {
+ // If the inlined function is in IR, the inliner will not use the locals
+ // handler of this class. However, it will use the [returnElement].
+ // When creating the [returnElement] (see below), the invocation of
+ // [updateLocal] requires [closureData] to be non-null.
+ localsHandler.closureData =
+ new ClosureClassMap(null, null, null, new ThisElement(function));
+ } else {
+ localsHandler.closureData =
+ compiler.closureToClassMapper.computeClosureToClassMapping(
+ function, function.parseNode(compiler), elements);
+ }
+ // TODO(kasperl): Bad smell. We shouldn't be constructing elements here.
+ returnElement = new VariableElementX.synthetic("result",
+ ElementKind.VARIABLE, function);
+ localsHandler.updateLocal(returnElement,
+ graph.addConstantNull(compiler));
+
+ // If the inlined function is in IR, the [SsaFromIrInliner] will use the
+ // the [returnElement]. The remaining state of this AST builder is not used
+ // and does need to be set up.
+ if (!hasIr) {
+ inTryStatement = false; // TODO(lry): why? Document.
+
+ int argumentIndex = 0;
+ if (function.isInstanceMember()) {
+ localsHandler.updateLocal(localsHandler.closureData.thisElement,
+ compiledArguments[argumentIndex++]);
+ }
+
+ FunctionSignature signature = function.computeSignature(compiler);
+ signature.orderedForEachParameter((Element parameter) {
+ HInstruction argument = compiledArguments[argumentIndex++];
+ localsHandler.updateLocal(parameter, argument);
+ });
+
+ ClassElement enclosing = function.getEnclosingClass();
+ if ((function.isConstructor() || function.isGenerativeConstructorBody())
+ && backend.classNeedsRti(enclosing)) {
+ enclosing.typeVariables.forEach((TypeVariableType typeVariable) {
+ HInstruction argument = compiledArguments[argumentIndex++];
+ localsHandler.updateLocal(typeVariable.element, argument);
+ });
+ }
+ assert(argumentIndex == compiledArguments.length);
+
+ elements = compiler.enqueuer.resolution.getCachedElements(function);
+ assert(elements != null);
+ returnType = signature.returnType;
+ stack = <HInstruction>[];
+ }
+ }
+
+ void restoreState(AstInliningState state) {
+ localsHandler = state.oldLocalsHandler;
+ returnElement = state.oldReturnElement;
+ if (state.irInliner == null) {
+ // These fields only need to be restored if the function that was inlined
+ // is in AST form, see [setupStateForInlining] above.
+ inTryStatement = state.inTryStatement;
+ elements = state.oldElements;
+ returnType = state.oldReturnType;
+ assert(stack.isEmpty);
+ stack = state.oldStack;
+ }
+ }
+
+ /**
+ * Run this builder on the body of the [function] to be inlined.
+ */
+ void visitInlinedFunction(FunctionElement function) {
+ assert(!compiler.irBuilder.hasIr(function));
+ potentiallyCheckInlinedParameterTypes(function);
+ if (function.isGenerativeConstructor()) {
+ buildFactory(function);
+ } else {
+ FunctionExpression functionNode = function.parseNode(compiler);
+ functionNode.body.accept(this);
+ }
+ }
+
+
addInlinedInstantiation(DartType type) {
if (type != null) {
currentInlinedInstantiations.add(type);
@@ -1594,90 +1785,6 @@
}
}
- void setupInliningState(FunctionElement function,
- List<HInstruction> compiledArguments) {
- InliningState state = new InliningState(
- function, returnElement, returnType, elements, stack,
- localsHandler, inTryStatement);
- inTryStatement = false; // TODO(lry): why? Document.
- LocalsHandler newLocalsHandler = new LocalsHandler(this);
- if (compiler.irBuilder.hasIr(function)) {
- // TODO(lry): handle ir functions with nested closure definitions.
- newLocalsHandler.closureData =
- new ClosureClassMap(null, null, null, new ThisElement(function));
- } else {
- newLocalsHandler.closureData =
- compiler.closureToClassMapper.computeClosureToClassMapping(
- function, function.parseNode(compiler), elements);
- }
-
- int argumentIndex = 0;
- if (function.isInstanceMember()) {
- newLocalsHandler.updateLocal(newLocalsHandler.closureData.thisElement,
- compiledArguments[argumentIndex++]);
- }
-
- FunctionSignature signature = function.computeSignature(compiler);
- signature.orderedForEachParameter((Element parameter) {
- HInstruction argument = compiledArguments[argumentIndex++];
- newLocalsHandler.updateLocal(parameter, argument);
- });
-
- ClassElement enclosing = function.getEnclosingClass();
- if ((function.isConstructor() || function.isGenerativeConstructorBody())
- && backend.classNeedsRti(enclosing)) {
- enclosing.typeVariables.forEach((TypeVariableType typeVariable) {
- HInstruction argument = compiledArguments[argumentIndex++];
- newLocalsHandler.updateLocal(typeVariable.element, argument);
- });
- }
- assert(argumentIndex == compiledArguments.length);
-
- // TODO(kasperl): Bad smell. We shouldn't be constructing elements here.
- returnElement = new VariableElementX.synthetic("result",
- ElementKind.VARIABLE, function);
- newLocalsHandler.updateLocal(returnElement,
- graph.addConstantNull(compiler));
- elements = compiler.enqueuer.resolution.getCachedElements(function);
- assert(elements != null);
- returnType = signature.returnType;
- stack = <HInstruction>[];
- inliningStack.add(state);
- localsHandler = newLocalsHandler;
- }
-
- void leaveInlinedMethod() {
- InliningState state = inliningStack.removeLast();
- elements = state.oldElements;
- stack.add(localsHandler.readLocal(returnElement));
- returnElement = state.oldReturnElement;
- returnType = state.oldReturnType;
- assert(stack.length == 1);
- state.oldStack.add(stack[0]);
- stack = state.oldStack;
- localsHandler = state.oldLocalsHandler;
- inTryStatement = state.inTryStatement;
- }
-
- void doInline(FunctionElement function) {
- if (function.isGenerativeConstructor()) {
- // TODO(lry): inline constructors in IR.
- assert(!compiler.irBuilder.hasIr(function));
- buildFactory(function);
- } else if (compiler.irBuilder.hasIr(function)) {
- IrFunction irFunction = compiler.irBuilder.getIr(function);
- SsaFromIrInliner irInliner = new SsaFromIrInliner(this);
- irInliner.visitAll(irFunction.statements);
- // The [IrInliner] does not push the final instruction on the [stack].
- // In a way, this violates the invariant of the [SsaBuilder], however
- // it works just fine because [leaveInlinedMethod] will restore the
- // stack of the callee and push the value of the [returnElement].
- } else {
- FunctionExpression functionNode = function.parseNode(compiler);
- functionNode.body.accept(this);
- }
- }
-
bool providedArgumentsKnownToBeComplete(Node currentNode) {
/* When inlining the iterator methods generated for a [:for-in:] loop, the
* [currentNode] is the [ForIn] tree. The compiler-generated iterator
@@ -2884,7 +2991,7 @@
if (node.isThis()) {
stack.add(localsHandler.readThis());
} else {
- compiler.internalError("SsaBuilder.visitIdentifier on non-this",
+ compiler.internalError("SsaFromAstMixin.visitIdentifier on non-this",
node: node);
}
}
@@ -2999,14 +3106,18 @@
value = compiler.constantHandler.getConstantForVariable(element);
}
if (value != null) {
- HInstruction instruction = graph.addConstant(value, compiler);
+ HConstant instruction = graph.addConstant(value, compiler);
stack.add(instruction);
// The inferrer may have found a better type than the constant
// handler in the case of lists, because the constant handler
// does not look at elements in the list.
TypeMask type =
TypeMaskFactory.inferredTypeForElement(element, compiler);
- if (!type.containsAll(compiler)) instruction.instructionType = type;
+ if (!type.containsAll(compiler) && !instruction.isConstantNull()) {
+ // TODO(13429): The inferrer should know that an element
+ // cannot be null.
+ instruction.instructionType = type.nonNullable();
+ }
} else if (element.isField() && isLazilyInitialized(element)) {
HInstruction instruction = new HLazyStatic(
element,
@@ -3686,14 +3797,6 @@
push(buildInvokeSuper(compiler.noSuchMethodSelector, element, inputs));
}
- visitSend(Send node) {
- Element element = elements[node];
- if (element != null && identical(element, sourceElement)) {
- graph.isRecursiveMethod = true;
- }
- super.visitSend(node);
- }
-
visitSuperSend(Send node) {
Selector selector = elements.getSelector(node);
Element element = elements[node];
@@ -3737,7 +3840,7 @@
Set<ClassElement> subclasses = compiler.world.subclassesOf(cls);
return subclasses != null && subclasses.any((ClassElement subclass) {
- return !backend.rti.isTrivialSubstitution(subclass, cls);
+ return !rti.isTrivialSubstitution(subclass, cls);
});
}
@@ -3896,6 +3999,11 @@
typeInfoSetterElement,
<HInstruction>[newObject, typeInfo],
backend.dynamicType);
+
+ // The new object will now be referenced through the
+ // `setRuntimeTypeInfo` call. We therefore set the type of that
+ // instruction to be of the object's type.
+ assert(stack.last is HInvokeStatic || stack.last == newObject);
stack.last.instructionType = newObject.instructionType;
return pop();
}
@@ -4230,7 +4338,7 @@
generateGetter(node, elements[node]);
}
- // TODO(antonm): migrate rest of SsaBuilder to internalError.
+ // TODO(antonm): migrate rest of SsaFromAstMixin to internalError.
internalError(String reason, {Node node}) {
compiler.internalError(reason, node: node);
}
@@ -4609,12 +4717,19 @@
// [receiver] is only used if the node is an instance send.
HInstruction receiver = null;
- if (Elements.isInstanceSend(node, elements)) {
+ Element getter = elements[node.selector];
+
+ if (!Elements.isUnresolved(getter) && getter.impliesType()) {
+ Identifier selector = node.selector;
+ generateThrowNoSuchMethod(node, selector.source,
+ argumentNodes: node.arguments);
+ return;
+ } else if (Elements.isInstanceSend(node, elements)) {
receiver = generateInstanceSendReceiver(node);
generateInstanceGetterWithCompiledReceiver(
node, elements.getGetterSelectorInComplexSendSet(node), receiver);
} else {
- generateGetter(node, elements[node.selector]);
+ generateGetter(node, getter);
}
HInstruction getterInstruction = pop();
handleComplexOperatorSend(node, getterInstruction, node.arguments);
@@ -4768,12 +4883,7 @@
}
handleInTryStatement();
-
- if (!inliningStack.isEmpty) {
- localsHandler.updateLocal(returnElement, value);
- } else {
- closeAndGotoExit(attachPosition(new HReturn(value), node));
- }
+ emitReturn(value, node);
}
visitThrow(Throw node) {
@@ -4869,7 +4979,7 @@
}
visitModifiers(Modifiers node) {
- compiler.unimplemented('SsaBuilder.visitModifiers', node: node);
+ compiler.unimplemented('SsaFromAstMixin.visitModifiers', node: node);
}
visitBreakStatement(BreakStatement node) {
@@ -4977,7 +5087,7 @@
}
visitLabel(Label node) {
- compiler.internalError('SsaBuilder.visitLabel', node: node);
+ compiler.internalError('SsaFromAstMixin.visitLabel', node: node);
}
visitLabeledStatement(LabeledStatement node) {
@@ -5407,11 +5517,11 @@
}
visitSwitchCase(SwitchCase node) {
- compiler.internalError('SsaBuilder.visitSwitchCase');
+ compiler.internalError('SsaFromAstMixin.visitSwitchCase');
}
visitCaseMatch(CaseMatch node) {
- compiler.internalError('SsaBuilder.visitCaseMatch');
+ compiler.internalError('SsaFromAstMixin.visitCaseMatch');
}
visitTryStatement(TryStatement node) {
@@ -5611,11 +5721,157 @@
}
visitTypedef(Typedef node) {
- compiler.unimplemented('SsaBuilder.visitTypedef', node: node);
+ compiler.unimplemented('SsaFromAstMixin.visitTypedef', node: node);
}
visitTypeVariable(TypeVariable node) {
- compiler.internalError('SsaBuilder.visitTypeVariable');
+ compiler.internalError('SsaFromAstMixin.visitTypeVariable');
+ }
+}
+
+/**
+ * This class builds SSA nodes for functions represented in AST.
+ */
+class SsaFromAstBuilder extends ResolvedVisitor with
+ SsaBuilderMixin<Node>,
+ SsaFromAstMixin,
+ SsaBuilderFields<Node> {
+ final Compiler compiler;
+ final JavaScriptBackend backend;
+ final ConstantSystem constantSystem;
+ final CodegenWorkItem work;
+ final RuntimeTypes rti;
+
+ /* This field is used by the native handler. */
+ final NativeEmitter nativeEmitter;
+
+ SsaFromAstBuilder(JavaScriptBackend backend,
+ CodegenWorkItem work,
+ this.nativeEmitter)
+ : this.backend = backend,
+ this.compiler = backend.compiler,
+ this.constantSystem = backend.constantSystem,
+ this.work = work,
+ this.rti = backend.rti,
+ super(work.resolutionTree, backend.compiler) {
+ localsHandler = new LocalsHandler(this);
+ sourceElementStack.add(work.element);
+ }
+
+ /**
+ * This method is invoked before inlining the body of [function] into this
+ * [SsaFromAstBuilder]. The inlined function can be either in AST or IR.
+ *
+ * The method is also invoked from the [SsaFromIrInliner], that is, if we
+ * are currently inlining an IR function and encounter a function invocation
+ * that should be inlined.
+ */
+ void enterInlinedMethod(FunctionElement function,
+ Node _,
+ List<HInstruction> compiledArguments) {
+ SsaFromIrInliner irInliner;
+ if (compiler.irBuilder.hasIr(function)) {
+ irInliner = new SsaFromIrInliner(this, function, compiledArguments);
+ }
+ AstInliningState state = new AstInliningState(
+ function, returnElement, returnType, elements, stack, localsHandler,
+ inTryStatement, irInliner);
+ inliningStack.add(state);
+
+ // Setting up the state of the (AST) builder is performed even when the
+ // inlined function is in IR, because the irInliner uses the [returnElement]
+ // of the AST builder.
+ setupStateForInlining(function, compiledArguments);
+ }
+
+ void leaveInlinedMethod() {
+ HInstruction result = localsHandler.readLocal(returnElement);
+ AstInliningState state = inliningStack.removeLast();
+ restoreState(state);
+ stack.add(result);
+ }
+
+ void doInline(FunctionElement function) {
+ if (compiler.irBuilder.hasIr(function)) {
+ AstInliningState state = inliningStack.last;
+ state.irInliner.visitInlinedFunction(function);
+ } else {
+ visitInlinedFunction(function);
+ }
+ }
+
+ void emitReturn(HInstruction value, Node node) {
+ if (inliningStack.isEmpty) {
+ closeAndGotoExit(attachPosition(new HReturn(value), node));
+ } else {
+ localsHandler.updateLocal(returnElement, value);
+ }
+ }
+}
+
+/**
+ * This class inlines an AST function into an [SsaFromIrBuilder].
+ */
+class SsaFromAstInliner extends ResolvedVisitor with
+ SsaBuilderMixin<Node>,
+ SsaFromAstMixin,
+ SsaBuilderDelegate<Node, IrNode> {
+ final SsaFromIrBuilder builder;
+
+ SsaFromAstInliner.internal(SsaFromIrBuilder builder)
+ : this.builder = builder,
+ super(builder.work.resolutionTree, builder.compiler);
+
+ factory SsaFromAstInliner(SsaFromIrBuilder builder,
+ FunctionElement function,
+ List<HInstruction> compiledArguments) {
+ SsaFromAstInliner result = new SsaFromAstInliner.internal(builder);
+ result.setupStateForInlining(function, compiledArguments);
+ return result;
+ }
+
+ ConstantSystem get constantSystem => builder.backend.constantSystem;
+ RuntimeTypes get rti => builder.backend.rti;
+ CodegenWorkItem get work => builder.work;
+
+ void emitReturn(HInstruction value, Node node) {
+ IrInliningState state = inliningStack.last;
+ builder.emitted[state.invokeNode] = value;
+ }
+
+ void enterInlinedMethod(FunctionElement function,
+ Node currentNode,
+ List<HInstruction> compiledArguments) {
+ // At this point we are inside the [SsaFromAstInliner] (inlining an AST
+ // function into an IR builder), and we encounter a function invocation that
+ // should be inlined.
+ // When inlining into an IR builder (which is what we are doing here), the
+ // returned value is stored in the builder's [emitted] map using the
+ // function invocation's IrNode as key.
+ // Since we are currently inlining an AST function, the invocation node is
+ // an AST node. A synthetic [IrInlinedInvocationDummy] is added to the
+ // [emitted] map to hold the result of the inlined function.
+ IrNode invokeNode = new IrInlinedInvocationDummy();
+ builder.enterInlinedMethod(function, invokeNode, compiledArguments);
+ }
+
+ void leaveInlinedMethod() {
+ IrInliningState state = inliningStack.last;
+ assert(state.invokeNode is IrInlinedInvocationDummy);
+ HInstruction result = builder.emitted.remove(state.invokeNode);
+ if (result == null) {
+ // When the inlined function is in AST form, it might not have an explicit
+ // [:return:] statement, and the result value might be undefined.
+ assert(!compiler.irBuilder.hasIr(state.function));
+ result = graph.addConstantNull(compiler);
+ }
+ assert(result != null);
+ stack.add(result);
+ builder.leaveInlinedMethod();
+ }
+
+ void doInline(FunctionElement function) {
+ builder.doInline(function);
}
}
@@ -5627,7 +5883,7 @@
* expressions as well.
*/
class StringBuilderVisitor extends Visitor {
- final SsaBuilder builder;
+ final SsaFromAstMixin builder;
final Node diagnosticNode;
/**
@@ -5784,29 +6040,42 @@
}
}
-class InliningState {
+abstract class InliningState {
/**
- * Documentation wanted -- johnniwinther
- *
* Invariant: [function] must be an implementation element.
*/
final FunctionElement function;
+
+ InliningState(this.function) {
+ assert(function.isImplementation);
+ }
+}
+
+class AstInliningState extends InliningState {
final Element oldReturnElement;
final DartType oldReturnType;
final TreeElements oldElements;
final List<HInstruction> oldStack;
final LocalsHandler oldLocalsHandler;
final bool inTryStatement;
+ final SsaFromIrInliner irInliner;
- InliningState(this.function,
- this.oldReturnElement,
- this.oldReturnType,
- this.oldElements,
- this.oldStack,
- this.oldLocalsHandler,
- this.inTryStatement) {
- assert(function.isImplementation);
- }
+ AstInliningState(FunctionElement function,
+ this.oldReturnElement,
+ this.oldReturnType,
+ this.oldElements,
+ this.oldStack,
+ this.oldLocalsHandler,
+ this.inTryStatement,
+ this.irInliner): super(function);
+}
+
+class IrInliningState extends InliningState {
+ final IrNode invokeNode;
+ final SsaFromAstInliner astInliner;
+
+ IrInliningState(FunctionElement function, this.invokeNode, this.astInliner)
+ : super(function);
}
class SsaBranch {
@@ -5820,7 +6089,7 @@
}
class SsaBranchBuilder {
- final SsaBuilder builder;
+ final SsaFromAstMixin builder;
final Node diagnosticNode;
SsaBranchBuilder(this.builder, [this.diagnosticNode]);
@@ -6048,18 +6317,18 @@
}
}
-class TypeBuilder implements DartTypeVisitor<dynamic, SsaBuilder> {
+class TypeBuilder implements DartTypeVisitor<dynamic, SsaFromAstMixin> {
void visitType(DartType type, _) {
throw 'Internal error $type';
}
- void visitVoidType(VoidType type, SsaBuilder builder) {
+ void visitVoidType(VoidType type, SsaFromAstMixin builder) {
ClassElement cls = builder.compiler.findHelper('VoidRuntimeType');
builder.push(new HVoidType(type, new TypeMask.exact(cls)));
}
void visitTypeVariableType(TypeVariableType type,
- SsaBuilder builder) {
+ SsaFromAstMixin builder) {
ClassElement cls = builder.compiler.findHelper('RuntimeType');
TypeMask instructionType = new TypeMask.subclass(cls);
if (!builder.sourceElement.enclosingElement.isClosure() &&
@@ -6073,7 +6342,7 @@
}
}
- void visitFunctionType(FunctionType type, SsaBuilder builder) {
+ void visitFunctionType(FunctionType type, SsaFromAstMixin builder) {
type.returnType.accept(this, builder);
HInstruction returnType = builder.pop();
List<HInstruction> inputs = <HInstruction>[returnType];
@@ -6102,19 +6371,19 @@
builder.push(new HFunctionType(inputs, type, new TypeMask.exact(cls)));
}
- void visitMalformedType(MalformedType type, SsaBuilder builder) {
+ void visitMalformedType(MalformedType type, SsaFromAstMixin builder) {
visitDynamicType(builder.compiler.types.dynamicType, builder);
}
- void visitStatementType(StatementType type, SsaBuilder builder) {
+ void visitStatementType(StatementType type, SsaFromAstMixin builder) {
throw 'not implemented visitStatementType($type)';
}
- void visitGenericType(GenericType type, SsaBuilder builder) {
+ void visitGenericType(GenericType type, SsaFromAstMixin builder) {
throw 'not implemented visitGenericType($type)';
}
- void visitInterfaceType(InterfaceType type, SsaBuilder builder) {
+ void visitInterfaceType(InterfaceType type, SsaFromAstMixin builder) {
List<HInstruction> inputs = <HInstruction>[];
for (DartType typeArgument in type.typeArguments) {
typeArgument.accept(this, builder);
@@ -6129,13 +6398,13 @@
builder.push(new HInterfaceType(inputs, type, new TypeMask.exact(cls)));
}
- void visitTypedefType(TypedefType type, SsaBuilder builder) {
+ void visitTypedefType(TypedefType type, SsaFromAstMixin builder) {
DartType unaliased = type.unalias(builder.compiler);
if (unaliased is TypedefType) throw 'unable to unalias $type';
unaliased.accept(this, builder);
}
- void visitDynamicType(DynamicType type, SsaBuilder builder) {
+ void visitDynamicType(DynamicType type, SsaFromAstMixin builder) {
ClassElement cls = builder.compiler.findHelper('DynamicRuntimeType');
builder.push(new HDynamicType(type, new TypeMask.exact(cls)));
}
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/from_ir_builder.dart b/sdk/lib/_internal/compiler/implementation/ssa/from_ir_builder.dart
index 84b6a6c..f5aa966 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/from_ir_builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/from_ir_builder.dart
@@ -16,9 +16,8 @@
Element element = work.element.implementation;
return compiler.withCurrentElement(element, () {
HInstruction.idCounter = 0;
-
- SsaFromIrBuilder builder = new SsaFromIrBuilder(backend, work);
-
+ SsaFromIrBuilder builder =
+ new SsaFromIrBuilder(backend, work, backend.emitter.nativeEmitter);
HGraph graph;
ElementKind kind = element.kind;
if (kind == ElementKind.GENERATIVE_CONSTRUCTOR) {
@@ -50,7 +49,8 @@
* This class contains code that is shared between [SsaFromIrBuilder] and
* [SsaFromIrInliner].
*/
-abstract class SsaFromIrMixin implements SsaGraphBuilderMixin<IrNode> {
+abstract class SsaFromIrMixin
+ implements IrNodesVisitor, SsaBuilderMixin<IrNode> {
/**
* Maps IR expressions to the generated [HInstruction]. Because the IR is
* in an SSA form, the arguments of an [IrNode] have already been visited
@@ -60,13 +60,30 @@
final Map<IrExpression, HInstruction> emitted =
new Map<IrExpression, HInstruction>();
- Compiler get compiler;
+ /**
+ * This method sets up the state of the IR visitor for inlining an invocation
+ * of [function].
+ */
+ void setupStateForInlining(FunctionElement function,
+ List<HInstruction> compiledArguments) {
+ // TODO(lry): once the IR supports functions with parameters or dynamic
+ // invocations, map the parameters (and [:this:]) to the argument
+ // instructions by extending the [emitted] mapping.
+ assert(function.computeSignature(compiler).parameterCount == 0);
+ }
- void emitReturn(HInstruction value, IrReturn node);
+ /**
+ * Run this builder on the body of the [function] to be inlined.
+ */
+ void visitInlinedFunction(FunctionElement function) {
+ assert(compiler.irBuilder.hasIr(function));
+ potentiallyCheckInlinedParameterTypes(function);
+ IrFunction functionNode = compiler.irBuilder.getIr(function);
+ visitAll(functionNode.statements);
+ }
- HInstruction addExpression(IrExpression irNode, HInstruction ssaNode) {
+ void addExpression(IrExpression irNode, HInstruction ssaNode) {
current.add(emitted[irNode] = ssaNode);
- return ssaNode;
}
HInstruction attachPosition(HInstruction target, IrNode node) {
@@ -88,7 +105,7 @@
}
bool providedArgumentsKnownToBeComplete(IrNode currentNode) {
- // See comment in [SsaBuilder.providedArgumentsKnownToBeComplete].
+ // See comment in [SsaFromAstBuilder.providedArgumentsKnownToBeComplete].
return false;
}
@@ -96,22 +113,33 @@
return nodes.map((e) => emitted[e]).toList(growable: false);
}
- HInstruction createInvokeStatic(IrNode node,
- Element element,
- List<HInstruction> arguments,
- [TypeMask type]) {
-// TODO(lry): enable inlining when building from IR.
-// if (tryInlineMethod(element, null, arguments, node)) {
-// return emitted[node];
-// }
- if (type == null) {
- type = TypeMaskFactory.inferredReturnTypeForElement(element, compiler);
+ void addInvokeStatic(IrInvokeStatic node,
+ FunctionElement function,
+ List<HInstruction> arguments,
+ [TypeMask type]) {
+ if (tryInlineMethod(function, null, arguments, node)) {
+ // When encountering a [:return:] instruction in the inlined function,
+ // the value in the [emitted] map is updated. This is performed either
+ // by [SsaFromIrBuilder.emitReturn] (if this is an [SsaFromIrBuilder] or
+ // and [SsaFromAstInliner]), or by [SsaFromAstInliner.leaveInlinedMethod]
+ // if this is an [SsaFromIrInliner].
+ // If the inlined function is in AST form, it might not have an explicit
+ // [:return:] statement and therefore the return value can be [:null:].
+ if (emitted[node] == null) {
+ // IR functions should always have an explicit [:return:].
+ assert(!compiler.irBuilder.hasIr(function.implementation));
+ emitted[node] = graph.addConstantNull(compiler);
+ }
+ return;
}
- bool targetCanThrow = !compiler.world.getCannotThrow(element);
+ if (type == null) {
+ type = TypeMaskFactory.inferredReturnTypeForElement(function, compiler);
+ }
+ bool targetCanThrow = !compiler.world.getCannotThrow(function);
HInvokeStatic instruction = new HInvokeStatic(
- element.declaration, arguments, type, targetCanThrow: targetCanThrow);
- instruction.sideEffects = compiler.world.getSideEffectsOfElement(element);
- return attachPosition(instruction, node);
+ function.declaration, arguments, type, targetCanThrow: targetCanThrow);
+ instruction.sideEffects = compiler.world.getSideEffectsOfElement(function);
+ addExpression(node, attachPosition(instruction, node));
}
void visitIrConstant(IrConstant node) {
@@ -119,11 +147,9 @@
}
void visitIrInvokeStatic(IrInvokeStatic node) {
- Element element = node.target;
- assert(element.isFunction());
+ FunctionElement function = node.target;
List<HInstruction> arguments = toInstructionList(node.arguments);
- HInstruction instruction = createInvokeStatic(node, element, arguments);
- addExpression(node, instruction);
+ addInvokeStatic(node, function, arguments);
}
void visitIrNode(IrNode node) {
@@ -131,7 +157,6 @@
}
void visitIrReturn(IrReturn node) {
- assert(isReachable);
HInstruction value = emitted[node.value];
// TODO(lry): add code for dynamic type check.
// value = potentiallyCheckType(value, returnType);
@@ -140,24 +165,32 @@
}
/**
- * This builder generates SSA nodes for elements that have an IR representation.
- * It mixes in [SsaGraphBuilderMixin] to share functionality with the
- * [SsaBuilder] that creates SSA nodes from trees.
+ * This builder generates SSA nodes for IR functions. It mixes in
+ * [SsaBuilderMixin] to share functionality with the [SsaFromAstBuilder] that
+ * creates SSA nodes from trees.
*/
class SsaFromIrBuilder extends IrNodesVisitor with
- SsaGraphBuilderMixin<IrNode>,
+ SsaBuilderMixin<IrNode>,
SsaFromIrMixin,
- SsaGraphBuilderFields<IrNode> {
+ SsaBuilderFields<IrNode> {
final Compiler compiler;
-
final JavaScriptBackend backend;
+ final CodegenWorkItem work;
- SsaFromIrBuilder(JavaScriptBackend backend, CodegenWorkItem work)
+ /* See comment on [SsaFromAstBuilder.nativeEmitter]. */
+ final NativeEmitter nativeEmitter;
+
+ SsaFromIrBuilder(JavaScriptBackend backend,
+ CodegenWorkItem work,
+ this.nativeEmitter)
: this.backend = backend,
- this.compiler = backend.compiler {
+ this.compiler = backend.compiler,
+ this.work = work {
sourceElementStack.add(work.element);
}
+ final List<IrInliningState> inliningStack = <IrInliningState>[];
+
HGraph buildMethod() {
FunctionElement functionElement = sourceElement.implementation;
graph.calledInLoop = compiler.world.isCalledInLoop(functionElement);
@@ -175,22 +208,49 @@
}
void emitReturn(HInstruction value, IrReturn node) {
- closeAndGotoExit(attachPosition(new HReturn(value), node));
+ if (inliningStack.isEmpty) {
+ closeAndGotoExit(attachPosition(new HReturn(value), node));
+ } else {
+ IrInliningState state = inliningStack.last;
+ emitted[state.invokeNode] = value;
+ }
}
- void setupInliningState(FunctionElement function,
+ /**
+ * This method is invoked before inlining the body of [function] into this
+ * [SsaFromIrBuilder]. The inlined function can be either in AST or IR.
+ *
+ * The method is also invoked from the [SsaFromAstInliner], that is, if we
+ * are currently inlining an AST function and encounter a function invocation
+ * that should be inlined.
+ */
+ void enterInlinedMethod(FunctionElement function,
+ IrNode callNode,
List<HInstruction> compiledArguments) {
- // TODO(lry): inlining when building from IR.
- throw "setup inlining for $function";
+ bool hasIr = compiler.irBuilder.hasIr(function);
+
+ SsaFromAstInliner astInliner;
+ if (!hasIr) {
+ astInliner = new SsaFromAstInliner(this, function, compiledArguments);
+ }
+
+ IrInliningState state = new IrInliningState(function, callNode, astInliner);
+ inliningStack.add(state);
+ if (hasIr) {
+ setupStateForInlining(function, compiledArguments);
+ }
}
void leaveInlinedMethod() {
- // TODO(lry): inlining when building from IR.
- throw "leave inlining in ir";
+ inliningStack.removeLast();
}
- void doInline(Element element) {
- // TODO(lry): inlining when building from IR.
- throw "inline ir in ir for $element";
+ void doInline(FunctionElement function) {
+ if (compiler.irBuilder.hasIr(function)) {
+ visitInlinedFunction(function);
+ } else {
+ IrInliningState state = inliningStack.last;
+ state.astInliner.visitInlinedFunction(function);
+ }
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/from_ir_inliner.dart b/sdk/lib/_internal/compiler/implementation/ssa/from_ir_inliner.dart
index d802603..e88f130 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/from_ir_inliner.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/from_ir_inliner.dart
@@ -6,59 +6,47 @@
/**
* This class implements an [IrNodesVisitor] that inlines a function represented
- * as IR into an [SsaBuilder].
+ * as IR into an [SsaFromAstBuilder].
*/
-class SsaFromIrInliner
- extends IrNodesVisitor with SsaGraphBuilderMixin<IrNode>, SsaFromIrMixin {
- final SsaBuilder builder;
+class SsaFromIrInliner extends IrNodesVisitor with
+ SsaBuilderMixin<IrNode>,
+ SsaFromIrMixin,
+ SsaBuilderDelegate<IrNode, Node> {
+ final SsaFromAstBuilder builder;
- SsaFromIrInliner(this.builder);
+ SsaFromIrInliner.internal(this.builder);
- Compiler get compiler => builder.compiler;
-
- JavaScriptBackend get backend => builder.backend;
-
- Element get sourceElement => builder.sourceElementStack.last;
-
- HGraph get graph => builder.graph;
-
- HBasicBlock get current => builder.current;
-
- void set current(HBasicBlock block) {
- builder.current = block;
+ factory SsaFromIrInliner(SsaFromAstBuilder builder,
+ FunctionElement function,
+ List<HInstruction> compiledArguments) {
+ SsaFromIrInliner irInliner = new SsaFromIrInliner.internal(builder);
+ irInliner.setupStateForInlining(function, compiledArguments);
+ return irInliner;
}
- HBasicBlock get lastOpenedBlock => builder.lastOpenedBlock;
+ final List<IrExpression> inlinedCalls = <IrExpression>[];
- void set lastOpenedBlock(HBasicBlock block) {
- builder.lastOpenedBlock = block;
- }
-
- bool get isReachable => builder.isReachable;
-
- void set isReachable(bool value) {
- builder.isReachable = value;
- }
-
- bool get inThrowExpression => builder.inThrowExpression;
-
- int get loopNesting => builder.loopNesting;
-
- List<InliningState> get inliningStack => builder.inliningStack;
-
- List<Element> get sourceElementStack => builder.sourceElementStack;
-
- void setupInliningState(FunctionElement function,
+ /**
+ * This function is invoked when we are currently inlining an IR function
+ * into an AST builder, and we encounter an infocation that is inlined.
+ */
+ void enterInlinedMethod(FunctionElement function,
+ IrNode callNode,
List<HInstruction> compiledArguments) {
- builder.setupInliningState(function, compiledArguments);
+ assert(callNode != null);
+ inlinedCalls.add(callNode);
+ builder.enterInlinedMethod(function, null, compiledArguments);
}
void leaveInlinedMethod() {
builder.leaveInlinedMethod();
+ // [leaveInlinedMethod] pushes the returned value on the builder's stack,
+ // no matter if the inlined function is represented in AST or IR.
+ emitted[inlinedCalls.removeLast()] = builder.pop();
}
- void doInline(Element element) {
- builder.doInline(element);
+ void doInline(FunctionElement function) {
+ builder.doInline(function);
}
void emitReturn(HInstruction value, IrReturn node) {
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/interceptor_simplifier.dart b/sdk/lib/_internal/compiler/implementation/ssa/interceptor_simplifier.dart
index e4a4ad8..5cf4392 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/interceptor_simplifier.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/interceptor_simplifier.dart
@@ -186,7 +186,7 @@
if (interceptedClasses.contains(backend.jsNumberClass)
&& !(interceptedClasses.contains(backend.jsDoubleClass)
|| interceptedClasses.contains(backend.jsIntClass))) {
- for (var user in node.usedBy) {
+ for (HInstruction user in node.usedBy) {
if (user is! HInvoke) continue;
Set<ClassElement> intercepted =
backend.getInterceptedClassesOn(user.selector.name);
@@ -200,7 +200,7 @@
}
} else {
interceptedClasses = new Set<ClassElement>();
- for (var user in node.usedBy) {
+ for (HInstruction user in node.usedBy) {
if (user is HIs) {
// Is-checks can be performed on any intercepted class.
interceptedClasses.addAll(backend.interceptedClasses);
@@ -215,8 +215,7 @@
HInstruction receiver = node.receiver;
if (canUseSelfForInterceptor(receiver, interceptedClasses)) {
- node.block.rewrite(node, receiver);
- return false;
+ return rewriteToUseSelfAsInterceptor(node, receiver);
}
// Try computing a constant interceptor.
@@ -254,6 +253,51 @@
return true;
}
+ bool rewriteToUseSelfAsInterceptor(HInterceptor node, HInstruction receiver) {
+ // `rewrite` below clears `node.usedBy`.
+ List<HInstruction> originalUsers = node.usedBy.toList();
+
+ node.block.rewrite(node, receiver);
+
+ // We have just rewritten:
+ //
+ // m = getInterceptor(a)
+ // m.foo$1(a, x)
+ // -->
+ // m = getInterceptor(a)
+ // a.foo$1(a, x)
+ //
+ // For the rewritten calls, if the selector matches only methods that ignore
+ // the explicit receiver parameter, replace occurences of the receiver
+ // argument with a dummy receiver '0':
+ //
+ // a.foo$1(a, x) --> a.foo$1(0, x)
+ //
+ JavaScriptBackend backend = compiler.backend;
+ for (HInstruction user in originalUsers) {
+ if (user is HInvokeDynamic) {
+ HInvokeDynamic invoke = user;
+ if (invoke.receiver == receiver &&
+ !backend.isInterceptedMixinSelector(invoke.selector)) {
+ HInstruction receiverArgument = invoke.inputs[1];
+ // TODO(15720): The test here should be
+ //
+ // invoke.receiver.nonCheck() == receiverArgument.nonCheck()
+ //
+ if (invoke.receiver == receiverArgument) { // recognize a.foo(a,...)
+ Constant constant = new DummyReceiverConstant(
+ receiverArgument.instructionType);
+ HConstant dummy = graph.addConstant(constant, compiler);
+ receiverArgument.usedBy.remove(invoke);
+ invoke.inputs[1] = dummy;
+ dummy.usedBy.add(invoke);
+ }
+ }
+ }
+ }
+ return false;
+ }
+
bool visitOneShotInterceptor(HOneShotInterceptor node) {
HInstruction constant = tryComputeConstantInterceptor(
node.inputs[1], node.interceptedClasses);
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart b/sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart
index daf4f1e..727a7d4 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart
@@ -388,12 +388,12 @@
if (left.isUInt31(compiler)) {
return newBuiltinVariant(instruction, compiler);
}
- clearAllSideEffects(instruction);
// We can call _tdivFast because the rhs is a 32bit integer
// and not 0, nor -1.
instruction.selector = renameToOptimizedSelector(
'_tdivFast', instruction.selector, compiler);
}
+ clearAllSideEffects(instruction);
}
return null;
}
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
index 64b666c..ea74d96 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
@@ -1414,9 +1414,9 @@
bool canThrow() => targetCanThrow;
/// If this instruction is a call to a constructor, [instantiatedTypes]
- /// contains the type(s) used in the (Dart) `New` expression(s).
- /// The [instructionType] of this node is not enough, because we also need
- /// the type arguments. See also [SsaBuilder.currentInlinedInstantiations].
+ /// contains the type(s) used in the (Dart) `New` expression(s). The
+ /// [instructionType] of this node is not enough, because we also need the
+ /// type arguments. See also [SsaFromAstMixin.currentInlinedInstantiations].
List<DartType> instantiatedTypes;
/** The first input must be the target. */
@@ -1424,7 +1424,7 @@
{this.targetCanThrow: true})
: super(inputs, type);
- toString() => 'invoke static: ${element.name}';
+ toString() => 'invoke static: $element';
accept(HVisitor visitor) => visitor.visitInvokeStatic(this);
int typeCode() => HInstruction.INVOKE_STATIC_TYPECODE;
}
@@ -1605,9 +1605,9 @@
ClassElement element;
/// If this field is not `null`, this call is from an inlined constructor and
- /// we have to register the instantiated type in the code generator.
- /// The [instructionType] of this node is not enough, because we also need
- /// the type arguments. See also [SsaBuilder.currentInlinedInstantiations].
+ /// we have to register the instantiated type in the code generator. The
+ /// [instructionType] of this node is not enough, because we also need the
+ /// type arguments. See also [SsaFromAstMixin.currentInlinedInstantiations].
List<DartType> instantiatedTypes;
HForeignNew(this.element, TypeMask type, List<HInstruction> inputs,
@@ -1837,7 +1837,7 @@
/**
* Signals that this is a special break instruction for the synthetic loop
* generatedfor a switch statement with continue statements. See
- * [SsaBuilder.buildComplexSwitchStatement] for detail.
+ * [SsaFromAstMixin.buildComplexSwitchStatement] for detail.
*/
final bool breakSwitchContinueLoop;
HBreak(TargetElement target, {bool this.breakSwitchContinueLoop: false})
@@ -1931,6 +1931,14 @@
// Maybe avoid this if the literal is big?
bool isCodeMotionInvariant() => true;
+
+ set instructionType(type) {
+ // Only lists can be specialized. The SSA builder uses the
+ // inferrer for finding the type of a constant list. We should
+ // have the constant know its type instead.
+ if (!isConstantList()) return;
+ super.instructionType = type;
+ }
}
class HNot extends HInstruction {
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
index 6b8eaaf..cd96172 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
@@ -123,11 +123,19 @@
if (replacement != instruction) {
block.rewrite(instruction, replacement);
- // If we can replace [instruction] with [replacement], then
- // [replacement]'s type can be narrowed.
- TypeMask newType = replacement.instructionType.intersection(
- instruction.instructionType, compiler);
- replacement.instructionType = newType;
+ // The intersection of double and int return conflicting, and
+ // because of our number implementation for JavaScript, it
+ // might be that an operation thought to return double, can be
+ // simplified to an int. For example:
+ // `2.5 * 10`.
+ if (!(replacement.isNumberOrNull(compiler)
+ && instruction.isNumberOrNull(compiler))) {
+ // If we can replace [instruction] with [replacement], then
+ // [replacement]'s type can be narrowed.
+ TypeMask newType = replacement.instructionType.intersection(
+ instruction.instructionType, compiler);
+ replacement.instructionType = newType;
+ }
// If the replacement instruction does not know its
// source element, use the source element of the
diff --git a/sdk/lib/_internal/compiler/implementation/universe/universe.dart b/sdk/lib/_internal/compiler/implementation/universe/universe.dart
index eed40c8..36181ce 100644
--- a/sdk/lib/_internal/compiler/implementation/universe/universe.dart
+++ b/sdk/lib/_internal/compiler/implementation/universe/universe.dart
@@ -334,8 +334,10 @@
}
if (isGetter()) return true;
if (isSetter()) return false;
+ return signatureApplies(element, compiler);
+ }
- FunctionElement function = element;
+ bool signatureApplies(FunctionElement function, Compiler compiler) {
FunctionSignature parameters = function.computeSignature(compiler);
if (argumentCount > parameters.parameterCount) return false;
int requiredParameterCount = parameters.requiredParameterCount;
diff --git a/sdk/lib/_internal/compiler/implementation/warnings.dart b/sdk/lib/_internal/compiler/implementation/warnings.dart
index e1a8516..5d5c72d 100644
--- a/sdk/lib/_internal/compiler/implementation/warnings.dart
+++ b/sdk/lib/_internal/compiler/implementation/warnings.dart
@@ -970,6 +970,15 @@
error: const MessageKind("Error: Cannot resolve setter."),
warning: const MessageKind("Warning: Cannot resolve setter."));
+ static const DualKind ASSIGNING_METHOD = const DualKind(
+ error: const MessageKind("Error: Cannot resolve setter."),
+ warning:
+ const MessageKind("Warning: Cannot assign a value to a method."));
+
+ static const DualKind ASSIGNING_TYPE = const DualKind(
+ error: const MessageKind("Error: Cannot resolve setter."),
+ warning: const MessageKind("Warning: Cannot assign a value to a type."));
+
static const MessageKind VOID_NOT_ALLOWED = const MessageKind(
"Error: Type 'void' can't be used here because it isn't a return type.",
howToFix: "Try removing 'void' keyword or replace it with 'var', 'final',"
diff --git a/sdk/lib/_internal/lib/annotations.dart b/sdk/lib/_internal/lib/annotations.dart
index 66d4818..23f1234 100644
--- a/sdk/lib/_internal/lib/annotations.dart
+++ b/sdk/lib/_internal/lib/annotations.dart
@@ -21,3 +21,10 @@
class NoInline {
const NoInline();
}
+
+// Ensures that the annotated method is represented internally using
+// IR nodes ([:value == true:]) or AST nodes ([:value == false:]).
+class IrRepresentation {
+ final bool value;
+ const IrRepresentation(this.value);
+}
diff --git a/sdk/lib/_internal/lib/interceptors.dart b/sdk/lib/_internal/lib/interceptors.dart
index 3bab8fd..1562b57 100644
--- a/sdk/lib/_internal/lib/interceptors.dart
+++ b/sdk/lib/_internal/lib/interceptors.dart
@@ -180,8 +180,7 @@
var mapTypeToInterceptor;
int findIndexForNativeSubclassType(Type type) {
- JS_EFFECT((_){ mapTypeToInterceptor = _; });
- if (mapTypeToInterceptor == null) return null;
+ if (JS('bool', '# == null', mapTypeToInterceptor)) return null;
List map = JS('JSFixedArray', '#', mapTypeToInterceptor);
for (int i = 0; i + 1 < map.length; i += 3) {
if (type == map[i]) {
@@ -195,7 +194,7 @@
var index = findIndexForNativeSubclassType(type);
if (index == null) return null;
List map = JS('JSFixedArray', '#', mapTypeToInterceptor);
- return mapTypeToInterceptor[index + 1];
+ return map[index + 1];
}
/**
@@ -208,7 +207,7 @@
var index = findIndexForNativeSubclassType(type);
if (index == null) return null;
List map = JS('JSFixedArray', '#', mapTypeToInterceptor);
- var constructorMap = mapTypeToInterceptor[index + 2];
+ var constructorMap = map[index + 2];
var constructorFn = JS('', '#[#]', constructorMap, name);
return constructorFn;
}
diff --git a/sdk/lib/_internal/lib/io_patch.dart b/sdk/lib/_internal/lib/io_patch.dart
index 2f3db18..88e4f86 100644
--- a/sdk/lib/_internal/lib/io_patch.dart
+++ b/sdk/lib/_internal/lib/io_patch.dart
@@ -83,6 +83,9 @@
patch static _renameLink(String oldPath, String newPath) {
throw new UnsupportedError("File._renameLink");
}
+ patch static _copy(String oldPath, String newPath) {
+ throw new UnsupportedError("File._copy");
+ }
patch static _lengthFromPath(String path) {
throw new UnsupportedError("File._lengthFromPath");
}
@@ -182,6 +185,9 @@
patch static int _pid(Process process) {
throw new UnsupportedError("ProcessUtils._pid");
}
+ patch static Stream<ProcessSignal> _watchSignal(ProcessSignal signal) {
+ throw new UnsupportedError("ProcessUtils._watchSignal");
+ }
}
patch class Process {
@@ -310,7 +316,7 @@
patch static Stdin _getStdioInputStream() {
throw new UnsupportedError("StdIOUtils._getStdioInputStream");
}
- patch static IOSink _getStdioOutputStream(int fd) {
+ patch static _getStdioOutputStream(int fd) {
throw new UnsupportedError("StdIOUtils._getStdioOutputStream");
}
patch static int _socketType(nativeSocket) {
@@ -357,6 +363,18 @@
}
}
+patch class Stdout {
+ patch bool get hasTerminal {
+ throw new UnsupportedError("Stdout.hasTerminal");
+ }
+ patch int get terminalColumns {
+ throw new UnsupportedError("Stdout.terminalColumns");
+ }
+ patch int get terminalLines {
+ throw new UnsupportedError("Stdout.terminalLines");
+ }
+}
+
patch class _FileSystemWatcher {
patch static Stream<FileSystemEvent> watch(
String path, int events, bool recursive) {
diff --git a/sdk/lib/_internal/lib/isolate_patch.dart b/sdk/lib/_internal/lib/isolate_patch.dart
index 560fb1f..45de5af 100644
--- a/sdk/lib/_internal/lib/isolate_patch.dart
+++ b/sdk/lib/_internal/lib/isolate_patch.dart
@@ -12,23 +12,31 @@
patch class Isolate {
patch static Future<Isolate> spawn(void entryPoint(message), var message) {
- return IsolateNatives.spawnFunction(entryPoint, message)
- .then((controlPort) => new Isolate._fromControlPort(controlPort));
+ try {
+ return IsolateNatives.spawnFunction(entryPoint, message)
+ .then((controlPort) => new Isolate._fromControlPort(controlPort));
+ } catch (e, st) {
+ return new Future<Isolate>.error(e, st);
+ }
}
patch static Future<Isolate> spawnUri(
Uri uri, List<String> args, var message) {
- if (args is List<String>) {
- for (int i = 0; i < args.length; i++) {
- if (args[i] is! String) {
- throw new ArgumentError("Args must be a list of Strings $args");
+ try {
+ if (args is List<String>) {
+ for (int i = 0; i < args.length; i++) {
+ if (args[i] is! String) {
+ throw new ArgumentError("Args must be a list of Strings $args");
+ }
}
+ } else if (args != null) {
+ throw new ArgumentError("Args must be a list of Strings $args");
}
- } else if (args != null) {
- throw new ArgumentError("Args must be a list of Strings $args");
+ return IsolateNatives.spawnUri(uri, args, message)
+ .then((controlPort) => new Isolate._fromControlPort(controlPort));
+ } catch (e, st) {
+ return new Future<Isolate>.error(e, st);
}
- return IsolateNatives.spawnUri(uri, args, message)
- .then((controlPort) => new Isolate._fromControlPort(controlPort));
}
}
diff --git a/sdk/lib/_internal/lib/js_array.dart b/sdk/lib/_internal/lib/js_array.dart
index 9ce29f9..730d063 100644
--- a/sdk/lib/_internal/lib/js_array.dart
+++ b/sdk/lib/_internal/lib/js_array.dart
@@ -269,11 +269,11 @@
if (end < start || end > receiverLength) {
throw new RangeError.range(end, start, receiverLength);
}
- Arrays.copy(this,
- end,
- this,
- start,
- receiverLength - end);
+ Lists.copy(this,
+ end,
+ this,
+ start,
+ receiverLength - end);
this.length = receiverLength - (end - start);
}
diff --git a/sdk/lib/_internal/lib/js_mirrors.dart b/sdk/lib/_internal/lib/js_mirrors.dart
index f27c8cc..18829bf 100644
--- a/sdk/lib/_internal/lib/js_mirrors.dart
+++ b/sdk/lib/_internal/lib/js_mirrors.dart
@@ -67,12 +67,12 @@
final IsolateMirror isolate = new JsIsolateMirror();
- TypeMirror get dynamicType => _dynamicType;
- TypeMirror get voidType => _voidType;
+ JsTypeMirror get dynamicType => _dynamicType;
+ JsTypeMirror get voidType => _voidType;
- final static TypeMirror _dynamicType =
+ final static JsTypeMirror _dynamicType =
new JsTypeMirror(const Symbol('dynamic'));
- final static TypeMirror _voidType = new JsTypeMirror(const Symbol('void'));
+ final static JsTypeMirror _voidType = new JsTypeMirror(const Symbol('void'));
static final Map<String, List<LibraryMirror>> librariesByName =
computeLibrariesByName();
@@ -226,6 +226,8 @@
return _cachedUpperBound = typeMirrorFromRuntimeTypeRepresentation(
owner, getMetadata(_typeVariable.bound));
}
+
+ _asRuntimeType() => _metadataIndex;
}
class JsTypeMirror extends JsDeclarationMirror implements TypeMirror {
@@ -244,7 +246,7 @@
bool get hasReflectedType => false;
Type get reflectedType {
- throw new UnsupportedError("This type does not support reflectedTypees");
+ throw new UnsupportedError("This type does not support reflectedType");
}
List<TypeVariableMirror> get typeVariables => const <TypeVariableMirror>[];
@@ -252,6 +254,12 @@
bool get isOriginalDeclaration => true;
TypeMirror get originalDeclaration => this;
+
+ _asRuntimeType() {
+ if (this == JsMirrorSystem._dynamicType) return null;
+ if (this == JsMirrorSystem._voidType) return null;
+ throw new RuntimeError('Should not call _asRuntimeType');
+ }
}
class JsLibraryMirror extends JsDeclarationMirror with JsObjectMirror
@@ -713,6 +721,8 @@
Map<Symbol, DeclarationMirror> get declarations => mixin.declarations;
+ _asRuntimeType() => null;
+
InstanceMirror invoke(
Symbol memberName,
List positionalArguments,
@@ -963,7 +973,16 @@
super(originalDeclaration.simpleName);
String get _prettyName => 'ClassMirror';
- String get _mangledName => '${_class._mangledName}<$_typeArguments>';
+ String get _mangledName {
+ for (TypeMirror typeArgument in typeArguments) {
+ if (typeArgument != JsMirrorSystem._dynamicType) {
+ return '${_class._mangledName}<$_typeArguments>';
+ }
+ }
+ // When all type arguments are dynamic, the canonical representation is to
+ // drop them.
+ return _class._mangledName;
+ }
List<TypeVariableMirror> get typeVariables => _class.typeVariables;
@@ -1082,9 +1101,16 @@
InstanceMirror newInstance(Symbol constructorName,
List positionalArguments,
[Map<Symbol, dynamic> namedArguments]) {
- return _class.newInstance(constructorName,
- positionalArguments,
- namedArguments);
+ var instance = _class._getInvokedInstance(constructorName,
+ positionalArguments,
+ namedArguments);
+ return reflect(setRuntimeTypeInfo(
+ instance, typeArguments.map((t) => t._asRuntimeType()).toList()));
+ }
+
+ _asRuntimeType() {
+ return [_class._jsConstructor].addAll(
+ typeArguments.map((t) => t._asRuntimeType()));
}
JsLibraryMirror get owner => _class.owner;
@@ -1116,8 +1142,6 @@
return _cachedSuperinterfaces = _class._getSuperinterfacesWithOwner(this);
}
- bool get hasReflectedType => _class.hasReflectedType;
-
bool get isPrivate => _class.isPrivate;
bool get isTopLevel => _class.isTopLevel;
@@ -1128,7 +1152,9 @@
Symbol get qualifiedName => _class.qualifiedName;
- Type get reflectedType => _class.reflectedType;
+ bool get hasReflectedType => true;
+
+ Type get reflectedType => createRuntimeType(_mangledName);
Symbol get simpleName => _class.simpleName;
@@ -1195,6 +1221,15 @@
filterConstructors(_methods));
}
+ _asRuntimeType() {
+ if (typeVariables.isEmpty) return _jsConstructor;
+ var type = [_jsConstructor];
+ for (int i = 0; i < typeVariables.length; i ++) {
+ type.add(JsMirrorSystem._dynamicType._asRuntimeType);
+ }
+ return type;
+ }
+
List<JsMethodMirror> _getMethodsWithOwner(DeclarationMirror methodOwner) {
var prototype = JS('', '#.prototype', _jsConstructor);
List<String> keys = extractKeys(prototype);
@@ -1357,25 +1392,33 @@
throw new NoSuchMethodError(this, fieldName, null, null);
}
+ _getInvokedInstance(Symbol constructorName,
+ List positionalArguments,
+ [Map<Symbol, dynamic> namedArguments]) {
+ if (namedArguments != null && !namedArguments.isEmpty) {
+ throw new UnsupportedError('Named arguments are not implemented.');
+ }
+ JsMethodMirror mirror =
+ JsCache.fetch(_jsConstructorCache, n(constructorName));
+ if (mirror == null) {
+ mirror = __constructors.values.firstWhere(
+ (m) => m.constructorName == constructorName,
+ orElse: () {
+ // TODO(ahe): What receiver to use?
+ throw new NoSuchMethodError(
+ this, constructorName, positionalArguments, namedArguments);
+ });
+ JsCache.update(_jsConstructorCache, n(constructorName), mirror);
+ }
+ return mirror._invoke(positionalArguments, namedArguments);
+ }
+
InstanceMirror newInstance(Symbol constructorName,
List positionalArguments,
[Map<Symbol, dynamic> namedArguments]) {
- if (namedArguments != null && !namedArguments.isEmpty) {
- throw new UnsupportedError('Named arguments are not implemented.');
- }
- JsMethodMirror mirror =
- JsCache.fetch(_jsConstructorCache, n(constructorName));
- if (mirror == null) {
- mirror = __constructors.values.firstWhere(
- (m) => m.constructorName == constructorName,
- orElse: () {
- // TODO(ahe): What receiver to use?
- throw new NoSuchStaticMethodError.missingConstructor(
- this, constructorName, positionalArguments, namedArguments);
- });
- JsCache.update(_jsConstructorCache, n(constructorName), mirror);
- }
- return reflect(mirror._invoke(positionalArguments, namedArguments));
+ return reflect(_getInvokedInstance(constructorName,
+ positionalArguments,
+ namedArguments));
}
JsLibraryMirror get owner {
@@ -1498,6 +1541,16 @@
List<TypeMirror> get typeArguments => const <TypeMirror>[];
+ bool get hasReflectedType => typeVariables.length == 0;
+
+ Type get reflectedType {
+ if (!hasReflectedType) {
+ throw new UnsupportedError(
+ "Declarations of generics have no reflected type");
+ }
+ return createRuntimeType(_mangledName);
+ }
+
// TODO(ahe): Implement this.
Map<Symbol, MethodMirror> get instanceMembers
=> throw new UnimplementedError();
diff --git a/sdk/lib/_internal/lib/js_number.dart b/sdk/lib/_internal/lib/js_number.dart
index b6606f0..7aaeb93 100644
--- a/sdk/lib/_internal/lib/js_number.dart
+++ b/sdk/lib/_internal/lib/js_number.dart
@@ -59,6 +59,8 @@
num abs() => JS('num', r'Math.abs(#)', this);
+ num get sign => this > 0 ? 1 : this < 0 ? -1 : this;
+
static const int _MIN_INT32 = -0x80000000;
static const int _MAX_INT32 = 0x7FFFFFFF;
@@ -240,7 +242,7 @@
}
num operator >>(num other) {
- if (false) _shrReceiverPositive(other);
+ if (false) _shrReceiverPositive(other);
if (other is !num) throw new ArgumentError(other);
if (JS('num', '#', other) < 0) throw new ArgumentError(other);
return _shrOtherPositive(other);
diff --git a/sdk/lib/_internal/lib/js_rti.dart b/sdk/lib/_internal/lib/js_rti.dart
index 3c4da5a..ca1d2d1 100644
--- a/sdk/lib/_internal/lib/js_rti.dart
+++ b/sdk/lib/_internal/lib/js_rti.dart
@@ -161,7 +161,7 @@
/**
* Returns a human-readable representation of the type representation [type].
*/
-String runtimeTypeToString(var type , {String onTypeVariable(int i)}) {
+String runtimeTypeToString(var type, {String onTypeVariable(int i)}) {
if (isNull(type)) {
return 'dynamic';
} else if (isJsArray(type)) {
diff --git a/sdk/lib/_internal/pub/bin/pub.dart b/sdk/lib/_internal/pub/bin/pub.dart
index e19d9a0..451ee6c 100644
--- a/sdk/lib/_internal/pub/bin/pub.dart
+++ b/sdk/lib/_internal/pub/bin/pub.dart
@@ -121,7 +121,7 @@
/// Checks that pub is running on a supported platform. If it isn't, it prints
/// an error message and exits. Completes when the validation is done.
Future validatePlatform() {
- return new Future.sync(() {
+ return syncFuture(() {
if (Platform.operatingSystem != 'windows') return null;
return runProcess('ver', []).then((result) {
diff --git a/sdk/lib/_internal/pub/lib/src/barback.dart b/sdk/lib/_internal/pub/lib/src/barback.dart
index 6f14935..a5a48a6 100644
--- a/sdk/lib/_internal/pub/lib/src/barback.dart
+++ b/sdk/lib/_internal/pub/lib/src/barback.dart
@@ -141,7 +141,7 @@
return BarbackServer.bind(host, port, barback, graph.entrypoint.root.name)
.then((server) {
- return new Future.sync(() {
+ return syncFuture(() {
if (watcher != WatcherType.NONE) {
return watchSources(graph, barback, watcher);
}
@@ -157,7 +157,7 @@
server.barback.errors.listen((error) {
if (error is TransformerException) error = error.error;
if (!completer.isCompleted) {
- completer.completeError(error, new Trace.current());
+ completer.completeError(error, new Chain.current());
}
}),
server.barback.results.listen((_) {}, onError: (error, stackTrace) {
@@ -295,7 +295,7 @@
// Show the level (unless the message mentions it).
if (!messageMentions(entry.level.name)) {
- prefixParts.add("${entry.level} in");
+ prefixParts.add("${entry.level} from");
}
// Show the transformer.
@@ -329,7 +329,7 @@
break;
case LogLevel.INFO:
- log.message("$prefix\n$message");
+ log.message("${log.cyan(prefix)}\n$message");
break;
}
}
diff --git a/sdk/lib/_internal/pub/lib/src/barback/dart2js_transformer.dart b/sdk/lib/_internal/pub/lib/src/barback/dart2js_transformer.dart
index c4b0597..9bb3022 100644
--- a/sdk/lib/_internal/pub/lib/src/barback/dart2js_transformer.dart
+++ b/sdk/lib/_internal/pub/lib/src/barback/dart2js_transformer.dart
@@ -11,6 +11,7 @@
import 'package:analyzer/analyzer.dart';
import 'package:barback/barback.dart';
import 'package:path/path.dart' as path;
+import 'package:stack_trace/stack_trace.dart';
import '../../../../compiler/compiler.dart' as compiler;
import '../../../../compiler/implementation/dart2js.dart'
@@ -101,9 +102,10 @@
// Need to report compile errors to the user in an easily visible way.
// Need to make sure paths in errors are mapped to the original source
// path so they can understand them.
- return dart.compile(entrypoint, provider,
+ return Chain.track(dart.compile(
+ entrypoint, provider,
packageRoot: packageRoot,
- minify: _mode == BarbackMode.RELEASE).then((_) {
+ minify: _mode == BarbackMode.RELEASE)).then((_) {
stopwatch.stop();
transform.logger.info("Took ${stopwatch.elapsed} to compile $id.");
});
@@ -259,6 +261,7 @@
Future<String> _readResource(Uri url) {
// See if the path is within a package. If so, use Barback so we can use
// generated Dart assets.
+
var id = _sourceUrlToId(url);
if (id != null) return _transform.readInputAsString(id);
@@ -266,7 +269,7 @@
// skip Barback and just hit the file system. This will occur at the very
// least for dart2js's implementations of the core libraries.
var sourcePath = path.fromUri(url);
- return new File(sourcePath).readAsString();
+ return Chain.track(new File(sourcePath).readAsString());
}
AssetId _sourceUrlToId(Uri url) {
@@ -274,11 +277,16 @@
var id = specialUrlToId(url);
if (id != null) return id;
- // See if it's a path within the root package.
+ // See if it's a path to a "public" asset within the root package. All
+ // other files in the root package are not visible to transformers, so
+ // should be loaded directly from disk.
var rootDir = _graph.entrypoint.root.dir;
var sourcePath = path.fromUri(url);
- if (isBeneath(sourcePath, rootDir)) {
+ if (isBeneath(sourcePath, path.join(rootDir, "lib")) ||
+ isBeneath(sourcePath, path.join(rootDir, "asset")) ||
+ isBeneath(sourcePath, path.join(rootDir, "web"))) {
var relative = path.relative(sourcePath, from: rootDir);
+
return new AssetId(_graph.entrypoint.root.name, relative);
}
diff --git a/sdk/lib/_internal/pub/lib/src/barback/load_transformers.dart b/sdk/lib/_internal/pub/lib/src/barback/load_transformers.dart
index 7c4e2a1..c92791b 100644
--- a/sdk/lib/_internal/pub/lib/src/barback/load_transformers.dart
+++ b/sdk/lib/_internal/pub/lib/src/barback/load_transformers.dart
@@ -12,6 +12,7 @@
// TODO(nweiz): don't import from "src" once issue 14966 is fixed.
import 'package:barback/src/internal_asset.dart';
import 'package:source_maps/source_maps.dart';
+import 'package:stack_trace/stack_trace.dart';
import '../barback.dart';
import '../dart.dart' as dart;
@@ -542,7 +543,7 @@
/// throws an error, that will also be sent.
void _respond(wrappedMessage, callback(message)) {
var replyTo = wrappedMessage['replyTo'];
- new Future.sync(() => callback(wrappedMessage['message']))
+ syncFuture(() => callback(wrappedMessage['message']))
.then((result) => replyTo.send({'type': 'success', 'value': result}))
.catchError((error, stackTrace) {
// TODO(nweiz): at least MissingInputException should be preserved here.
@@ -565,10 +566,11 @@
'replyTo': receivePort.sendPort
});
- return receivePort.first.then((response) {
+ return Chain.track(receivePort.first).then((response) {
if (response['type'] == 'success') return response['value'];
assert(response['type'] == 'error');
return new Future.error(
- new dart.CrossIsolateException.deserialize(response['error']));
+ new dart.CrossIsolateException.deserialize(response['error']),
+ new Chain.current());
});
}
diff --git a/sdk/lib/_internal/pub/lib/src/barback/server.dart b/sdk/lib/_internal/pub/lib/src/barback/server.dart
index f491aab..cb6c46e 100644
--- a/sdk/lib/_internal/pub/lib/src/barback/server.dart
+++ b/sdk/lib/_internal/pub/lib/src/barback/server.dart
@@ -61,7 +61,7 @@
/// root package.
static Future<BarbackServer> bind(String host, int port, Barback barback,
String rootPackage) {
- return HttpServer.bind(host, port)
+ return Chain.track(HttpServer.bind(host, port))
.then((server) => new BarbackServer._(server, barback, rootPackage));
}
@@ -69,7 +69,7 @@
: _server = server,
port = server.port,
address = server.address {
- _server.listen(_handleRequest, onError: (error, stackTrace) {
+ Chain.track(_server).listen(_handleRequest, onError: (error, stackTrace) {
_resultsController.addError(error, stackTrace);
close();
});
@@ -115,7 +115,7 @@
_resultsController.add(
new BarbackServerResult._success(request.uri, id));
// TODO(rnystrom): Set content-type based on asset type.
- return request.response.addStream(stream).then((_) {
+ return Chain.track(request.response.addStream(stream)).then((_) {
// Log successful requests both so we can provide debugging
// information and so scheduled_test knows we haven't timed out while
// loading transformers.
@@ -134,7 +134,7 @@
return;
}
- trace = new Trace.from(trace);
+ trace = new Chain.forTrace(trace);
_logRequest(request, "$error\n$trace");
// Otherwise, it's some internal error.
@@ -145,7 +145,7 @@
});
}).catchError((error, trace) {
if (error is! AssetNotFoundException) {
- trace = new Trace.from(trace);
+ trace = new Chain.forTrace(trace);
_logRequest(request, "$error\n$trace");
_resultsController.addError(error, trace);
@@ -161,7 +161,7 @@
/// Creates a web socket for [request] which should be an upgrade request.
void _handleWebSocket(HttpRequest request) {
- WebSocketTransformer.upgrade(request).then((socket) {
+ Chain.track(WebSocketTransformer.upgrade(request)).then((socket) {
socket.listen((data) {
var command;
try {
diff --git a/sdk/lib/_internal/pub/lib/src/command.dart b/sdk/lib/_internal/pub/lib/src/command.dart
index 221bc45..5e0229c 100644
--- a/sdk/lib/_internal/pub/lib/src/command.dart
+++ b/sdk/lib/_internal/pub/lib/src/command.dart
@@ -88,19 +88,17 @@
cache = new SystemCache.withSources(cacheDir, isOffline: isOffline);
- handleError(error, trace) {
+ handleError(error, Chain chain) {
// This is basically the top-level exception handler so that we don't
// spew a stack trace on our users.
var message;
log.error(getErrorMessage(error));
- if (trace != null) {
- if (options['trace'] || !isUserFacingException(error)) {
- log.error(new Trace.from(trace).terse);
- } else {
- log.fine(new Trace.from(trace).terse);
- }
+ if (options['trace'] || !isUserFacingException(error)) {
+ log.error(chain.terse);
+ } else {
+ log.fine(chain.terse);
}
if (error is ApplicationException && error.innerError != null) {
@@ -124,28 +122,31 @@
return flushThenExit(_chooseExitCode(error));
}
- new Future.sync(() {
- // Make sure there aren't unexpected arguments.
- if (!takesArguments && commandOptions.rest.isNotEmpty) {
- log.error('Command "${commandOptions.name}" does not take any '
- 'arguments.');
- this.printUsage();
- return flushThenExit(exit_codes.USAGE);
- }
+ var captureStackChains =
+ options['trace'] || options['verbose'] || options['verbosity'] == 'all';
+ captureErrors(() {
+ return syncFuture(() {
+ // Make sure there aren't unexpected arguments.
+ if (!takesArguments && commandOptions.rest.isNotEmpty) {
+ log.error('Command "${commandOptions.name}" does not take any '
+ 'arguments.');
+ this.printUsage();
+ return flushThenExit(exit_codes.USAGE);
+ }
- if (requiresEntrypoint) {
- // TODO(rnystrom): Will eventually need better logic to walk up
- // subdirectories until we hit one that looks package-like. For now,
- // just assume the cwd is it.
- entrypoint = new Entrypoint(path.current, cache);
- }
+ if (requiresEntrypoint) {
+ // TODO(rnystrom): Will eventually need better logic to walk up
+ // subdirectories until we hit one that looks package-like. For now,
+ // just assume the cwd is it.
+ entrypoint = new Entrypoint(path.current, cache);
+ }
- var commandFuture = onRun();
- if (commandFuture == null) return true;
+ var commandFuture = onRun();
+ if (commandFuture == null) return true;
- return commandFuture;
- }).whenComplete(() => cache.deleteTempDir())
- .catchError(handleError)
+ return commandFuture;
+ }).whenComplete(() => cache.deleteTempDir());
+ }, captureStackChains: captureStackChains).catchError(handleError)
.then((_) {
// Explicitly exit on success to ensure that any dangling dart:io handles
// don't cause the process to never terminate.
diff --git a/sdk/lib/_internal/pub/lib/src/command/build.dart b/sdk/lib/_internal/pub/lib/src/command/build.dart
index 1c9e37e..b13e4d8 100644
--- a/sdk/lib/_internal/pub/lib/src/command/build.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/build.dart
@@ -44,7 +44,7 @@
Future onRun() {
if (!dirExists(source)) {
- throw new ApplicationException("There is no '$source' directory.");
+ throw new ApplicationException('There is no "$source" directory.');
}
cleanDir(target);
@@ -52,9 +52,7 @@
var dart2jsTransformer;
var builtFiles = 0;
- return entrypoint.ensureLockFileIsUpToDate().then((_) {
- return entrypoint.loadPackageGraph();
- }).then((graph) {
+ return entrypoint.loadPackageGraph().then((graph) {
dart2jsTransformer = new Dart2JSTransformer(graph, mode);
var builtInTransformers = [
dart2jsTransformer,
diff --git a/sdk/lib/_internal/pub/lib/src/command/get.dart b/sdk/lib/_internal/pub/lib/src/command/get.dart
index 51c5f0a..fbe86ae 100644
--- a/sdk/lib/_internal/pub/lib/src/command/get.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/get.dart
@@ -22,7 +22,7 @@
}
Future onRun() {
- return entrypoint.getDependencies()
+ return entrypoint.acquireDependencies()
.then((_) => log.message("Got dependencies!"));
}
}
diff --git a/sdk/lib/_internal/pub/lib/src/command/lish.dart b/sdk/lib/_internal/pub/lib/src/command/lish.dart
index 6d75814..bd9c445 100644
--- a/sdk/lib/_internal/pub/lib/src/command/lish.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/lish.dart
@@ -15,7 +15,6 @@
import '../io.dart';
import '../log.dart' as log;
import '../oauth2.dart' as oauth2;
-import '../sdk.dart' as sdk;
import '../source/hosted.dart';
import '../utils.dart';
import '../validator.dart';
@@ -106,7 +105,7 @@
// Show the package contents so the user can verify they look OK.
var package = entrypoint.root;
log.message(
- 'Publishing "${package.name}" ${package.version} to $server:\n'
+ 'Publishing ${package.name} ${package.version} to $server:\n'
'${generateTree(files, baseDir: entrypoint.root.dir)}');
return createTarGz(files, baseDir: entrypoint.root.dir);
diff --git a/sdk/lib/_internal/pub/lib/src/command/serve.dart b/sdk/lib/_internal/pub/lib/src/command/serve.dart
index f6df4ce..f99df21 100644
--- a/sdk/lib/_internal/pub/lib/src/command/serve.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/serve.dart
@@ -65,9 +65,7 @@
return flushThenExit(exit_codes.USAGE);
}
- return entrypoint.ensureLockFileIsUpToDate().then((_) {
- return entrypoint.loadPackageGraph();
- }).then((graph) {
+ return entrypoint.loadPackageGraph().then((graph) {
var builtInTransformers = [new DartForwardingTransformer(mode)];
if (useDart2JS) {
builtInTransformers.add(new Dart2JSTransformer(graph, mode));
diff --git a/sdk/lib/_internal/pub/lib/src/command/upgrade.dart b/sdk/lib/_internal/pub/lib/src/command/upgrade.dart
index 306e027..a14ab6f 100644
--- a/sdk/lib/_internal/pub/lib/src/command/upgrade.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/upgrade.dart
@@ -26,15 +26,19 @@
}
Future onRun() {
- var future;
- if (commandOptions.rest.isEmpty) {
- future = entrypoint.upgradeAllDependencies();
- } else {
- future = entrypoint.upgradeDependencies(commandOptions.rest);
- }
+ var upgradeAll = commandOptions.rest.isEmpty;
+ return entrypoint.acquireDependencies(useLatest: commandOptions.rest,
+ upgradeAll: upgradeAll).then((numChanged) {
+ // TODO(rnystrom): Show a more detailed message about what was added,
+ // removed, modified, and/or upgraded?
+ if (numChanged == 0) {
+ log.message("No dependencies changed.");
+ } else if (numChanged == 1) {
+ log.message("Changed $numChanged dependency!");
+ } else {
+ log.message("Changed $numChanged dependencies!");
+ }
- return future.then((_) {
- log.message("Dependencies upgraded!");
if (isOffline) {
log.warning("Warning: Upgrading when offline may not update you to the "
"latest versions of your dependencies.");
diff --git a/sdk/lib/_internal/pub/lib/src/command/uploader.dart b/sdk/lib/_internal/pub/lib/src/command/uploader.dart
index 330efcc..5158662 100644
--- a/sdk/lib/_internal/pub/lib/src/command/uploader.dart
+++ b/sdk/lib/_internal/pub/lib/src/command/uploader.dart
@@ -16,6 +16,7 @@
import '../log.dart' as log;
import '../oauth2.dart' as oauth2;
import '../source/hosted.dart';
+import '../utils.dart';
/// Handles the `uploader` pub command.
class UploaderCommand extends PubCommand {
@@ -57,7 +58,7 @@
return flushThenExit(exit_codes.USAGE);
}
- return new Future.sync(() {
+ return syncFuture(() {
var package = commandOptions['package'];
if (package != null) return package;
return new Entrypoint(path.current, cache).root.name;
diff --git a/sdk/lib/_internal/pub/lib/src/dart.dart b/sdk/lib/_internal/pub/lib/src/dart.dart
index bf6cb2a..6833282 100644
--- a/sdk/lib/_internal/pub/lib/src/dart.dart
+++ b/sdk/lib/_internal/pub/lib/src/dart.dart
@@ -12,8 +12,6 @@
import 'package:path/path.dart' as path;
import 'package:stack_trace/stack_trace.dart';
import '../../../compiler/compiler.dart' as compiler;
-import '../../../compiler/implementation/source_file_provider.dart'
- show FormattingDiagnosticHandler, CompilerSourceFileProvider;
import '../../../compiler/implementation/filenames.dart'
show appendSlash;
@@ -53,7 +51,7 @@
/// if [packageRoot] is passed that will be used instead.
Future compile(String entrypoint, CompilerProvider provider, {
String packageRoot, bool toDart: false, bool minify: true}) {
- return new Future.sync(() {
+ return syncFuture(() {
var options = <String>['--categories=Client,Server'];
if (toDart) options.add('--output-type=dart');
if (minify) options.add('--minify');
@@ -62,14 +60,14 @@
packageRoot = path.join(path.dirname(entrypoint), 'packages');
}
- return compiler.compile(
+ return Chain.track(compiler.compile(
path.toUri(entrypoint),
path.toUri(appendSlash(_libPath)),
path.toUri(appendSlash(packageRoot)),
provider.provideInput,
provider.handleDiagnostic,
options,
- provider.provideOutput);
+ provider.provideOutput));
});
}
@@ -106,15 +104,16 @@
var dartPath = path.join(dir, 'runInIsolate.dart');
writeTextFile(dartPath, code, dontLogContents: true);
var port = new ReceivePort();
- return Isolate.spawn(_isolateBuffer, {
+ return Chain.track(Isolate.spawn(_isolateBuffer, {
'replyTo': port.sendPort,
'uri': path.toUri(dartPath).toString(),
'message': message
- }).then((_) => port.first).then((response) {
+ })).then((_) => port.first).then((response) {
if (response['type'] == 'success') return null;
assert(response['type'] == 'error');
return new Future.error(
- new CrossIsolateException.deserialize(response['error']));
+ new CrossIsolateException.deserialize(response['error']),
+ new Chain.current());
});
});
}
@@ -127,11 +126,10 @@
/// Adding an additional isolate in the middle works around this.
void _isolateBuffer(message) {
var replyTo = message['replyTo'];
- // TODO(floitsch): If we do it right we shouldn't need to capture synchronous
- // errors.
- new Future.sync(() {
- return Isolate.spawnUri(Uri.parse(message['uri']), [], message['message']);
- }).then((_) => replyTo.send({'type': 'success'})).catchError((e, stack) {
+ Chain.track(Isolate.spawnUri(
+ Uri.parse(message['uri']), [], message['message']))
+ .then((_) => replyTo.send({'type': 'success'}))
+ .catchError((e, stack) {
replyTo.send({
'type': 'error',
'error': CrossIsolateException.serialize(e, stack)
diff --git a/sdk/lib/_internal/pub/lib/src/entrypoint.dart b/sdk/lib/_internal/pub/lib/src/entrypoint.dart
index cf7e5d0..918736a 100644
--- a/sdk/lib/_internal/pub/lib/src/entrypoint.dart
+++ b/sdk/lib/_internal/pub/lib/src/entrypoint.dart
@@ -17,7 +17,6 @@
import 'solver/version_solver.dart';
import 'system_cache.dart';
import 'utils.dart';
-import 'version.dart';
/// Pub operates over a directed graph of dependencies that starts at a root
/// "entrypoint" package. This is typically the package where the current
@@ -81,7 +80,7 @@
var packageDir = path.join(packagesDir, id.name);
var source;
- var future = new Future.sync(() {
+ var future = syncFuture(() {
ensureDir(path.dirname(packageDir));
if (entryExists(packageDir)) {
@@ -109,60 +108,36 @@
return future;
}
- /// Gets all dependencies of the [root] package, respecting the [LockFile]
- /// if present.
+ /// Gets all dependencies of the [root] package.
///
- /// Returns a [Future] that completes when all dependencies are available.
- Future getDependencies() {
- return new Future.sync(() {
- return resolveVersions(cache.sources, root, lockFile: loadLockFile());
- }).then(_getDependencies);
- }
-
- /// Gets the latest available versions of all dependencies of the [root]
- /// package, writing a new [LockFile].
+ /// [useLatest], if provided, defines a list of packages that will be
+ /// unlocked and forced to their latest versions. If [upgradeAll] is
+ /// true, the previous lockfile is ignored and all packages are re-resolved
+ /// from scratch. Otherwise, it will attempt to preserve the versions of all
+ /// previously locked packages.
///
- /// Returns a [Future] that completes when all dependencies are available.
- Future upgradeAllDependencies() {
- return resolveVersions(cache.sources, root).then(_getDependencies);
- }
-
- /// Gets the latest available versions of [dependencies], while leaving
- /// other dependencies as specified by the [LockFile] if possible.
+ /// If [useLatest] is non-empty or [upgradeAll] is true, displays a detailed
+ /// report of the changes made relative to the previous lockfile.
///
- /// Returns a [Future] that completes when all dependencies are available.
- Future upgradeDependencies(List<String> dependencies) {
- return new Future.sync(() {
- return resolveVersions(cache.sources, root,
- lockFile: loadLockFile(), useLatest: dependencies);
- }).then(_getDependencies);
- }
+ /// Returns a [Future] that completes to the number of changed dependencies.
+ /// It completes when an up-to-date lockfile has been generated and all
+ /// dependencies are available.
+ Future<int> acquireDependencies({List<String> useLatest,
+ bool upgradeAll: false}) {
+ var numChanged = 0;
- /// Removes the old packages directory, gets all dependencies listed in
- /// [result], and writes a [LockFile].
- Future _getDependencies(SolveResult result) {
- return new Future.sync(() {
+ return syncFuture(() {
+ return resolveVersions(cache.sources, root, lockFile: loadLockFile(),
+ useLatest: useLatest, upgradeAll: upgradeAll);
+ }).then((result) {
if (!result.succeeded) throw result.error;
- // Warn the user if any overrides were in effect.
- if (result.overrides.isNotEmpty) {
- var buffer = new StringBuffer();
- buffer.write("Warning: You are using these overridden dependencies:");
- for (var override in result.overrides) {
- var source = cache.sources[override.source];
- buffer.write("\n- ${override.name}");
- if (override.constraint != VersionConstraint.any) {
- buffer.write(" version ${override.constraint}");
- }
- if (source != cache.sources.defaultSource) {
- var description = source.formatDescription(root.dir,
- override.description);
- buffer.write(" (from ${override.source} $description)");
- }
- }
- log.warning(buffer);
- }
+ // TODO(rnystrom): Should also show the report if there were changes.
+ // That way pub get/build/serve will show the report when relevant.
+ // https://code.google.com/p/dart/issues/detail?id=15587
+ numChanged = result.showReport(showAll: useLatest != null || upgradeAll);
+ // Install the packages.
cleanDir(packagesDir);
return Future.wait(result.packages.map((id) {
if (id.isRoot) return new Future.value(id);
@@ -172,6 +147,8 @@
_saveLockFile(ids);
_linkSelf();
_linkSecondaryPackageDirs();
+
+ return numChanged;
});
}
@@ -234,8 +211,8 @@
/// Gets dependencies if the lockfile is out of date with respect to the
/// pubspec.
- Future ensureLockFileIsUpToDate() {
- return new Future.sync(() {
+ Future _ensureLockFileIsUpToDate() {
+ return syncFuture(() {
var lockFile = loadLockFile();
// If we don't have a current lock file, we definitely need to install.
@@ -265,23 +242,48 @@
});
}).then((upToDate) {
if (upToDate) return null;
- return getDependencies().then((_) => log.message("Got dependencies!"));
+ return acquireDependencies().then((_) {
+ log.message("Got dependencies!");
+ });
});
}
+ /// Warns users if they have directory or file named `assets` _anywhere_
+ /// inside `web` directory.
+ void _warnOnAssetsPaths() {
+ var webDir = path.join(root.dir, 'web');
+ if (!dirExists(webDir)) return;
+
+ listDir(webDir, recursive: true)
+ .where((p) => path.basename(p) == 'assets')
+ .forEach((p) {
+ var assetsPath = path.relative(p, from: root.dir);
+ log.warning(
+ 'Warning: Pub reserves paths containing "assets" for using assets '
+ 'from packages. Please rename the path "$assetsPath".');
+ });
+ }
+
+ /// Loads the package graph for the application and all of its transitive
+ /// dependencies. Before loading makes sure the lockfile and dependencies are
+ /// installed and up to date.
+ Future<PackageGraph> loadPackageGraph() =>
+ _ensureLockFileIsUpToDate()
+ .then((_) {
+ _warnOnAssetsPaths();
+ return _loadPackageGraph();
+ });
+
/// Loads the package graph for the application and all of its transitive
/// dependencies.
- Future<PackageGraph> loadPackageGraph() {
+ Future<PackageGraph> _loadPackageGraph() {
var lockFile = loadLockFile();
return Future.wait(lockFile.packages.values.map((id) {
var source = cache.sources[id.source];
return source.getDirectory(id)
.then((dir) => new Package.load(id.name, dir, cache.sources));
})).then((packages) {
- var packageMap = <String, Package>{};
- for (var package in packages) {
- packageMap[package.name] = package;
- }
+ var packageMap = new Map.fromIterable(packages, key: (p) => p.name);
packageMap[root.name] = root;
return new PackageGraph(this, lockFile, packageMap);
});
diff --git a/sdk/lib/_internal/pub/lib/src/http.dart b/sdk/lib/_internal/pub/lib/src/http.dart
index 017b387..afaefd8 100644
--- a/sdk/lib/_internal/pub/lib/src/http.dart
+++ b/sdk/lib/_internal/pub/lib/src/http.dart
@@ -32,10 +32,6 @@
/// it's not supported.
final PUB_API_HEADERS = const {'Accept': 'application/vnd.pub.v2+json'};
-/// Whether dart:io's SecureSocket has been initialized with pub's resources
-/// yet.
-bool _initializedSecureSocket = false;
-
/// An HTTP client that transforms 40* errors and socket exceptions into more
/// user-friendly error messages.
class PubHttpClient extends http.BaseClient {
@@ -44,11 +40,7 @@
http.Client inner;
PubHttpClient([http.Client inner])
- : this.inner = inner == null ? new http.Client() : inner {
- if (!_initializedSecureSocket) {
- SecureSocket.initialize(database: resourcePath('certs'));
- }
- }
+ : this.inner = inner == null ? new http.Client() : inner;
Future<http.StreamedResponse> send(http.BaseRequest request) {
_requestStopwatches[request] = new Stopwatch()..start();
diff --git a/sdk/lib/_internal/pub/lib/src/io.dart b/sdk/lib/_internal/pub/lib/src/io.dart
index bc6ffd1..06bd104 100644
--- a/sdk/lib/_internal/pub/lib/src/io.dart
+++ b/sdk/lib/_internal/pub/lib/src/io.dart
@@ -190,7 +190,7 @@
log.io("Creating $file from stream.");
return _descriptorPool.withResource(() {
- return stream.pipe(new File(file).openWrite()).then((_) {
+ return Chain.track(stream.pipe(new File(file).openWrite())).then((_) {
log.fine("Created $file from stream.");
return file;
});
@@ -372,7 +372,7 @@
// directory since it may just be a leaf application that only has
// code in bin or web.
if (!isSelfLink) {
- log.warning('Warning: Package "$name" does not have a "lib" directory so '
+ log.warning('Warning: Package $name does not have a "lib" directory so '
'you will not be able to import any libraries from it.');
}
}
@@ -404,7 +404,7 @@
/// A line-by-line stream of standard input.
final Stream<String> stdinLines = streamToLines(
- new ByteStream(stdin).toStringStream());
+ new ByteStream(Chain.track(stdin)).toStringStream());
/// Displays a message and reads a yes/no confirmation from the user. Returns
/// a [Future] that completes to `true` if the user confirms or `false` if they
@@ -435,8 +435,12 @@
/// This returns a Future that will never complete, since the program will have
/// exited already. This is useful to prevent Future chains from proceeding
/// after you've decided to exit.
-Future flushThenExit(int status) =>
- Future.wait([stdout.close(), stderr.close()]).then((_) => exit(status));
+Future flushThenExit(int status) {
+ return Future.wait([
+ Chain.track(stdout.close()),
+ Chain.track(stderr.close())
+ ]).then((_) => exit(status));
+}
/// Returns a [EventSink] that pipes all data to [consumer] and a [Future] that
/// will succeed when [EventSink] is closed or fail with any errors that occur
@@ -586,15 +590,16 @@
var pair = consumerToSink(process.stdin);
_stdin = pair.first;
- _stdinClosed = errorGroup.registerFuture(pair.last);
+ _stdinClosed = errorGroup.registerFuture(Chain.track(pair.last));
_stdout = new ByteStream(
- errorGroup.registerStream(process.stdout));
+ errorGroup.registerStream(Chain.track(process.stdout)));
_stderr = new ByteStream(
- errorGroup.registerStream(process.stderr));
+ errorGroup.registerStream(Chain.track(process.stderr)));
var exitCodeCompleter = new Completer();
- _exitCode = errorGroup.registerFuture(exitCodeCompleter.future);
+ _exitCode = errorGroup.registerFuture(
+ Chain.track(exitCodeCompleter.future));
_process.exitCode.then((code) => exitCodeCompleter.complete(code));
}
@@ -620,10 +625,10 @@
log.process(executable, args);
- return fn(executable,
- args,
- workingDirectory: workingDir,
- environment: environment);
+ return Chain.track(fn(executable,
+ args,
+ workingDirectory: workingDir,
+ environment: environment));
}
/// Wraps [input] to provide a timeout. If [input] completes before
@@ -641,7 +646,7 @@
var timer = new Timer(duration, () {
completer.completeError(new TimeoutException(
'Timed out while $description.', duration),
- new Trace.current());
+ new Chain.current());
});
input.then((value) {
if (completer.isCompleted) return;
@@ -663,9 +668,9 @@
/// Returns a future that completes to the value that the future returned from
/// [fn] completes to.
Future withTempDir(Future fn(String path)) {
- return new Future.sync(() {
+ return syncFuture(() {
var tempDir = createSystemTempDir();
- return new Future.sync(() => fn(tempDir))
+ return syncFuture(() => fn(tempDir))
.whenComplete(() => deleteEntry(tempDir));
});
}
@@ -757,14 +762,12 @@
/// considered to be [baseDir], which defaults to the current working directory.
/// Returns a [ByteStream] that will emit the contents of the archive.
ByteStream createTarGz(List contents, {baseDir}) {
- return new ByteStream(futureStream(new Future.sync(() {
+ return new ByteStream(futureStream(syncFuture(() {
var buffer = new StringBuffer();
buffer.write('Creating .tag.gz stream containing:\n');
contents.forEach((file) => buffer.write('$file\n'));
log.fine(buffer.toString());
- var controller = new StreamController<List<int>>(sync: true);
-
if (baseDir == null) baseDir = path.current;
baseDir = path.absolute(baseDir);
contents = contents.map((entry) {
@@ -788,7 +791,7 @@
// Don't use [withTempDir] here because we don't want to delete the temp
// directory until the returned stream has closed.
var tempDir = createSystemTempDir();
- return new Future.sync(() {
+ return syncFuture(() {
// Create the tar file.
var tarFile = path.join(tempDir, "intermediate.tar");
var args = ["a", "-w$baseDir", tarFile];
diff --git a/sdk/lib/_internal/pub/lib/src/log.dart b/sdk/lib/_internal/pub/lib/src/log.dart
index 86c2b7f..bbbcb3c 100644
--- a/sdk/lib/_internal/pub/lib/src/log.dart
+++ b/sdk/lib/_internal/pub/lib/src/log.dart
@@ -6,7 +6,6 @@
library pub.log;
import 'dart:async';
-import 'dart:collection';
import 'dart:io';
import 'io.dart';
@@ -35,10 +34,13 @@
/// progress is done, a single entry will be added to the log for it.
String _progressMessage;
+final _cyan = getSpecial('\u001b[36m');
final _green = getSpecial('\u001b[32m');
+final _magenta = getSpecial('\u001b[35m');
final _red = getSpecial('\u001b[31m');
final _yellow = getSpecial('\u001b[33m');
final _none = getSpecial('\u001b[0m');
+final _bold = getSpecial('\u001b[1m');
/// An enum type for defining the different logging levels. By default, [ERROR]
/// and [WARNING] messages are printed to sterr. [MESSAGE] messages are printed
@@ -218,16 +220,42 @@
return callback().whenComplete(_stopProgress);
}
+/// Wraps [text] in the ANSI escape codes to make it bold when on a platform
+/// that supports that.
+///
+/// Use this to highlight the most important piece of a long chunk of text.
+String bold(text) => "$_bold$text$_none";
+
+/// Wraps [text] in the ANSI escape codes to color it cyan when on a platform
+/// that supports that.
+///
+/// Use this to highlight something interesting but neither good nor bad.
+String cyan(text) => "$_cyan$text$_none";
+
/// Wraps [text] in the ANSI escape codes to color it green when on a platform
/// that supports that.
+///
+/// Use this to highlight something successful or otherwise positive.
String green(text) => "$_green$text$_none";
+/// Wraps [text] in the ANSI escape codes to color it magenta when on a
+/// platform that supports that.
+///
+/// Use this to highlight something risky that the user should be aware of but
+/// may intend to do.
+String magenta(text) => "$_magenta$text$_none";
+
/// Wraps [text] in the ANSI escape codes to color it red when on a platform
/// that supports that.
+///
+/// Use this to highlight unequivocal errors, problems, or failures.
String red(text) => "$_red$text$_none";
/// Wraps [text] in the ANSI escape codes to color it yellow when on a platform
/// that supports that.
+///
+/// Use this to highlight warnings, cautions or other things that are bad but
+/// do not prevent the user's goal from being reached.
String yellow(text) => "$_yellow$text$_none";
/// Stops the running progress indicator, if currently running.
diff --git a/sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart b/sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart
index 882ef36..6229c6e 100644
--- a/sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart
+++ b/sdk/lib/_internal/pub/lib/src/solver/backtracking_solver.dart
@@ -55,13 +55,19 @@
class BacktrackingSolver {
final SourceRegistry sources;
final Package root;
+
+ /// The lockfile that was present before solving.
final LockFile lockFile;
+
final PubspecCache cache;
/// The set of packages that are being explicitly upgraded. The solver will
/// only allow the very latest version for each of these packages.
final _forceLatest = new Set<String>();
+ /// If this is set, the contents of [lockFile] are ignored while solving.
+ final bool _upgradeAll;
+
/// The set of packages whose dependecy is being overridden by the root
/// package, keyed by the name of the package.
///
@@ -93,12 +99,12 @@
var _attemptedSolutions = 1;
BacktrackingSolver(SourceRegistry sources, this.root, this.lockFile,
- List<String> useLatest)
+ List<String> useLatest, {bool upgradeAll: false})
: sources = sources,
- cache = new PubspecCache(sources) {
+ cache = new PubspecCache(sources),
+ _upgradeAll = upgradeAll {
for (var package in useLatest) {
- forceLatestVersion(package);
- lockFile.packages.remove(package);
+ _forceLatest.add(package);
}
for (var override in root.dependencyOverrides) {
@@ -126,12 +132,14 @@
_validateSdkConstraint(root.pubspec);
return _traverseSolution();
}).then((packages) {
- return new SolveResult(packages, overrides, null, attemptedSolutions);
+ return new SolveResult.success(sources, root, lockFile, packages,
+ overrides, _getAvailableVersions(packages), attemptedSolutions);
}).catchError((error) {
if (error is! SolveFailure) throw error;
// Wrap a failure in a result so we can attach some other data.
- return new SolveResult(null, overrides, error, attemptedSolutions);
+ return new SolveResult.failure(sources, root, lockFile, overrides,
+ error, attemptedSolutions);
}).whenComplete(() {
// Gather some solving metrics.
var buffer = new StringBuffer();
@@ -148,8 +156,30 @@
});
}
- void forceLatestVersion(String package) {
- _forceLatest.add(package);
+ /// Generates a map containing all of the known available versions for each
+ /// package in [packages].
+ ///
+ /// The version list may not always be complete. The the package is the root
+ /// root package, or its a package that we didn't unlock while solving
+ /// because we weren't trying to upgrade it, we will just know the current
+ /// version.
+ Map<String, List<Version>> _getAvailableVersions(List<PackageId> packages) {
+ var availableVersions = new Map<String, List<Version>>();
+ for (var package in packages) {
+ var cached = cache.getCachedVersions(package.toRef());
+ var versions;
+ if (cached != null) {
+ versions = cached.map((id) => id.version).toList();
+ } else {
+ // If the version list was never requested, just use the one known
+ // version.
+ versions = [package.version];
+ }
+
+ availableVersions[package.name] = versions;
+ }
+
+ return availableVersions;
}
/// Adds [versions], which is the list of all allowed versions of a given
@@ -179,7 +209,12 @@
/// Gets the version of [package] currently locked in the lock file. Returns
/// `null` if it isn't in the lockfile (or has been unlocked).
- PackageId getLocked(String package) => lockFile.packages[package];
+ PackageId getLocked(String package) {
+ if (_upgradeAll) return null;
+ if (_forceLatest.contains(package)) return null;
+
+ return lockFile.packages[package];
+ }
/// Traverses the root package's dependency graph using the current potential
/// solution. If successful, completes to the solution. If not, backtracks
@@ -251,6 +286,15 @@
// when that happens.
var selected = _selected[i].current;
+ // If the failure is a disjoint version range, then no possible versions
+ // for that package can match and there's no reason to try them. Instead,
+ // just backjump past it.
+ if (failure is DisjointConstraintException &&
+ selected.name == failure.package) {
+ logSolve("skipping past disjoint selected ${selected.name}");
+ continue;
+ }
+
// If we get to the package that failed, backtrack to here.
if (selected.name == failure.package) {
logSolve('backjump to failed package ${selected.name}');
@@ -335,10 +379,11 @@
buffer.writeln("Solving dependencies:");
for (var package in root.dependencies) {
buffer.write("- $package");
+ var locked = getLocked(package.name);
if (_forceLatest.contains(package.name)) {
buffer.write(" (use latest)");
- } else if (lockFile.packages.containsKey(package.name)) {
- var version = lockFile.packages[package.name].version;
+ } else if (locked != null) {
+ var version = locked.version;
buffer.write(" (locked to $version)");
}
buffer.writeln();
@@ -473,12 +518,35 @@
var dependencies = _getDependencies(dep.name);
dependencies.add(new Dependency(depender, dep));
+ // If the package is barback, pub has an implicit version constraint on
+ // it since pub itself uses barback too. Note that we don't check for
+ // the hosted source here because we still want to do this even when
+ // people on the Dart team are on the bleeding edge and have a path
+ // dependency on the tip version of barback in the Dart repo.
+ //
+ // The length check here is to ensure we only add the barback
+ // dependency once.
+ if (dep.name == "barback" && dependencies.length == 1) {
+ var range = new VersionRange(
+ min: barback.supportedVersion, includeMin: true,
+ max: barback.supportedVersion.nextMinor, includeMax: false);
+ _solver.logSolve('add implicit $range pub dependency on barback');
+
+ // Use the same source and description as the explicit dependency.
+ // That way, this doesn't fail with a source/desc conflict if users
+ // (like Dart team members) use things like a path dependency to
+ // find barback.
+ var barbackDep = new PackageDep(dep.name, dep.source, range,
+ dep.description);
+ dependencies.add(new Dependency("pub itself", barbackDep));
+ }
+
var constraint = _getConstraint(dep.name);
// See if it's possible for a package to match that constraint.
if (constraint.isEmpty) {
_solver.logSolve('disjoint constraints on ${dep.name}');
- throw new DisjointConstraintException(depender, dependencies);
+ throw new DisjointConstraintException(dep.name, dependencies);
}
var selected = _validateSelected(dep, constraint);
@@ -525,6 +593,14 @@
}
return allowed;
+ }).catchError((error, stackTrace) {
+ if (error is PackageNotFoundException) {
+ // Show the user why the package was being requested.
+ throw new DependencyNotFoundException(
+ dep.name, error, _getDependencies(dep.name));
+ }
+
+ throw error;
});
}
@@ -603,19 +679,6 @@
.map((dep) => dep.dep.constraint)
.fold(VersionConstraint.any, (a, b) => a.intersect(b));
- // If the package is barback, pub has an implicit version constraint on it
- // since pub itself uses barback too. Note that we don't check for the
- // hosted source here because we still want to do this even when people on
- // the Dart team are on the bleeding edge and have a path dependency on the
- // tip version of barback in the Dart repo.
- if (name == "barback") {
- var range = new VersionRange(
- min: barback.supportedVersion, includeMin: true,
- max: barback.supportedVersion.nextMinor, includeMax: false);
- constraint = constraint.intersect(range);
- _solver.logSolve('add implicit $range constraint to barback');
- }
-
return constraint;
}
diff --git a/sdk/lib/_internal/pub/lib/src/solver/solve_report.dart b/sdk/lib/_internal/pub/lib/src/solver/solve_report.dart
new file mode 100644
index 0000000..6856878
--- /dev/null
+++ b/sdk/lib/_internal/pub/lib/src/solver/solve_report.dart
@@ -0,0 +1,267 @@
+// 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 pub.solver.solve_report;
+
+import '../lock_file.dart';
+import '../log.dart' as log;
+import '../package.dart';
+import '../source_registry.dart';
+import '../utils.dart';
+import 'version_solver.dart';
+
+/// Generates and displays nicely formatted reports for the results of running
+/// a version resolution.
+///
+/// If [showAll] is true, then all of the previous and current dependencies
+/// are shown and their changes relative to the previous lock file are
+/// highlighted. Otherwise, only overrides are shown.
+///
+/// Returns the number of changed dependencies.
+int show(SourceRegistry sources, Package root, LockFile previousLockFile,
+ SolveResult result, {bool showAll: false}) {
+ var report = new _SolveReport(sources, root, previousLockFile, result);
+ return report.show(showAll: showAll);
+}
+
+/// Unlike [SolveResult], which is the static data describing a resolution,
+/// this class contains the mutable state used while generating the report
+/// itself. It's a report builder.
+class _SolveReport {
+ final SourceRegistry _sources;
+ final Package _root;
+ final LockFile _previousLockFile;
+ final SolveResult _result;
+
+ /// The dependencies in [_result], keyed by package name.
+ final _dependencies = new Map<String, PackageId>();
+
+ final _output = new StringBuffer();
+
+ /// To avoid emitting trailing newlines, we track if any are needed and only
+ /// emit then when text on the next line is about to be written.
+ // TODO(rnystrom): Move this into a separate class that wraps any StringSink
+ // with this logic.
+ int _pendingLines = 0;
+
+ _SolveReport(this._sources, this._root, this._previousLockFile,
+ this._result) {
+ // Fill the map so we can use it later.
+ for (var id in _result.packages) {
+ _dependencies[id.name] = id;
+ }
+ }
+
+ /// Displays a report of the results of the version resolution relative to
+ /// the previous lock file.
+ ///
+ /// If [showAll] is true, then all of the previous and current dependencies
+ /// are shown and their changes relative to the previous lock file are
+ /// highlighted. Otherwise, only overrides are shown.
+ ///
+ /// Returns the number of changed dependencies.
+ int show({bool showAll: false}) {
+ if (showAll) _reportChanges();
+ _reportOverrides();
+
+ // Count how many dependencies actually changed.
+ var dependencies = _dependencies.keys.toSet();
+ dependencies.addAll(_previousLockFile.packages.keys);
+ dependencies.remove(_root.name);
+
+ return dependencies.where((name) {
+ var oldId = _previousLockFile.packages[name];
+ var newId = _dependencies[name];
+
+ // Added or removed dependencies count.
+ if (oldId == null) return true;
+ if (newId == null) return true;
+
+ // The dependency existed before, so see if it was modified.
+ return !_descriptionsEqual(oldId, newId) ||
+ oldId.version != newId.version;
+ }).length;
+ }
+
+ /// Displays a report of all of the previous and current dependencies and
+ /// how they have changed.
+ void _reportChanges() {
+ _output.clear();
+
+ // Show the new set of dependencies ordered by name.
+ var names = _result.packages.map((id) => id.name).toList();
+ names.remove(_root.name);
+ names.sort();
+ names.forEach(_reportPackage);
+
+ // Show any removed ones.
+ var removed = _previousLockFile.packages.keys.toSet();
+ removed.removeAll(names);
+ if (removed.isNotEmpty) {
+ _writeln("These packages are no longer being depended on:");
+ removed = removed.toList();
+ removed.sort();
+ removed.forEach(_reportPackage);
+ }
+
+ log.message(_output.toString());
+ }
+
+ /// Displays a warning about the overrides currently in effect.
+ void _reportOverrides() {
+ _output.clear();
+
+ if (_result.overrides.isNotEmpty) {
+ _writeln("Warning: You are using these overridden dependencies:");
+ var overrides = _result.overrides.map((dep) => dep.name).toList();
+ overrides.sort((a, b) => a.compareTo(b));
+
+ overrides.forEach(
+ (name) => _reportPackage(name, highlightOverride: false));
+
+ log.warning(_output.toString());
+ }
+ }
+
+ /// Reports the results of the upgrade on the package named [name].
+ ///
+ /// If [highlightOverride] is true (or absent), writes "(override)" next to
+ /// overridden packages.
+ void _reportPackage(String name, {bool highlightOverride}) {
+ if (highlightOverride == null) highlightOverride = true;
+
+ var newId = _dependencies[name];
+ var oldId = _previousLockFile.packages[name];
+ var id = newId != null ? newId : oldId;
+
+ var isOverridden = _result.overrides.map(
+ (dep) => dep.name).contains(id.name);
+
+ var changed = false;
+
+ // Show a one-character "icon" describing the change. They are:
+ //
+ // ! The package is being overridden.
+ // - The package was removed.
+ // + The package was added.
+ // > The package was upgraded from a lower version.
+ // < The package was downgraded from a higher version.
+ // * Any other change between the old and new package.
+ if (isOverridden) {
+ _write(log.magenta("! "));
+ } else if (newId == null) {
+ _write(log.red("- "));
+ } else if (oldId == null) {
+ _write(log.green("+ "));
+ } else if (!_descriptionsEqual(oldId, newId)) {
+ _write(log.cyan("* "));
+ changed = true;
+ } else if (oldId.version < newId.version) {
+ _write(log.green("> "));
+ changed = true;
+ } else if (oldId.version > newId.version) {
+ _write(log.cyan("< "));
+ changed = true;
+ } else {
+ // Unchanged.
+ _write(" ");
+ }
+
+ _write(log.bold(id.name));
+ _write(" ");
+ _writeId(id);
+
+ // If the package was upgraded, show what it was upgraded from.
+ if (changed) {
+ _write(" (was ");
+ _writeId(oldId);
+ _write(")");
+ }
+
+ // Highlight overridden packages.
+ if (isOverridden && highlightOverride) {
+ _write(" ${log.magenta('(overridden)')}");
+ }
+
+ // See if there are any newer versions of the package that we were
+ // unable to upgrade to.
+ if (newId != null) {
+ var versions = _result.availableVersions[newId.name];
+ var newerStable = 0;
+ var newerUnstable = 0;
+
+ for (var version in versions) {
+ if (version > newId.version) {
+ if (version.isPreRelease) {
+ newerUnstable++;
+ } else {
+ newerStable++;
+ }
+ }
+ }
+
+ // If there are newer stable versions, only show those.
+ var message;
+ if (newerStable > 0) {
+ message = "($newerStable newer "
+ "${pluralize('version', newerStable)} available)";
+ } else if (newerUnstable > 0) {
+ message = "($newerUnstable newer unstable "
+ "${pluralize('version', newerUnstable)} available)";
+ }
+
+ if (message != null) _write(" ${log.cyan(message)}");
+ }
+
+ _writeln();
+ }
+
+ /// Returns `true` if [a] and [b] are from the same source and have the same
+ /// description.
+ bool _descriptionsEqual(PackageId a, PackageId b) {
+ if (a.source != b.source) return false;
+
+ if (_sources.contains(a.source)) {
+ var source = _sources[a.source];
+ return source.descriptionsEqual(a.description, b.description);
+ } else {
+ // Unknown source, so just do a literal comparison.
+ return a.description == b.description;
+ }
+ }
+
+ /// Writes a terse description of [id] (not including its name) to the output.
+ void _writeId(PackageId id) {
+ _write(id.version);
+
+ var source = null;
+ if (_sources.contains(id.source)) {
+ source = _sources[id.source];
+ }
+
+ if (source != null && source != _sources.defaultSource) {
+ var description = source.formatDescription(_root.dir, id.description);
+ _write(" from ${id.source} $description");
+ }
+ }
+
+ /// Writes [obj] to the output.
+ void _write(Object obj) {
+ while (_pendingLines > 0) {
+ _output.writeln();
+ _pendingLines--;
+ }
+ _output.write(obj);
+ }
+
+ /// Writes [obj] (if not null) followed by a newline to the output.
+ ///
+ /// Doesn't actually immediately write a newline. Instead, it waits until
+ /// output is written on the next line. That way, trailing newlines aren't
+ /// displayed.
+ void _writeln([Object obj]) {
+ if (obj != null) _write(obj);
+ _pendingLines++;
+ }
+}
\ No newline at end of file
diff --git a/sdk/lib/_internal/pub/lib/src/solver/version_queue.dart b/sdk/lib/_internal/pub/lib/src/solver/version_queue.dart
index 529cf74..021b60e 100644
--- a/sdk/lib/_internal/pub/lib/src/solver/version_queue.dart
+++ b/sdk/lib/_internal/pub/lib/src/solver/version_queue.dart
@@ -8,7 +8,6 @@
import 'dart:collection' show Queue;
import '../package.dart';
-import 'backtracking_solver.dart';
/// A function that asynchronously returns a sequence of package IDs.
typedef Future<Iterable<PackageId>> PackageIdGenerator();
diff --git a/sdk/lib/_internal/pub/lib/src/solver/version_solver.dart b/sdk/lib/_internal/pub/lib/src/solver/version_solver.dart
index 54c5ab4..60e71a6f 100644
--- a/sdk/lib/_internal/pub/lib/src/solver/version_solver.dart
+++ b/sdk/lib/_internal/pub/lib/src/solver/version_solver.dart
@@ -15,6 +15,7 @@
import '../version.dart';
import '../utils.dart';
import 'backtracking_solver.dart';
+import 'solve_report.dart' as solve_report;
/// Attempts to select the best concrete versions for all of the transitive
/// dependencies of [root] taking into account all of the [VersionConstraint]s
@@ -24,13 +25,16 @@
/// If [useLatest] is given, then only the latest versions of the referenced
/// packages will be used. This is for forcing an upgrade to one or more
/// packages.
+///
+/// If [upgradeAll] is true, the contents of [lockFile] are ignored.
Future<SolveResult> resolveVersions(SourceRegistry sources, Package root,
- {LockFile lockFile, List<String> useLatest}) {
+ {LockFile lockFile, List<String> useLatest, bool upgradeAll: false}) {
if (lockFile == null) lockFile = new LockFile.empty();
if (useLatest == null) useLatest = [];
return log.progress('Resolving dependencies', () {
- return new BacktrackingSolver(sources, root, lockFile, useLatest).solve();
+ return new BacktrackingSolver(sources, root, lockFile, useLatest,
+ upgradeAll: upgradeAll).solve();
});
}
@@ -46,6 +50,13 @@
/// The dependency overrides that were used in the solution.
final List<PackageDep> overrides;
+ /// The available versions of all selected packages from their source.
+ ///
+ /// Will be empty if the solve failed. An entry here may not include the full
+ /// list of versions available if the given package was locked and did not
+ /// need to be unlocked during the solve.
+ final Map<String, List<Version>> availableVersions;
+
/// The error that prevented the solver from finding a solution or `null` if
/// it was successful.
final SolveFailure error;
@@ -56,8 +67,30 @@
/// solution.
final int attemptedSolutions;
- SolveResult(this.packages, this.overrides, this.error,
- this.attemptedSolutions);
+ final SourceRegistry _sources;
+ final Package _root;
+ final LockFile _previousLockFile;
+
+ SolveResult.success(this._sources, this._root, this._previousLockFile,
+ this.packages, this.overrides, this.availableVersions,
+ this.attemptedSolutions)
+ : error = null;
+
+ SolveResult.failure(this._sources, this._root, this._previousLockFile,
+ this.overrides, this.error, this.attemptedSolutions)
+ : this.packages = null,
+ this.availableVersions = {};
+
+ /// Displays a report of what changes were made to the lockfile.
+ ///
+ /// If [showAll] is true, displays all new and previous dependencies.
+ /// Otherwise, just shows a warning for any overrides in effect.
+ ///
+ /// Returns the number of changed (added, removed, or modified) dependencies.
+ int showReport({bool showAll: false}) {
+ return solve_report.show(_sources, _root, _previousLockFile, this,
+ showAll: showAll);
+ }
String toString() {
if (!succeeded) {
@@ -163,6 +196,10 @@
return ids;
});
}
+
+ /// Returns the previously cached list of versions for the package identified
+ /// by [package] or returns `null` if not in the cache.
+ List<PackageId> getCachedVersions(PackageRef package) => _versions[package];
}
/// A reference from a depending package to a package that it depends on.
@@ -191,6 +228,13 @@
final innerError = null;
final innerTrace = null;
+ String get message => toString();
+
+ /// A message describing the specific kind of solve failure.
+ String get _message {
+ throw new UnimplementedError("Must override _message or toString().");
+ }
+
SolveFailure(this.package, Iterable<Dependency> dependencies)
: dependencies = dependencies != null ? dependencies : <Dependency>[];
@@ -198,7 +242,7 @@
if (dependencies.isEmpty) return _message;
var buffer = new StringBuffer();
- buffer.writeln("$_message:");
+ buffer.write("$_message:");
var map = {};
for (var dep in dependencies) {
@@ -207,20 +251,15 @@
var names = ordered(map.keys);
- buffer.writeAll(names.map(
- (name) => "- '$name' ${_describeDependency(map[name])}"), '\n');
+ for (var name in names) {
+ buffer.writeln();
+ buffer.write("- $name ${_describeDependency(map[name])}");
+ }
return buffer.toString();
}
- String get message => toString();
-
- /// A message describing the specific kind of solve failure.
- String get _message {
- throw new UnimplementedError("Must override _message or toString().");
- }
-
- /// Describes a dependencie's reference in the output message. Override this
+ /// Describes a dependency's reference in the output message. Override this
/// to highlight which aspect of [dep] led to the failure.
String _describeDependency(PackageDep dep) =>
"depends on version ${dep.constraint}";
@@ -229,12 +268,11 @@
/// Exception thrown when the current SDK's version does not match a package's
/// constraint on it.
class BadSdkVersionException extends SolveFailure {
+ final String _message;
+
BadSdkVersionException(String package, String message)
: super(package, null),
_message = message;
-
- /// A message describing the specific kind of solve failure.
- final String _message;
}
/// Exception thrown when the [VersionConstraint] used to match a package is
@@ -247,7 +285,7 @@
Iterable<Dependency> dependencies)
: super(package, dependencies);
- String get _message => "Package '$package' has no versions that match "
+ String get _message => "Package $package has no versions that match "
"$constraint derived from";
}
@@ -262,7 +300,7 @@
: super(package, null);
String get _message =>
- "The latest version of '$package', $best, does not match $constraint.";
+ "The latest version of $package, $best, does not match $constraint.";
}
/// Exception thrown when the [VersionConstraint] used to match a package is
@@ -272,17 +310,17 @@
DisjointConstraintException(String package, Iterable<Dependency> dependencies)
: super(package, dependencies);
- String get _message => "Incompatible version constraints on '$package'";
+ String get _message => "Incompatible version constraints on $package";
}
/// Exception thrown when two packages with the same name but different sources
/// are depended upon.
class SourceMismatchException extends SolveFailure {
+ String get _message => "Incompatible dependencies on $package";
+
SourceMismatchException(String package, Iterable<Dependency> dependencies)
: super(package, dependencies);
- String get _message => "Incompatible dependencies on '$package'";
-
String _describeDependency(PackageDep dep) =>
"depends on it from source ${dep.source}";
}
@@ -294,22 +332,40 @@
String toString() {
var dep = dependencies.single;
- return "Package '${dep.depender}' depends on '${dep.dep.name}' from "
- "unknown source '${dep.dep.source}'.";
+ return 'Package ${dep.depender} depends on ${dep.dep.name} from unknown '
+ 'source "${dep.dep.source}".';
}
}
/// Exception thrown when two packages with the same name and source but
/// different descriptions are depended upon.
class DescriptionMismatchException extends SolveFailure {
+ String get _message => "Incompatible dependencies on $package";
+
DescriptionMismatchException(String package,
Iterable<Dependency> dependencies)
: super(package, dependencies);
- String get _message => "Incompatible dependencies on '$package'";
-
String _describeDependency(PackageDep dep) {
// TODO(nweiz): Dump descriptions to YAML when that's supported.
return "depends on it with description ${JSON.encode(dep.description)}";
}
}
+
+/// Exception thrown when a dependency could not be found in its source.
+///
+/// Unlike [PackageNotFoundException], this includes information about the
+/// dependent packages requesting the missing one.
+class DependencyNotFoundException extends SolveFailure {
+ final PackageNotFoundException _innerException;
+ String get _message => "${_innerException.message}\nDepended on by";
+
+ DependencyNotFoundException(String package, this._innerException,
+ Iterable<Dependency> dependencies)
+ : super(package, dependencies);
+
+ /// The failure isn't because of the version of description of the package,
+ /// it's the package itself that can't be found, so just show the name and no
+ /// descriptive details.
+ String _describeDependency(PackageDep dep) => "";
+}
diff --git a/sdk/lib/_internal/pub/lib/src/source.dart b/sdk/lib/_internal/pub/lib/src/source.dart
index a27a909..299f6cf 100644
--- a/sdk/lib/_internal/pub/lib/src/source.dart
+++ b/sdk/lib/_internal/pub/lib/src/source.dart
@@ -7,6 +7,7 @@
import 'dart:async';
import 'package:path/path.dart' as path;
+import 'package:stack_trace/stack_trace.dart';
import 'io.dart';
import 'package.dart';
@@ -203,7 +204,8 @@
/// This doesn't need to be implemented if [shouldCache] is false.
Future<String> systemCacheDirectory(PackageId id) {
return new Future.error(
- "systemCacheDirectory() must be implemented if shouldCache is true.");
+ "systemCacheDirectory() must be implemented if shouldCache is true.",
+ new Chain.current());
}
/// When a [Pubspec] or [LockFile] is parsed, it reads in the description for
diff --git a/sdk/lib/_internal/pub/lib/src/source/git.dart b/sdk/lib/_internal/pub/lib/src/source/git.dart
index 5a7f5e5..c50e719 100644
--- a/sdk/lib/_internal/pub/lib/src/source/git.dart
+++ b/sdk/lib/_internal/pub/lib/src/source/git.dart
@@ -40,7 +40,7 @@
return git.isInstalled.then((installed) {
if (!installed) {
throw new Exception(
- "Cannot get '${id.name}' from Git (${_getUrl(id)}).\n"
+ "Cannot get ${id.name} from Git (${_getUrl(id)}).\n"
"Please ensure Git is correctly installed.");
}
@@ -121,7 +121,7 @@
/// future that completes once this is finished and throws an exception if it
/// fails.
Future _ensureRepoCache(PackageId id) {
- return new Future.sync(() {
+ return syncFuture(() {
var path = _repoCachePath(id);
if (!entryExists(path)) return _clone(_getUrl(id), path, mirror: true);
return git.run(["fetch"], workingDir: path).then((result) => null);
@@ -141,7 +141,7 @@
/// the working tree, but instead makes the repository a local mirror of the
/// remote repository. See the manpage for `git clone` for more information.
Future _clone(String from, String to, {bool mirror: false}) {
- return new Future.sync(() {
+ return syncFuture(() {
// Git on Windows does not seem to automatically create the destination
// directory.
ensureDir(to);
diff --git a/sdk/lib/_internal/pub/lib/src/source/hosted.dart b/sdk/lib/_internal/pub/lib/src/source/hosted.dart
index 1429e28..781ab0c 100644
--- a/sdk/lib/_internal/pub/lib/src/source/hosted.dart
+++ b/sdk/lib/_internal/pub/lib/src/source/hosted.dart
@@ -78,7 +78,7 @@
/// Downloads a package from the site and unpacks it.
Future<bool> get(PackageId id, String destPath) {
- return new Future.sync(() {
+ return syncFuture(() {
var url = _makeVersionUrl(id, (server, package, version) =>
"$server/packages/$package/versions/$version.tar.gz");
log.io("Get package from $url.");
@@ -156,16 +156,17 @@
String url) {
if (error is PubHttpException &&
error.response.statusCode == 404) {
- fail('Could not find package "$package" at $url.', error, stackTrace);
+ throw new PackageNotFoundException(
+ "Could not find package $package at $url.", error, stackTrace);
}
if (error is TimeoutException) {
- fail('Timed out trying to find package "$package" at $url.',
+ fail("Timed out trying to find package $package at $url.",
error, stackTrace);
}
if (error is io.SocketException) {
- fail('Got socket error trying to find package "$package" at $url.',
+ fail("Got socket error trying to find package $package at $url.",
error, stackTrace);
}
@@ -191,7 +192,7 @@
.toList();
}).then((versions) {
// If there are no versions in the cache, report a clearer error.
- if (versions.isEmpty) fail('Could not find package "$name" in cache.');
+ if (versions.isEmpty) fail("Could not find package $name in cache.");
return versions;
});
diff --git a/sdk/lib/_internal/pub/lib/src/source/path.dart b/sdk/lib/_internal/pub/lib/src/source/path.dart
index 76892e1..52f6212 100644
--- a/sdk/lib/_internal/pub/lib/src/source/path.dart
+++ b/sdk/lib/_internal/pub/lib/src/source/path.dart
@@ -20,7 +20,7 @@
final shouldCache = false;
Future<Pubspec> describeUncached(PackageId id) {
- return new Future.sync(() {
+ return syncFuture(() {
var dir = _validatePath(id.name, id.description);
return new Pubspec.load(dir, systemCache.sources,
expectedName: id.name);
@@ -35,7 +35,7 @@
}
Future<bool> get(PackageId id, String destination) {
- return new Future.sync(() {
+ return syncFuture(() {
try {
var dir = _validatePath(id.name, id.description);
createPackageSymlink(id.name, dir, destination,
@@ -135,10 +135,11 @@
if (dirExists(dir)) return dir;
if (fileExists(dir)) {
- fail("Path dependency for package '$name' must refer to a "
- "directory, not a file. Was '$dir'.");
+ fail('Path dependency for package $name must refer to a directory, '
+ 'not a file. Was "$dir".');
}
- fail("Could not find package '$name' at '$dir'.");
+ throw new PackageNotFoundException(
+ 'Could not find package $name at "$dir".');
}
}
diff --git a/sdk/lib/_internal/pub/lib/src/source_registry.dart b/sdk/lib/_internal/pub/lib/src/source_registry.dart
index 6dbe58e..cd3dc3e 100644
--- a/sdk/lib/_internal/pub/lib/src/source_registry.dart
+++ b/sdk/lib/_internal/pub/lib/src/source_registry.dart
@@ -43,6 +43,8 @@
/// Returns the source named [name]. Throws an error if no such source has
/// been registered. If [name] is null, returns the default source.
+ // TODO(rnystrom): Return a NullSource that does nothing safely so that
+ // calling code doesn't have to worry about it.
Source operator[](String name) {
if (name == null) {
if (defaultSource != null) return defaultSource;
diff --git a/sdk/lib/_internal/pub/lib/src/utils.dart b/sdk/lib/_internal/pub/lib/src/utils.dart
index 222941a..dc25e53 100644
--- a/sdk/lib/_internal/pub/lib/src/utils.dart
+++ b/sdk/lib/_internal/pub/lib/src/utils.dart
@@ -77,9 +77,6 @@
Future<List> get future => _completer.future;
}
-/// Like [Future.sync], but wraps the Future in [Chain.track] as well.
-Future syncFuture(callback()) => Chain.track(new Future.sync(callback));
-
/// Returns a buffered stream that will emit the same values as the stream
/// returned by [future] once [future] completes.
///
@@ -131,6 +128,37 @@
/// under the covers.
Future newFuture(callback()) => new Future.value().then((_) => callback());
+/// Like [new Future.sync], but automatically wraps the future in a
+/// [Chain.track] call.
+Future syncFuture(callback()) => Chain.track(new Future.sync(callback));
+
+/// Runs [callback] in an error zone and pipes any unhandled error to the
+/// returned [Future].
+///
+/// If the returned [Future] produces an error, its stack trace will always be a
+/// [Chain]. By default, this chain will contain only the local stack trace, but
+/// if [captureStackChains] is passed, it will contain the full stack chain for
+/// the error.
+Future captureErrors(Future callback(), {bool captureStackChains: false}) {
+ var completer = new Completer();
+ var wrappedCallback = () {
+ new Future.sync(callback).then(completer.complete)
+ .catchError((e, stackTrace) {
+ completer.completeError(e, new Chain.forTrace(stackTrace));
+ });
+ };
+
+ if (captureStackChains) {
+ Chain.capture(wrappedCallback, onError: completer.completeError);
+ } else {
+ runZoned(wrappedCallback, onError: (e, stackTrace) {
+ completer.completeError(e, new Chain([new Trace.from(stackTrace)]));
+ });
+ }
+
+ return completer.future;
+}
+
/// Returns a [StreamTransformer] that will call [onDone] when the stream
/// completes.
///
@@ -411,7 +439,7 @@
}, onError: (e, [stackTrace]) {
completer.completeError(e, stackTrace);
}, onDone: () {
- completer.completeError(new StateError("No elements"));
+ completer.completeError(new StateError("No elements"), new Chain.current());
}, cancelOnError: true);
return completer.future;
}
@@ -804,6 +832,16 @@
String toString() => message;
}
+/// An class for exceptions where a package could not be found in a [Source].
+///
+/// The source is responsible for wrapping its internal exceptions in this so
+/// that other code in pub can use this to show a more detailed explanation of
+/// why the package was being requested.
+class PackageNotFoundException extends ApplicationException {
+ PackageNotFoundException(String message, [innerError, StackTrace innerTrace])
+ : super(message, innerError, innerTrace);
+}
+
/// Throw a [ApplicationException] with [message].
void fail(String message, [innerError, StackTrace innerTrace]) {
throw new ApplicationException(message, innerError, innerTrace);
diff --git a/sdk/lib/_internal/pub/lib/src/validator/compiled_dartdoc.dart b/sdk/lib/_internal/pub/lib/src/validator/compiled_dartdoc.dart
index d6abf6d..400e6b2 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/compiled_dartdoc.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/compiled_dartdoc.dart
@@ -10,6 +10,7 @@
import '../entrypoint.dart';
import '../io.dart';
+import '../utils.dart';
import '../validator.dart';
/// Validates that a package doesn't contain compiled Dartdoc
@@ -19,7 +20,7 @@
: super(entrypoint);
Future validate() {
- return new Future.sync(() {
+ return syncFuture(() {
for (var entry in listDir(entrypoint.root.dir, recursive: true)) {
if (path.basename(entry) != "nav.json") continue;
var dir = path.dirname(entry);
diff --git a/sdk/lib/_internal/pub/lib/src/validator/directory.dart b/sdk/lib/_internal/pub/lib/src/validator/directory.dart
index 6039fc5..f733e4e 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/directory.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/directory.dart
@@ -10,6 +10,7 @@
import '../entrypoint.dart';
import '../io.dart';
+import '../utils.dart';
import '../validator.dart';
/// A validator that validates a package's top-level directories.
@@ -22,7 +23,7 @@
];
Future validate() {
- return new Future.sync(() {
+ return syncFuture(() {
for (var dir in listDir(entrypoint.root.dir)) {
if (!dirExists(dir)) continue;
diff --git a/sdk/lib/_internal/pub/lib/src/validator/lib.dart b/sdk/lib/_internal/pub/lib/src/validator/lib.dart
index 98bed28..22ed406 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/lib.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/lib.dart
@@ -10,6 +10,7 @@
import '../entrypoint.dart';
import '../io.dart';
+import '../utils.dart';
import '../validator.dart';
// TODO(nweiz): When issue 7196 is fixed, complain about non-Dart files in lib.
@@ -20,7 +21,7 @@
: super(entrypoint);
Future validate() {
- return new Future.sync(() {
+ return syncFuture(() {
var libDir = path.join(entrypoint.root.dir, "lib");
if (!dirExists(libDir)) {
diff --git a/sdk/lib/_internal/pub/lib/src/validator/license.dart b/sdk/lib/_internal/pub/lib/src/validator/license.dart
index 222d693..ffad6a7 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/license.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/license.dart
@@ -10,6 +10,7 @@
import '../entrypoint.dart';
import '../io.dart';
+import '../utils.dart';
import '../validator.dart';
/// A validator that checks that a LICENSE-like file exists.
@@ -18,7 +19,7 @@
: super(entrypoint);
Future validate() {
- return new Future.sync(() {
+ return syncFuture(() {
var licenseLike = new RegExp(
r"^([a-zA-Z0-9]+[-_])?(LICENSE|COPYING)(\..*)?$");
if (listDir(entrypoint.root.dir)
diff --git a/sdk/lib/_internal/pub/lib/src/validator/name.dart b/sdk/lib/_internal/pub/lib/src/validator/name.dart
index 1285fb1..1b77ead 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/name.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/name.dart
@@ -10,6 +10,7 @@
import '../entrypoint.dart';
import '../io.dart';
+import '../utils.dart';
import '../validator.dart';
/// Dart reserved words, from the Dart spec.
@@ -26,7 +27,7 @@
: super(entrypoint);
Future validate() {
- return new Future.sync(() {
+ return syncFuture(() {
_checkName(entrypoint.root.name, 'Package name "${entrypoint.root.name}"',
isPackage: true);
diff --git a/sdk/lib/_internal/pub/lib/src/validator/utf8_readme.dart b/sdk/lib/_internal/pub/lib/src/validator/utf8_readme.dart
index 9f30d65..da0c223 100644
--- a/sdk/lib/_internal/pub/lib/src/validator/utf8_readme.dart
+++ b/sdk/lib/_internal/pub/lib/src/validator/utf8_readme.dart
@@ -9,6 +9,7 @@
import '../entrypoint.dart';
import '../io.dart';
+import '../utils.dart';
import '../validator.dart';
/// Validates that a package's README is valid utf-8.
@@ -17,7 +18,7 @@
: super(entrypoint);
Future validate() {
- return new Future.sync(() {
+ return syncFuture(() {
var readme = entrypoint.root.readmePath;
if (readme == null) return;
var bytes = readBinaryFile(readme);
diff --git a/sdk/lib/_internal/pub/lib/src/version.dart b/sdk/lib/_internal/pub/lib/src/version.dart
index e8738ff..8c34d57 100644
--- a/sdk/lib/_internal/pub/lib/src/version.dart
+++ b/sdk/lib/_internal/pub/lib/src/version.dart
@@ -9,7 +9,7 @@
import 'dart:math';
-import 'package:collection_helpers/equality.dart';
+import 'package:collection/equality.dart';
/// Regex that matches a version number at the beginning of a string.
final _START_VERSION = new RegExp(
diff --git a/sdk/lib/_internal/pub/pub.status b/sdk/lib/_internal/pub/pub.status
index 3e49ab9..2165264 100644
--- a/sdk/lib/_internal/pub/pub.status
+++ b/sdk/lib/_internal/pub/pub.status
@@ -9,6 +9,7 @@
[ $runtime == vm && $system == windows ]
test/serve/watch_removed_file_test: Pass, Fail # Issue 13026
test/serve/missing_file_test: Pass, Fail # Issue 15431
+test/serve/warns_on_assets_paths_test: Pass, Fail # Issue 15741
# Pub only runs on the VM, so just rule out all compilers.
[ $compiler == dart2js || $compiler == dart2dart ]
diff --git a/sdk/lib/_internal/pub/resource/certs/cert9.db b/sdk/lib/_internal/pub/resource/certs/cert9.db
deleted file mode 100644
index 955f26d..0000000
--- a/sdk/lib/_internal/pub/resource/certs/cert9.db
+++ /dev/null
Binary files differ
diff --git a/sdk/lib/_internal/pub/resource/certs/key4.db b/sdk/lib/_internal/pub/resource/certs/key4.db
deleted file mode 100644
index 1b6b97a..0000000
--- a/sdk/lib/_internal/pub/resource/certs/key4.db
+++ /dev/null
Binary files differ
diff --git a/sdk/lib/_internal/pub/resource/certs/pkcs11.txt b/sdk/lib/_internal/pub/resource/certs/pkcs11.txt
deleted file mode 100644
index 81f899b..0000000
--- a/sdk/lib/_internal/pub/resource/certs/pkcs11.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-library=
-name=NSS Internal PKCS #11 Module
-parameters=configdir='utils/pub/resource/certs' certPrefix='' keyPrefix='' secmod='secmod.db' flags= updatedir='' updateCertPrefix='' updateKeyPrefix='' updateid='' updateTokenDescription=''
-NSS=Flags=internal,critical trustOrder=75 cipherOrder=100 slotParams=(1={slotFlags=[RSA,DSA,DH,RC2,RC4,DES,RANDOM,SHA1,MD5,MD2,SSL,TLS,AES,Camellia,SEED,SHA256,SHA512] askpw=any timeout=30})
-
diff --git a/sdk/lib/_internal/pub/test/build/warns_on_assets_paths_test.dart b/sdk/lib/_internal/pub/test/build/warns_on_assets_paths_test.dart
new file mode 100644
index 0000000..90c69f0
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/build/warns_on_assets_paths_test.dart
@@ -0,0 +1,101 @@
+// 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 pub_tests;
+
+import 'package:path/path.dart' as path;
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+
+getWarningRegExp(String assetsPath) {
+ // Escape backslashes since they are metacharacters in a regex.
+ assetsPath = assetsPath.replaceAll("\\", "\\\\");
+ return new RegExp(
+ '^Warning: Pub reserves paths containing "assets" for using assets from '
+ 'packages\\. Please rename the path "$assetsPath"\\.\$');
+}
+
+main() {
+ initConfig();
+
+ integration('warns user about assets dir in the root of "web"', () {
+ d.dir(appPath, [
+ d.appPubspec(),
+ d.dir('web', [
+ d.file('index.html'),
+ d.dir('assets')
+ ])
+ ]).create();
+
+ var assetsPath = path.join('web', 'assets');
+ schedulePub(args: ['build'],
+ error: getWarningRegExp(assetsPath),
+ exitCode: 0);
+ });
+
+ integration('warns user about assets dir nested anywhere in "web"', () {
+ d.dir(appPath, [
+ d.appPubspec(),
+ d.dir('web', [
+ d.file('index.html'),
+ d.dir('foo', [
+ d.dir('assets')
+ ])
+ ])
+ ]).create();
+
+ var assetsPath = path.join('web', 'foo', 'assets');
+ schedulePub(args: ['build'],
+ error: getWarningRegExp(assetsPath),
+ exitCode: 0);
+ });
+
+ integration('warns user about assets file in the root of "web"', () {
+ d.dir(appPath, [
+ d.appPubspec(),
+ d.dir('web', [
+ d.file('index.html'),
+ d.file('assets')
+ ])
+ ]).create();
+
+ var assetsPath = path.join('web', 'assets');
+ schedulePub(args: ['build'],
+ error: getWarningRegExp(assetsPath),
+ exitCode: 0);
+ });
+
+ integration('warns user about assets file nested anywhere in "web"', () {
+ d.dir(appPath, [
+ d.appPubspec(),
+ d.dir('web', [
+ d.file('index.html'),
+ d.dir('foo', [
+ d.file('assets')
+ ])
+ ])
+ ]).create();
+
+ var assetsPath = path.join('web', 'foo', 'assets');
+ schedulePub(args: ['build'],
+ error: getWarningRegExp(assetsPath),
+ exitCode: 0);
+ });
+
+ integration('does not warn if no assets dir or file anywhere in "web"', () {
+ d.dir(appPath, [
+ d.appPubspec(),
+ d.dir('web', [
+ d.file('index.html'),
+ d.dir('foo')
+ ])
+ ]).create();
+
+ schedulePub(args: ['build'],
+ error: new RegExp(
+ r'^(?!Warning: Pub reserves paths containing "assets").*$'),
+ exitCode: 0);
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/build/with_no_web_directory_test.dart b/sdk/lib/_internal/pub/test/build/with_no_web_directory_test.dart
index 95a8e3c..d25df72 100644
--- a/sdk/lib/_internal/pub/test/build/with_no_web_directory_test.dart
+++ b/sdk/lib/_internal/pub/test/build/with_no_web_directory_test.dart
@@ -12,7 +12,7 @@
d.appDir().create();
schedulePub(args: ["build"],
- error: new RegExp(r"^There is no '[^']+[/\\]web' directory.$",
+ error: new RegExp(r'^There is no "[^"]+[/\\]web" directory.$',
multiLine: true),
exitCode: 1);
});
diff --git a/sdk/lib/_internal/pub/test/dependency_override_test.dart b/sdk/lib/_internal/pub/test/dependency_override_test.dart
index 7e0f229..fcbb3bc 100644
--- a/sdk/lib/_internal/pub/test/dependency_override_test.dart
+++ b/sdk/lib/_internal/pub/test/dependency_override_test.dart
@@ -112,9 +112,9 @@
schedulePub(args: [command.name], output: command.success, error:
"""
Warning: You are using these overridden dependencies:
- - bar
- - baz (from path $bazPath)
- - foo
+ ! bar 1.0.0
+ ! baz 0.0.1 from path $bazPath
+ ! foo 1.0.0
""");
});
});
diff --git a/sdk/lib/_internal/pub/test/get/hosted/get_test.dart b/sdk/lib/_internal/pub/test/get/hosted/get_test.dart
index 40eaca5..8dd1d0e 100644
--- a/sdk/lib/_internal/pub/test/get/hosted/get_test.dart
+++ b/sdk/lib/_internal/pub/test/get/hosted/get_test.dart
@@ -26,6 +26,6 @@
d.appDir({"bad name!": "1.2.3"}).create();
pubGet(error: new RegExp(
- r'Could not find package "bad name!" at http://127\.0\.0\.1:\d+\.$'));
+ r"Could not find package bad name! at http://127\.0\.0\.1:\d+\."));
});
}
diff --git a/sdk/lib/_internal/pub/test/get/path/nonexistent_dir_test.dart b/sdk/lib/_internal/pub/test/get/path/nonexistent_dir_test.dart
index 2db4d38..35552bb 100644
--- a/sdk/lib/_internal/pub/test/get/path/nonexistent_dir_test.dart
+++ b/sdk/lib/_internal/pub/test/get/path/nonexistent_dir_test.dart
@@ -18,6 +18,8 @@
})
]).create();
- pubGet(error: "Could not find package 'foo' at '$badPath'.");
+ pubGet(error: """Could not find package foo at "$badPath".
+Depended on by:
+- myapp""");
});
}
\ No newline at end of file
diff --git a/sdk/lib/_internal/pub/test/get/path/path_is_file_test.dart b/sdk/lib/_internal/pub/test/get/path/path_is_file_test.dart
index 288f68f..81524c8 100644
--- a/sdk/lib/_internal/pub/test/get/path/path_is_file_test.dart
+++ b/sdk/lib/_internal/pub/test/get/path/path_is_file_test.dart
@@ -24,7 +24,7 @@
})
]).create();
- pubGet(error: "Path dependency for package 'foo' must refer to a "
- "directory, not a file. Was '$dummyPath'.");
+ pubGet(error: 'Path dependency for package foo must refer to a '
+ 'directory, not a file. Was "$dummyPath".');
});
}
\ No newline at end of file
diff --git a/sdk/lib/_internal/pub/test/hosted/fail_gracefully_on_missing_package_test.dart b/sdk/lib/_internal/pub/test/hosted/fail_gracefully_on_missing_package_test.dart
index 18fed7f..944e6ed 100644
--- a/sdk/lib/_internal/pub/test/hosted/fail_gracefully_on_missing_package_test.dart
+++ b/sdk/lib/_internal/pub/test/hosted/fail_gracefully_on_missing_package_test.dart
@@ -16,8 +16,10 @@
d.appDir({"foo": "1.2.3"}).create();
- pubCommand(command, error: new RegExp(
- r'Could not find package "foo" at http://127\.0\.0\.1:\d+\.$'));
+ pubCommand(command, error: new RegExp(r"""
+Could not find package foo at http://127\.0\.0\.1:\d+\.
+Depended on by:
+- myapp""", multiLine: true));
});
});
}
diff --git a/sdk/lib/_internal/pub/test/hosted/offline_test.dart b/sdk/lib/_internal/pub/test/hosted/offline_test.dart
index 16be30c..b799198 100644
--- a/sdk/lib/_internal/pub/test/hosted/offline_test.dart
+++ b/sdk/lib/_internal/pub/test/hosted/offline_test.dart
@@ -46,7 +46,7 @@
d.appDir({"foo": "any"}).create();
pubCommand(command, args: ['--offline'],
- error: 'Could not find package "foo" in cache.');
+ error: "Could not find package foo in cache.");
});
integration('fails gracefully no cached versions match', () {
@@ -60,8 +60,8 @@
d.appDir({"foo": ">2.0.0"}).create();
pubCommand(command, args: ['--offline'], error:
- "Package 'foo' has no versions that match >2.0.0 derived from:\n"
- "- 'myapp' depends on version >2.0.0");
+ "Package foo has no versions that match >2.0.0 derived from:\n"
+ "- myapp depends on version >2.0.0");
});
});
}
diff --git a/sdk/lib/_internal/pub/test/implicit_barback_dependency_test.dart b/sdk/lib/_internal/pub/test/implicit_barback_dependency_test.dart
index 02f2363..894cf51 100644
--- a/sdk/lib/_internal/pub/test/implicit_barback_dependency_test.dart
+++ b/sdk/lib/_internal/pub/test/implicit_barback_dependency_test.dart
@@ -10,16 +10,19 @@
main() {
initConfig();
- var previousVersion = new Version(
- barback.supportedVersion.major, barback.supportedVersion.minor - 1, 0);
+ var current = barback.supportedVersion.toString();
+ var previous = new Version(barback.supportedVersion.major,
+ barback.supportedVersion.minor - 1, 0).toString();
+ var nextPatch = barback.supportedVersion.nextPatch.toString();
+ var max = barback.supportedVersion.nextMinor.toString();
forBothPubGetAndUpgrade((command) {
integration("implicitly constrains barback to versions pub supports", () {
servePackages([
- packageMap("barback", previousVersion.toString()),
- packageMap("barback", barback.supportedVersion.toString()),
- packageMap("barback", barback.supportedVersion.nextPatch.toString()),
- packageMap("barback", barback.supportedVersion.nextMinor.toString())
+ packageMap("barback", previous),
+ packageMap("barback", current),
+ packageMap("barback", nextPatch),
+ packageMap("barback", max)
]);
d.appDir({
@@ -35,10 +38,10 @@
integration("discovers transitive dependency on barback", () {
servePackages([
- packageMap("barback", previousVersion.toString()),
- packageMap("barback", barback.supportedVersion.toString()),
- packageMap("barback", barback.supportedVersion.nextPatch.toString()),
- packageMap("barback", barback.supportedVersion.nextMinor.toString())
+ packageMap("barback", previous),
+ packageMap("barback", current),
+ packageMap("barback", nextPatch),
+ packageMap("barback", max)
]);
d.dir("foo", [
@@ -55,30 +58,78 @@
pubCommand(command);
d.packagesDir({
- "barback": barback.supportedVersion.nextPatch.toString(),
+ "barback": nextPatch,
"foo": "0.0.1"
}).validate();
});
+
+ integration("pub's implicit constraint uses the same source and "
+ "description as the explicit one", () {
+ d.dir('barback', [
+ d.libDir('barback', 'barback $current'),
+ d.libPubspec('barback', current)
+ ]).create();
+
+ d.dir(appPath, [
+ d.appPubspec({
+ "barback": {"path": "../barback"}
+ })
+ ]).create();
+
+ pubCommand(command);
+
+ d.packagesDir({
+ "barback": current
+ }).validate();
+ });
});
integration("unlock if the locked version doesn't meet pub's constraint", () {
servePackages([
- packageMap("barback", previousVersion.toString()),
- packageMap("barback", barback.supportedVersion.toString())
+ packageMap("barback", previous),
+ packageMap("barback", current)
]);
d.appDir({"barback": "any"}).create();
// Hand-create a lockfile to pin barback to an older version.
createLockFile("myapp", hosted: {
- "barback": previousVersion.toString()
+ "barback": previous
});
pubGet();
// It should be upgraded.
d.packagesDir({
- "barback": barback.supportedVersion.toString()
+ "barback": current
}).validate();
});
+
+ integration("includes pub in the error if a solve failed because there "
+ "is no version available", () {
+ servePackages([
+ packageMap("barback", previous)
+ ]);
+
+ d.appDir({"barback": "any"}).create();
+
+ pubGet(error: """
+Package barback has no versions that match >=$current <$max derived from:
+- myapp depends on version any
+- pub itself depends on version >=$current <$max""");
+ });
+
+ integration("includes pub in the error if a solve failed because there "
+ "is a disjoint constraint", () {
+ servePackages([
+ packageMap("barback", current)
+ ]);
+
+ d.appDir({"barback": previous}).create();
+
+ pubGet(error: """
+Incompatible version constraints on barback:
+- myapp depends on version $previous
+- pub itself depends on version >=$current <$max""");
+ });
}
\ No newline at end of file
diff --git a/sdk/lib/_internal/pub/test/pub_get_and_upgrade_test.dart b/sdk/lib/_internal/pub/test/pub_get_and_upgrade_test.dart
index f0df450..337c957 100644
--- a/sdk/lib/_internal/pub/test/pub_get_and_upgrade_test.dart
+++ b/sdk/lib/_internal/pub/test/pub_get_and_upgrade_test.dart
@@ -110,7 +110,7 @@
]).create();
pubCommand(command,
- error: new RegExp("^Incompatible dependencies on 'baz':\n"));
+ error: new RegExp("^Incompatible dependencies on baz:\n"));
});
integration('does not allow a dependency on itself', () {
diff --git a/sdk/lib/_internal/pub/test/serve/warns_on_assets_paths_test.dart b/sdk/lib/_internal/pub/test/serve/warns_on_assets_paths_test.dart
new file mode 100644
index 0000000..c4ae0c5
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/serve/warns_on_assets_paths_test.dart
@@ -0,0 +1,117 @@
+// 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 pub_tests;
+
+import 'package:path/path.dart' as path;
+import 'package:scheduled_test/scheduled_test.dart';
+
+import '../descriptor.dart' as d;
+import '../test_pub.dart';
+import 'utils.dart';
+
+getWarningRegExp(String assetsPath) {
+ // Escape backslashes since they are metacharacters in a regex.
+ assetsPath = assetsPath.replaceAll("\\", "\\\\");
+ return new RegExp(
+ '^Warning: Pub reserves paths containing "assets" for using assets from '
+ 'packages\\. Please rename the path "$assetsPath"\\.\$');
+}
+
+main() {
+ initConfig();
+
+ integration('warns user about assets dir in the root of "web"', () {
+ d.dir(appPath, [
+ d.appPubspec(),
+ d.dir('web', [
+ d.file('index.html'),
+ d.dir('assets')
+ ])
+ ]).create();
+
+ var pub = pubServe();
+ waitForBuildSuccess();
+ endPubServe();
+
+ var assetsPath = path.join('web', 'assets');
+ expect(pub.remainingStderr(), completion(
+ matches(getWarningRegExp(assetsPath))));
+ });
+
+ integration('warns user about assets dir nested anywhere in "web"', () {
+ d.dir(appPath, [
+ d.appPubspec(),
+ d.dir('web', [
+ d.file('index.html'),
+ d.dir('foo', [
+ d.dir('assets')
+ ])
+ ])
+ ]).create();
+
+ var pub = pubServe();
+ waitForBuildSuccess();
+ endPubServe();
+
+ var assetsPath = path.join('web', 'foo', 'assets');
+ expect(pub.remainingStderr(), completion(
+ matches(getWarningRegExp(assetsPath))));
+ });
+
+ integration('warns user about assets file in the root of "web"', () {
+ d.dir(appPath, [
+ d.appPubspec(),
+ d.dir('web', [
+ d.file('index.html'),
+ d.file('assets')
+ ])
+ ]).create();
+
+ var pub = pubServe();
+ waitForBuildSuccess();
+ endPubServe();
+
+ var assetsPath = path.join('web', 'assets');
+ expect(pub.remainingStderr(), completion(
+ matches(getWarningRegExp(assetsPath))));
+ });
+
+ integration('warns user about assets file nested anywhere in "web"', () {
+ d.dir(appPath, [
+ d.appPubspec(),
+ d.dir('web', [
+ d.file('index.html'),
+ d.dir('foo', [
+ d.file('assets')
+ ])
+ ])
+ ]).create();
+
+ var pub = pubServe();
+ waitForBuildSuccess();
+ endPubServe();
+
+ var assetsPath = path.join('web', 'foo', 'assets');
+ expect(pub.remainingStderr(), completion(
+ matches(getWarningRegExp(assetsPath))));
+ });
+
+ integration('does not warn if no assets dir or file anywhere in "web"', () {
+ d.dir(appPath, [
+ d.appPubspec(),
+ d.dir('web', [
+ d.file('index.html'),
+ d.dir('foo')
+ ])
+ ]).create();
+
+ var pub = pubServe();
+ waitForBuildSuccess();
+ endPubServe();
+
+ expect(pub.remainingStderr(), completion(
+ matches(r'^(?!Warning: Pub reserves paths containing "assets").*$')));
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/test_pub.dart b/sdk/lib/_internal/pub/test/test_pub.dart
index 6eef80b..22c12b2 100644
--- a/sdk/lib/_internal/pub/test/test_pub.dart
+++ b/sdk/lib/_internal/pub/test/test_pub.dart
@@ -147,6 +147,7 @@
if (_server == null) return new Future.value();
var future = _server.close();
_server = null;
+ _hasServer = false;
_portCompleterCache = null;
return future;
}
@@ -263,13 +264,13 @@
/// Enum identifying a pub command that can be run with a well-defined success
/// output.
class RunCommand {
- static final get = new RunCommand('get', 'Got dependencies!');
- static final upgrade = new RunCommand('upgrade', 'Dependencies upgraded!');
+ static final get = new RunCommand('get', new RegExp(r'Got dependencies!$'));
+ static final upgrade = new RunCommand('upgrade', new RegExp(
+ r'(No dependencies changed\.|Changed \d+ dependenc(y|ies)!)$'));
final String name;
final RegExp success;
- RunCommand(this.name, String message)
- : success = new RegExp("$message\$");
+ RunCommand(this.name, this.success);
}
/// Many tests validate behavior that is the same between pub get and
@@ -290,8 +291,8 @@
/// [warning] to stderr. If [error] is given, it expects the command to *only*
/// print [error] to stderr.
// TODO(rnystrom): Clean up other tests to call this when possible.
-void pubCommand(RunCommand command, {Iterable<String> args, Pattern error,
- Pattern warning}) {
+void pubCommand(RunCommand command,
+ {Iterable<String> args, Pattern output, Pattern error, Pattern warning}) {
if (error != null && warning != null) {
throw new ArgumentError("Cannot pass both 'error' and 'warning'.");
}
@@ -299,7 +300,7 @@
var allArgs = [command.name];
if (args != null) allArgs.addAll(args);
- var output = command.success;
+ if (output == null) output = command.success;
var exitCode = null;
if (error != null) exitCode = 1;
@@ -316,9 +317,10 @@
pubCommand(RunCommand.get, args: args, error: error, warning: warning);
}
-void pubUpgrade({Iterable<String> args, Pattern error,
+void pubUpgrade({Iterable<String> args, Pattern output, Pattern error,
Pattern warning}) {
- pubCommand(RunCommand.upgrade, args: args, error: error, warning: warning);
+ pubCommand(RunCommand.upgrade, args: args, output: output, error: error,
+ warning: warning);
}
/// Defines an integration test. The [body] should schedule a series of
@@ -433,7 +435,7 @@
// TODO(rnystrom): This is overly specific and inflexible regarding different
// test packages. Should validate this a little more loosely.
expect(pub.nextLine(), completion(startsWith(
- 'Publishing "test_pkg" 1.0.0 to ')));
+ 'Publishing test_pkg 1.0.0 to ')));
expect(pub.nextLine(), completion(equals("|-- LICENSE")));
expect(pub.nextLine(), completion(equals("|-- lib")));
expect(pub.nextLine(), completion(equals("| '-- test_pkg.dart")));
@@ -835,7 +837,7 @@
return schedule(() {
var cache = new SystemCache.withSources(path.join(sandboxDir, cachePath));
- return new Future.sync(() {
+ return syncFuture(() {
var validator = fn(new Entrypoint(path.join(sandboxDir, appPath), cache));
return validator.validate().then((_) {
return new Pair(validator.errors, validator.warnings);
diff --git a/sdk/lib/_internal/pub/test/transformer/dart2js/reads_nonpublic_files_from_disk_test.dart b/sdk/lib/_internal/pub/test/transformer/dart2js/reads_nonpublic_files_from_disk_test.dart
new file mode 100644
index 0000000..982c45e
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/transformer/dart2js/reads_nonpublic_files_from_disk_test.dart
@@ -0,0 +1,42 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS d.file
+// for 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 pub_tests;
+
+import 'package:scheduled_test/scheduled_test.dart';
+
+import '../../descriptor.dart' as d;
+import '../../test_pub.dart';
+import '../../serve/utils.dart';
+
+main() {
+ initConfig();
+ integration("reads imported files from non-public directories straight from"
+ "the file system", () {
+ // Since the "private" directory isn't served by the barback server, the
+ // relative import for it will fail if the dart2js transformer tries to
+ // get it from barback. This is a regression test for dartbug.com/15688.
+ d.dir(appPath, [
+ d.appPubspec(),
+ d.dir("private", [
+ d.file("lib.dart", """
+library lib;
+lib() => 'libtext';
+""")
+ ]),
+ d.dir("web", [
+ d.file("main.dart", """
+import '../private/lib.dart';
+void main() {
+ print(lib());
+}
+""")
+ ])
+ ]).create();
+
+ pubServe();
+ requestShouldSucceed("main.dart.js", contains("libtext"));
+ endPubServe();
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/unknown_source_test.dart b/sdk/lib/_internal/pub/test/unknown_source_test.dart
index d198083..9ecc3a9 100644
--- a/sdk/lib/_internal/pub/test/unknown_source_test.dart
+++ b/sdk/lib/_internal/pub/test/unknown_source_test.dart
@@ -17,7 +17,7 @@
d.appDir({"foo": {"bad": "foo"}}).create();
pubCommand(command, error:
- "Package 'myapp' depends on 'foo' from unknown source 'bad'.");
+ 'Package myapp depends on foo from unknown source "bad".');
});
integration('fails gracefully on transitive dependency from an unknown '
@@ -30,7 +30,7 @@
d.appDir({"foo": {"path": "../foo"}}).create();
pubCommand(command, error:
- "Package 'foo' depends on 'bar' from unknown source 'bad'.");
+ 'Package foo depends on bar from unknown source "bad".');
});
integration('ignores unknown source in lockfile', () {
diff --git a/sdk/lib/_internal/pub/test/upgrade/report/describes_change_test.dart b/sdk/lib/_internal/pub/test/upgrade/report/describes_change_test.dart
new file mode 100644
index 0000000..9bb02a5
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/upgrade/report/describes_change_test.dart
@@ -0,0 +1,62 @@
+// 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 pub_tests;
+
+import '../../descriptor.dart' as d;
+import '../../test_pub.dart';
+
+main() {
+ initConfig();
+ integration("shows how package changed from previous lockfile", () {
+ servePackages([
+ packageMap("unchanged", "1.0.0"),
+ packageMap("version_changed", "1.0.0"),
+ packageMap("version_changed", "2.0.0"),
+ packageMap("source_changed", "1.0.0")
+ ]);
+
+ d.dir("source_changed", [
+ d.libDir("source_changed"),
+ d.libPubspec("source_changed", "2.0.0")
+ ]).create();
+
+ d.dir("description_changed_1", [
+ d.libDir("description_changed"),
+ d.libPubspec("description_changed", "1.0.0")
+ ]).create();
+
+ d.dir("description_changed_2", [
+ d.libDir("description_changed"),
+ d.libPubspec("description_changed", "1.0.0")
+ ]).create();
+
+ // Create the first lockfile.
+ d.appDir({
+ "unchanged": "any",
+ "version_changed": "1.0.0",
+ "source_changed": "any",
+ "description_changed": {"path": "../description_changed_1"}
+ }).create();
+
+ pubGet();
+
+ // Change the pubspec.
+ d.appDir({
+ "unchanged": "any",
+ "version_changed": "any",
+ "source_changed": {"path": "../source_changed"},
+ "description_changed": {"path": "../description_changed_2"}
+ }).create();
+
+ // Upgrade everything.
+ pubUpgrade(output: new RegExp(r"""
+Resolving dependencies\.+
+. description_changed 1\.0\.0 from path \.\.[/\\]description_changed_2 \(was 1\.0\.0 from path \.\.[/\\]description_changed_1\)
+. source_changed 2\.0\.0 from path \.\.[/\\]source_changed \(was 1\.0\.0\)
+. unchanged 1\.0\.0
+. version_changed 2\.0\.0 \(was 1\.0\.0\)
+""", multiLine: true));
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/upgrade/report/does_not_show_newer_versions_for_locked_packages_test.dart b/sdk/lib/_internal/pub/test/upgrade/report/does_not_show_newer_versions_for_locked_packages_test.dart
new file mode 100644
index 0000000..b442686
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/upgrade/report/does_not_show_newer_versions_for_locked_packages_test.dart
@@ -0,0 +1,44 @@
+// 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 pub_tests;
+
+import '../../descriptor.dart' as d;
+import '../../test_pub.dart';
+
+main() {
+ initConfig();
+ integration("does not show how many newer versions are available for "
+ "packages that are locked and not being upgraded", () {
+ servePackages([
+ packageMap("not_upgraded", "1.0.0"),
+ packageMap("not_upgraded", "2.0.0"),
+ packageMap("not_upgraded", "3.0.0-dev"),
+ packageMap("upgraded", "1.0.0"),
+ packageMap("upgraded", "2.0.0"),
+ packageMap("upgraded", "3.0.0-dev")
+ ]);
+
+ // Constraint everything to the first version.
+ d.appDir({
+ "not_upgraded": "1.0.0",
+ "upgraded": "1.0.0"
+ }).create();
+
+ pubGet();
+
+ // Loosen the constraints.
+ d.appDir({
+ "not_upgraded": "any",
+ "upgraded": "any"
+ }).create();
+
+ // Only upgrade "upgraded".
+ pubUpgrade(args: ["upgraded"], output: new RegExp(r"""
+Resolving dependencies\.+
+ not_upgraded 1\.0\.0
+. upgraded 2\.0\.0 \(was 1\.0\.0\) \(1 newer unstable version available\)
+""", multiLine: true));
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/upgrade/report/highlights_overrides_test.dart b/sdk/lib/_internal/pub/test/upgrade/report/highlights_overrides_test.dart
new file mode 100644
index 0000000..6bbccc5
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/upgrade/report/highlights_overrides_test.dart
@@ -0,0 +1,32 @@
+// 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 pub_tests;
+
+import '../../descriptor.dart' as d;
+import '../../test_pub.dart';
+
+main() {
+ initConfig();
+ integration("highlights overridden packages", () {
+ servePackages([
+ packageMap("overridden", "1.0.0")
+ ]);
+
+ d.dir(appPath, [
+ d.pubspec({
+ "name": "myapp",
+ "dependency_overrides": {
+ "overridden": "any"
+ }
+ })
+ ]).create();
+
+ // Upgrade everything.
+ pubUpgrade(output: new RegExp(r"""
+Resolving dependencies\.+
+! overridden 1\.0\.0 \(overridden\)
+""", multiLine: true));
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/upgrade/report/leading_character_shows_change_test.dart b/sdk/lib/_internal/pub/test/upgrade/report/leading_character_shows_change_test.dart
new file mode 100644
index 0000000..815f640
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/upgrade/report/leading_character_shows_change_test.dart
@@ -0,0 +1,92 @@
+// 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 pub_tests;
+
+import '../../descriptor.dart' as d;
+import '../../test_pub.dart';
+
+main() {
+ initConfig();
+ integration("the character before each package describes the change", () {
+ servePackages([
+ packageMap("added", "1.0.0"),
+ packageMap("downgraded", "1.0.0"),
+ packageMap("downgraded", "2.0.0"),
+ packageMap("overridden", "1.0.0"),
+ packageMap("removed", "1.0.0"),
+ packageMap("source_changed", "1.0.0"),
+ packageMap("upgraded", "1.0.0"),
+ packageMap("upgraded", "2.0.0"),
+ packageMap("unchanged", "1.0.0")
+ ]);
+
+ d.dir("description_changed_1", [
+ d.libDir("description_changed"),
+ d.libPubspec("description_changed", "1.0.0")
+ ]).create();
+
+ d.dir("description_changed_2", [
+ d.libDir("description_changed"),
+ d.libPubspec("description_changed", "1.0.0")
+ ]).create();
+
+ d.dir("source_changed", [
+ d.libDir("source_changed"),
+ d.libPubspec("source_changed", "1.0.0")
+ ]).create();
+
+ // Create the first lockfile.
+ d.dir(appPath, [
+ d.pubspec({
+ "name": "myapp",
+ "dependencies": {
+ "description_changed": {"path": "../description_changed_1"},
+ "downgraded": "2.0.0",
+ "removed": "any",
+ "source_changed": "any",
+ "unchanged": "any",
+ "upgraded": "1.0.0"
+ },
+ "dependency_overrides": {
+ "overridden": "any"
+ }
+ })
+ ]).create();
+
+ pubGet();
+
+ // Change the pubspec.
+ d.dir(appPath, [
+ d.pubspec({
+ "name": "myapp",
+ "dependencies": {
+ "added": "any",
+ "description_changed": {"path": "../description_changed_2"},
+ "downgraded": "1.0.0",
+ "source_changed": {"path": "../source_changed"},
+ "unchanged": "any",
+ "upgraded": "2.0.0"
+ },
+ "dependency_overrides": {
+ "overridden": "any"
+ }
+ })
+ ]).create();
+
+ // Upgrade everything.
+ pubUpgrade(output: new RegExp(r"""
+Resolving dependencies\.+
+\+ added .*
+\* description_changed .*
+< downgraded .*
+! overridden .*
+\* source_changed .*
+ unchanged .*
+> upgraded .*
+These packages are no longer being depended on:
+- removed .*
+""", multiLine: true));
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/upgrade/report/shows_newer_available_versions_test.dart b/sdk/lib/_internal/pub/test/upgrade/report/shows_newer_available_versions_test.dart
new file mode 100644
index 0000000..c887135
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/upgrade/report/shows_newer_available_versions_test.dart
@@ -0,0 +1,52 @@
+// 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 pub_tests;
+
+import '../../descriptor.dart' as d;
+import '../../test_pub.dart';
+
+main() {
+ initConfig();
+ integration("shows how many newer versions are available", () {
+ servePackages([
+ packageMap("multiple_newer", "1.0.0"),
+ packageMap("multiple_newer", "1.0.1-unstable.1"),
+ packageMap("multiple_newer", "1.0.1"),
+ packageMap("multiple_newer", "1.0.2-unstable.1"),
+ packageMap("multiple_newer_stable", "1.0.0"),
+ packageMap("multiple_newer_stable", "1.0.1"),
+ packageMap("multiple_newer_stable", "1.0.2"),
+ packageMap("multiple_newer_unstable", "1.0.0"),
+ packageMap("multiple_newer_unstable", "1.0.1-unstable.1"),
+ packageMap("multiple_newer_unstable", "1.0.1-unstable.2"),
+ packageMap("no_newer", "1.0.0"),
+ packageMap("one_newer_unstable", "1.0.0"),
+ packageMap("one_newer_unstable", "1.0.1-unstable.1"),
+ packageMap("one_newer_stable", "1.0.0"),
+ packageMap("one_newer_stable", "1.0.1")
+ ]);
+
+ // Constraint everything to the first version.
+ d.appDir({
+ "multiple_newer": "1.0.0",
+ "multiple_newer_stable": "1.0.0",
+ "multiple_newer_unstable": "1.0.0",
+ "no_newer": "1.0.0",
+ "one_newer_unstable": "1.0.0",
+ "one_newer_stable": "1.0.0"
+ }).create();
+
+ // Upgrade everything.
+ pubUpgrade(output: new RegExp(r"""
+Resolving dependencies\.+
+. multiple_newer 1\.0\.0 \(1 newer version available\)
+. multiple_newer_stable 1\.0\.0 \(2 newer versions available\)
+. multiple_newer_unstable 1\.0\.0 \(2 newer unstable versions available\)
+. no_newer 1\.0\.0
+. one_newer_stable 1\.0\.0 \(1 newer version available\)
+. one_newer_unstable 1\.0\.0 \(1 newer unstable version available\)
+""", multiLine: true));
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/upgrade/report/shows_number_of_changed_dependencies_test.dart b/sdk/lib/_internal/pub/test/upgrade/report/shows_number_of_changed_dependencies_test.dart
new file mode 100644
index 0000000..77010e2c
--- /dev/null
+++ b/sdk/lib/_internal/pub/test/upgrade/report/shows_number_of_changed_dependencies_test.dart
@@ -0,0 +1,38 @@
+// 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 pub_tests;
+
+import '../../descriptor.dart' as d;
+import '../../test_pub.dart';
+
+main() {
+ initConfig();
+ integration("does not show how many newer versions are available for "
+ "packages that are locked and not being upgraded", () {
+ servePackages([
+ packageMap("a", "1.0.0"),
+ packageMap("b", "1.0.0"),
+ packageMap("c", "2.0.0")
+ ]);
+
+ d.appDir({
+ "a": "any"
+ }).create();
+
+ // One dependency changed.
+ pubUpgrade(output: new RegExp(r"Changed 1 dependency!$"));
+
+ // Remove one and add two.
+ d.appDir({
+ "b": "any",
+ "c": "any"
+ }).create();
+
+ pubUpgrade(output: new RegExp(r"Changed 3 dependencies!$"));
+
+ // Don't change anything.
+ pubUpgrade(output: new RegExp(r"No dependencies changed.$"));
+ });
+}
diff --git a/sdk/lib/_internal/pub/test/version_solver_test.dart b/sdk/lib/_internal/pub/test/version_solver_test.dart
index 4200480..11afd79 100644
--- a/sdk/lib/_internal/pub/test/version_solver_test.dart
+++ b/sdk/lib/_internal/pub/test/version_solver_test.dart
@@ -15,6 +15,7 @@
import '../lib/src/sdk.dart' as sdk;
import '../lib/src/source.dart';
import '../lib/src/system_cache.dart';
+import '../lib/src/utils.dart';
import '../lib/src/version.dart';
import '../lib/src/solver/version_solver.dart';
import 'test_pub.dart';
@@ -261,7 +262,7 @@
'bar 1.0.0': {
'myapp from mock2': '>=1.0.0'
}
- }, error: sourceMismatch('foo', 'bar'));
+ }, error: sourceMismatch('myapp', 'foo', 'bar'));
testResolve('with wrong version', {
'myapp 1.0.0': {
@@ -322,7 +323,7 @@
},
'foo 2.0.0': {},
'foo 2.1.3': {}
- }, error: noVersion(['myapp']));
+ }, error: noVersion(['myapp', 'foo']));
testResolve('no version that matches combined constraint', {
'myapp 0.0.0': {
@@ -337,7 +338,7 @@
},
'shared 2.5.0': {},
'shared 3.5.0': {}
- }, error: noVersion(['foo', 'bar']));
+ }, error: noVersion(['shared', 'foo', 'bar']));
testResolve('disjoint constraints', {
'myapp 0.0.0': {
@@ -352,7 +353,7 @@
},
'shared 2.0.0': {},
'shared 4.0.0': {}
- }, error: disjointConstraint(['foo', 'bar']));
+ }, error: disjointConstraint(['shared', 'foo', 'bar']));
testResolve('mismatched descriptions', {
'myapp 0.0.0': {
@@ -367,7 +368,7 @@
},
'shared-x 1.0.0': {},
'shared-y 1.0.0': {}
- }, error: descriptionMismatch('foo', 'bar'));
+ }, error: descriptionMismatch('shared', 'foo', 'bar'));
testResolve('mismatched sources', {
'myapp 0.0.0': {
@@ -382,7 +383,7 @@
},
'shared 1.0.0': {},
'shared 1.0.0 from mock2': {}
- }, error: sourceMismatch('foo', 'bar'));
+ }, error: sourceMismatch('shared', 'foo', 'bar'));
testResolve('no valid solution', {
'myapp 0.0.0': {
@@ -411,7 +412,7 @@
},
'a 1.0.0': {},
'b 1.0.0': {}
- }, error: noVersion(['myapp']), maxTries: 1);
+ }, error: noVersion(['myapp', 'b']), maxTries: 1);
}
badSource() {
@@ -632,7 +633,7 @@
'c 3.0.0': {},
'c 4.0.0': {},
'c 5.0.0': {},
- }, error: sourceMismatch('myapp', 'b'), maxTries: 1);
+ }, error: sourceMismatch('a', 'myapp', 'b'), maxTries: 1);
testResolve('backjump to conflicting description', {
'myapp 0.0.0': {
@@ -650,7 +651,7 @@
'c 3.0.0': {},
'c 4.0.0': {},
'c 5.0.0': {},
- }, error: descriptionMismatch('myapp', 'b'), maxTries: 1);
+ }, error: descriptionMismatch('a', 'myapp', 'b'), maxTries: 1);
// Dependencies are ordered so that packages with fewer versions are tried
// first. Here, there are two valid solutions (either a or b must be
@@ -1083,9 +1084,10 @@
DisjointConstraintException);
}
-FailMatcherBuilder descriptionMismatch(String package1, String package2) {
- return (maxTries) => new SolveFailMatcher([package1, package2], maxTries,
- DescriptionMismatchException);
+FailMatcherBuilder descriptionMismatch(
+ String package, String depender1, String depender2) {
+ return (maxTries) => new SolveFailMatcher([package, depender1, depender2],
+ maxTries, DescriptionMismatchException);
}
// If no solution can be found, the solver just reports the last failure that
@@ -1094,9 +1096,10 @@
SolveFailMatcher couldNotSolve(maxTries) =>
new SolveFailMatcher([], maxTries, null);
-FailMatcherBuilder sourceMismatch(String package1, String package2) {
- return (maxTries) => new SolveFailMatcher([package1, package2], maxTries,
- SourceMismatchException);
+FailMatcherBuilder sourceMismatch(
+ String package, String depender1, String depender2) {
+ return (maxTries) => new SolveFailMatcher([package, depender1, depender2],
+ maxTries, SourceMismatchException);
}
unknownSource(String depender, String dependency, String source) {
@@ -1268,7 +1271,7 @@
}
Future<List<Version>> getVersions(String name, String description) {
- return new Future.sync(() {
+ return syncFuture(() {
// Make sure the solver doesn't request the same thing twice.
if (_requestedVersions.contains(description)) {
throw new Exception('Version list for $description was already '
@@ -1287,7 +1290,7 @@
}
Future<Pubspec> describe(PackageId id) {
- return new Future.sync(() {
+ return syncFuture(() {
// Make sure the solver doesn't request the same thing twice.
if (_requestedPubspecs.containsKey(id.description) &&
_requestedPubspecs[id.description].contains(id.version)) {
diff --git a/sdk/lib/async/stream.dart b/sdk/lib/async/stream.dart
index 957ca2e..b722e46 100644
--- a/sdk/lib/async/stream.dart
+++ b/sdk/lib/async/stream.dart
@@ -49,6 +49,11 @@
*
* Broadcast streams are used for independent events/observers.
*
+ * Stream transformations, such as [where] and [skip], always return
+ * non-broadcast streams. If several listeners want to listen to the returned
+ * stream, use [asBroadcastStream] to create a broadcast stream on top of the
+ * non-broadcast stream.
+ *
* The default implementation of [isBroadcast] returns false.
* A broadcast stream inheriting from [Stream] must override [isBroadcast]
* to return [:true:].
@@ -256,6 +261,8 @@
*
* The new stream sends the same error and done events as this stream,
* but it only sends the data events that satisfy the [test].
+ *
+ * The returned stream is not a broadcast stream, even if this stream is.
*/
Stream<T> where(bool test(T event)) {
return new _WhereStream<T>(this, test);
@@ -264,6 +271,8 @@
/**
* Creates a new stream that converts each element of this stream
* to a new value using the [convert] function.
+ *
+ * The returned stream is not a broadcast stream, even if this stream is.
*/
Stream map(convert(T event)) {
return new _MapStream<T, dynamic>(this, convert);
@@ -281,8 +290,8 @@
* trace. The stack trace argument might be `null` if the stream itself
* received an error without stack trace.
*
- * An [AsyncError] [:e:] is matched by a test function if [:test(e):] returns
- * true. If [test] is omitted, every error is considered matching.
+ * An asynchronous error [:e:] is matched by a test function if [:test(e):]
+ * returns true. If [test] is omitted, every error is considered matching.
*
* If the error is intercepted, the [handle] function can decide what to do
* with it. It can throw if it wants to raise a new (or the same) error,
@@ -291,6 +300,8 @@
* If you need to transform an error into a data event, use the more generic
* [Stream.transform] to handle the event by writing a data event to
* the output sink
+ *
+ * The returned stream is not a broadcast stream, even if this stream is.
*/
Stream<T> handleError(Function onError, { bool test(error) }) {
return new _HandleErrorStream<T>(this, onError, test);
@@ -303,6 +314,8 @@
* Each incoming event is converted to an [Iterable] of new events,
* and each of these new events are then sent by the returned stream
* in order.
+ *
+ * The returned stream is not a broadcast stream, even if this stream is.
*/
Stream expand(Iterable convert(T value)) {
return new _ExpandStream<T, dynamic>(this, convert);
@@ -637,6 +650,8 @@
* Internally the method cancels its subscription after these elements. This
* means that single-subscription (non-broadcast) streams are closed and
* cannot be reused after a call to this method.
+ *
+ * The returned stream is not a broadcast stream, even if this stream is.
*/
Stream<T> take(int count) {
return new _TakeStream(this, count);
@@ -655,6 +670,8 @@
* Internally the method cancels its subscription after these elements. This
* means that single-subscription (non-broadcast) streams are closed and
* cannot be reused after a call to this method.
+ *
+ * The returned stream is not a broadcast stream, even if this stream is.
*/
Stream<T> takeWhile(bool test(T element)) {
return new _TakeWhileStream(this, test);
@@ -662,6 +679,8 @@
/**
* Skips the first [count] data events from this stream.
+ *
+ * The returned stream is not a broadcast stream, even if this stream is.
*/
Stream<T> skip(int count) {
return new _SkipStream(this, count);
@@ -674,6 +693,8 @@
*
* Starting with the first data event where [test] returns false for the
* event data, the returned stream will have the same events as this stream.
+ *
+ * The returned stream is not a broadcast stream, even if this stream is.
*/
Stream<T> skipWhile(bool test(T element)) {
return new _SkipWhileStream(this, test);
@@ -687,6 +708,8 @@
*
* Equality is determined by the provided [equals] method. If that is
* omitted, the '==' operator on the last provided data element is used.
+ *
+ * The returned stream is not a broadcast stream, even if this stream is.
*/
Stream<T> distinct([bool equals(T previous, T next)]) {
return new _DistinctStream(this, equals);
@@ -977,6 +1000,8 @@
*
* If `onTimeout` is omitted, a timeout will just put a [TimeoutException]
* into the error channel of the returned stream.
+ *
+ * The returned stream is not a broadcast stream, even if this stream is.
*/
Stream timeout(Duration timeLimit, {void onTimeout(EventSink sink)}) {
StreamSubscription<T> subscription;
diff --git a/sdk/lib/collection/list.dart b/sdk/lib/collection/list.dart
index ca2b39e..d4dac6a 100644
--- a/sdk/lib/collection/list.dart
+++ b/sdk/lib/collection/list.dart
@@ -20,7 +20,7 @@
* repeatedly increasing the length of a growable list is not efficient.
* To avoid this, either override 'add' and 'addAll' to also forward directly
* to the growable list, or, preferably, use `DelegatingList` from
- * "package:collection_helpers/wrappers.dart" instead.
+ * "package:collection/wrappers.dart" instead.
*/
abstract class ListBase<E> = Object with ListMixin<E>;
@@ -40,7 +40,7 @@
* repeatedly increasing the length of a growable list is not efficient.
* To avoid this, either override 'add' and 'addAll' to also forward directly
* to the growable list, or, if possible, use `DelegatingList` from
- * "package:collection_helpers/wrappers.dart" instead.
+ * "package:collection/wrappers.dart" instead.
*/
abstract class ListMixin<E> implements List<E> {
diff --git a/sdk/lib/collection/splay_tree.dart b/sdk/lib/collection/splay_tree.dart
index 389e678..114505e 100644
--- a/sdk/lib/collection/splay_tree.dart
+++ b/sdk/lib/collection/splay_tree.dart
@@ -625,10 +625,47 @@
}
+/**
+ * A [Set] of objects that can be ordered relative to each other.
+ *
+ * The set is based on a self-balancing binary tree. It allows most operations
+ * in amortized logarithmic time.
+ *
+ * Elements of the set are compared using the `compare` function passed in
+ * the constructor. If that is omitted, the objects are assumed to be
+ * [Comparable], and are compared using their [Comparable.compareTo]
+ * method. Non-comparable objects (including `null`) will not work as an element
+ * in that case.
+ */
class SplayTreeSet<E> extends _SplayTree<E> with IterableMixin<E>
implements Set<E> {
Comparator _comparator;
_Predicate _validKey;
+
+ /**
+ * Create a new [SplayTreeSet] with the given compare function.
+ *
+ * If the [compare] function is omitted, it defaults to [Comparable.compare],
+ * and the elements must be comparable.
+ *
+ * A provided `compare` function may not work on all objects. It may not even
+ * work on all `E` instances.
+ *
+ * For operations that add elements to the set, the user is supposed to not
+ * pass in objects that doesn't work with the compare function.
+ *
+ * The methods [contains], [remove], [lookup], [removeAll] or [retainAll]
+ * are typed to accept any object(s), and the [isValidKey] test can used to
+ * filter those objects before handing them to the `compare` function.
+ *
+ * If [isValidKey] is provided, only values satisfying `isValidKey(other)`
+ * are compared using the `compare` method in the methods mentioned above.
+ * If the `isValidKey` function returns false for an object, it is assumed to
+ * not be in the set.
+ *
+ * If omitted, the `isValidKey` function defaults to checking against the
+ * type parameter: `other is E`.
+ */
SplayTreeSet([int compare(E key1, E key2), bool isValidKey(potentialKey)])
: _comparator = (compare == null) ? Comparable.compare : compare,
_validKey = (isValidKey != null) ? isValidKey : ((v) => v is E);
@@ -685,7 +722,7 @@
}
}
- void removeAll(Iterable elements) {
+ void removeAll(Iterable<Object> elements) {
for (Object element in elements) {
if (_validKey(element)) _remove(element);
}
@@ -703,7 +740,8 @@
// The iterator should not have side effects.
throw new ConcurrentModificationError(this);
}
- if (this.contains(object)) retainSet.add(object);
+ // Equivalent to this.contains(object).
+ if (_validKey(object) && _splay(object) == 0) retainSet.add(_root.key);
}
// Take over the elements from the retained set, if it differs.
if (retainSet._count != _count) {
@@ -745,7 +783,7 @@
}
Set<E> intersection(Set<E> other) {
- Set<E> result = new SplayTreeSet<E>();
+ Set<E> result = new SplayTreeSet<E>(_compare, _validKey);
for (E element in this) {
if (other.contains(element)) result.add(element);
}
@@ -753,7 +791,7 @@
}
Set<E> difference(Set<E> other) {
- Set<E> result = new SplayTreeSet<E>();
+ Set<E> result = new SplayTreeSet<E>(_compare, _validKey);
for (E element in this) {
if (!other.contains(element)) result.add(element);
}
@@ -765,7 +803,7 @@
}
SplayTreeSet<E> _clone() {
- var set = new SplayTreeSet<E>();
+ var set = new SplayTreeSet<E>(_compare, _validKey);
set._count = _count;
set._root = _cloneNode(_root);
return set;
@@ -777,7 +815,7 @@
..right = _cloneNode(node.right);
}
- bool containsAll(Iterable other) {
+ bool containsAll(Iterable<Object> other) {
for (var element in other) {
if (!this.contains(element)) return false;
}
diff --git a/sdk/lib/convert/chunked_conversion.dart b/sdk/lib/convert/chunked_conversion.dart
index 80425fd..c0a5c65 100644
--- a/sdk/lib/convert/chunked_conversion.dart
+++ b/sdk/lib/convert/chunked_conversion.dart
@@ -9,6 +9,9 @@
/**
* A [ChunkedConversionSink] is used to transmit data more efficiently between
* two converters during chunked conversions.
+ *
+ * It is recommended that implementations of `ChunkedConversionSink` extends
+ * this class, to inherit any further methods that may be added to the class.
*/
abstract class ChunkedConversionSink<T> {
ChunkedConversionSink();
diff --git a/sdk/lib/convert/converter.dart b/sdk/lib/convert/converter.dart
index 0556761..b4c12f0 100644
--- a/sdk/lib/convert/converter.dart
+++ b/sdk/lib/convert/converter.dart
@@ -7,8 +7,8 @@
/**
* A [Converter] converts data from one representation into another.
*
- * *Converters are still experimental and are subject to change without notice.*
- *
+ * It is recommended that implementations of `Converter` extend this class,
+ * to inherit any further methods that may be added to the class.
*/
abstract class Converter<S, T> implements StreamTransformer {
const Converter();
diff --git a/sdk/lib/core/comparable.dart b/sdk/lib/core/comparable.dart
index 21161df..8896b25 100644
--- a/sdk/lib/core/comparable.dart
+++ b/sdk/lib/core/comparable.dart
@@ -35,10 +35,10 @@
int compareTo(T other);
/**
- * Compare one comparable to another.
+ * A [Comparator] that compares one comparable to another.
*
* This utility function is used as the default comparator
- * for the [List] sort function.
+ * for ordering collections, for example in the [List] sort function.
*/
static int compare(Comparable a, Comparable b) => a.compareTo(b);
}
diff --git a/sdk/lib/core/double.dart b/sdk/lib/core/double.dart
index 4aa161b..53964e4 100644
--- a/sdk/lib/core/double.dart
+++ b/sdk/lib/core/double.dart
@@ -60,6 +60,15 @@
double abs();
/**
+ * Returns the sign of the double's numerical value.
+ *
+ * Returns -1.0 if the value is less than zero,
+ * +1.0 if the value is greater than zero,
+ * and the value itself if it is -0.0, 0.0 or NaN.
+ */
+ double get sign;
+
+ /**
* Returns the integer closest to `this`.
*
* Rounds away from zero when there is no closest integer:
diff --git a/sdk/lib/core/int.dart b/sdk/lib/core/int.dart
index 6ca2718..23eda31 100644
--- a/sdk/lib/core/int.dart
+++ b/sdk/lib/core/int.dart
@@ -196,6 +196,14 @@
*/
int abs();
+ /**
+ * Returns the sign of this integer.
+ *
+ * Returns 0 for zero, -1 for values less than zero and
+ * +1 for values greater than zero.
+ */
+ int get sign;
+
/** Returns `this`. */
int round();
diff --git a/sdk/lib/core/list.dart b/sdk/lib/core/list.dart
index a33cd35..cf4da42 100644
--- a/sdk/lib/core/list.dart
+++ b/sdk/lib/core/list.dart
@@ -16,6 +16,14 @@
*
* * Growable list. Full implementation of the API defined in this class.
*
+ * The default growable list, as returned by `new List()` or `[]`, keeps
+ * an internal buffer, and grows that buffer when necessary. This guarantees
+ * that a sequence of [add] operations will each execute in amortized constant
+ * time. Setting the length directly may take time proportional to the new
+ * length, and may change the internal capacity so that a following add
+ * operation will need to immediately increase the buffer capacity.
+ * Other list implementations may have different performance behavior.
+ *
* The following code illustrates that some List implementations support
* only a subset of the API.
*
diff --git a/sdk/lib/core/map.dart b/sdk/lib/core/map.dart
index fb09d30..b289d9a 100644
--- a/sdk/lib/core/map.dart
+++ b/sdk/lib/core/map.dart
@@ -18,17 +18,26 @@
*/
abstract class Map<K, V> {
/**
- * Creates a Map instance with the default implementation.
+ * Creates a Map instance with the default implementation, [LinkedHashMap].
+ *
+ * A `LinkedHashMap` requires the keys to implement compatible
+ * `operator==` and `hashCode`, and it allows null as a key.
*/
factory Map() = LinkedHashMap<K, V>;
/**
- * Creates a Map instance that contains all key-value pairs of [other].
+ * Creates a [LinkedHashMap] instance that contains all key-value pairs of
+ * [other].
+ *
+ * A `LinkedHashMap` requires the keys to implement compatible
+ * `operator==` and `hashCode`, and it allows null as a key.
*/
factory Map.from(Map<K, V> other) = LinkedHashMap<K, V>.from;
/**
- * Creates an identity map with the default implementation.
+ * Creates an identity map with the default implementation, [LinkedHashMap].
+ *
+ * The returned map allows `null` as a key.
*/
factory Map.identity() = LinkedHashMap<K, V>.identity;
@@ -36,6 +45,10 @@
* Creates a Map instance in which the keys and values are computed from the
* [iterable].
*
+ * The created map is a [LinkedHashMap].
+ * A `LinkedHashMap` requires the keys to implement compatible
+ * `operator==` and `hashCode`, and it allows null as a key.
+ *
* For each element of the [iterable] this constructor computes a key-value
* pair, by applying [key] and [value] respectively.
*
@@ -70,6 +83,10 @@
/**
* Creates a Map instance associating the given [keys] to [values].
*
+ * The created map is a [LinkedHashMap].
+ * A `LinkedHashMap` requires the keys to implement compatible
+ * `operator==` and `hashCode`, and it allows null as a key.
+ *
* This constructor iterates over [keys] and [values] and maps each element of
* [keys] to the corresponding element of [values].
*
diff --git a/sdk/lib/core/num.dart b/sdk/lib/core/num.dart
index 7e4bf45..fc89d65 100644
--- a/sdk/lib/core/num.dart
+++ b/sdk/lib/core/num.dart
@@ -170,6 +170,27 @@
num abs();
/**
+ * Returns minus one, zero or plus one depending on the sign and
+ * numerical value of the number.
+ *
+ * Returns minus one if the number is less than zero,
+ * plus one if the number is greater than zero,
+ * and zero if the number is equal to zero.
+ *
+ * Returns NaN if the number is the double NaN value.
+ *
+ * Returns a number of the same type as this number.
+ * For doubles, `-0.0.sign == -0.0`.
+
+ * The result satisfies:
+ *
+ * n == n.sign * n.abs()
+ *
+ * for all numbers `n` (except NaN, because NaN isn't `==` to itself).
+ */
+ num get sign;
+
+ /**
* Returns the integer closest to `this`.
*
* Rounds away from zero when there is no closest integer:
diff --git a/sdk/lib/core/set.dart b/sdk/lib/core/set.dart
index 2dff5f2..059f320 100644
--- a/sdk/lib/core/set.dart
+++ b/sdk/lib/core/set.dart
@@ -13,11 +13,11 @@
* Set implementations may consider some elements indistinguishable. These
* elements are treated as being the same for any operation on the set.
*
- * The default `Set` implementation, [HashSet], considers objects
+ * The default `Set` implementation, [LinkedHashSet], considers objects
* indistinguishable if they are equal with regard to [Object.operator==].
*
- * Sets may be either ordered or unordered. [HashSet] is unordered and doesn't
- * guarantee anything about the order that elements are accessed in by
+ * Sets may be either ordered or unordered. [HashSet] is unordered and
+ * doesn't guarantee anything about the order that elements are accessed in by
* iteration. [LinkedHashSet] iterates in the insertion order of its elements.
*
* It is generally not allowed to modify the set (add or remove elements) while
@@ -47,7 +47,7 @@
/**
* Creates a [Set] that contains all elements of [other].
*
- * The created `Set` is a [HashSet]. As such, it considers elements that
+ * The created `Set` is a [LinkedHashSet]. As such, it considers elements that
* are equal (using `==`) to be undistinguishable, and requires them to
* have a compatible [Object.hashCode] implementation.
*/
@@ -95,6 +95,11 @@
/**
* Removes all elements of this set that are not elements in [elements].
+ *
+ * Checks for each element of [elements] whether there is an element in this
+ * set that is equal to it (according to `this.contains`), and if so, the
+ * equal element in this set is retained, and elements that are not equal
+ * to any element in `elements` are removed.
*/
void retainAll(Iterable<Object> elements);
diff --git a/sdk/lib/io/file.dart b/sdk/lib/io/file.dart
index 152fb6e..7369640 100644
--- a/sdk/lib/io/file.dart
+++ b/sdk/lib/io/file.dart
@@ -107,6 +107,26 @@
File renameSync(String newPath);
/**
+ * Copy this file. Returns a `Future<File>` that completes
+ * with a [File] instance for the copied file.
+ *
+ * If [newPath] identifies an existing file, that file is
+ * replaced. If [newPath] identifies an existing directory, the
+ * operation fails and the future completes with an exception.
+ */
+ Future<File> copy(String newPath);
+
+ /**
+ * Synchronously copy this file. Returns a [File]
+ * instance for the copied file.
+ *
+ * If [newPath] identifies an existing file, that file is
+ * replaced. If [newPath] identifies an existing directory the
+ * operation fails and an exception is thrown.
+ */
+ File copySync(String newPath);
+
+ /**
* Get the length of the file. Returns a [:Future<int>:] that
* completes with the length in bytes.
*/
diff --git a/sdk/lib/io/file_impl.dart b/sdk/lib/io/file_impl.dart
index cb1efe3..fcf2f5e 100644
--- a/sdk/lib/io/file_impl.dart
+++ b/sdk/lib/io/file_impl.dart
@@ -327,6 +327,24 @@
return new File(newPath);
}
+ Future<File> copy(String newPath) {
+ return _IOService.dispatch(_FILE_COPY, [path, newPath]).then((response) {
+ if (_isErrorResponse(response)) {
+ throw _exceptionFromResponse(
+ response, "Cannot copy file to '$newPath'", path);
+ }
+ return new File(newPath);
+ });
+ }
+
+ external static _copy(String oldPath, String newPath);
+
+ File copySync(String newPath) {
+ var result = _copy(path, newPath);
+ throwIfError(result, "Cannot copy file to '$newPath'", path);
+ return new File(newPath);
+ }
+
Future<RandomAccessFile> open({FileMode mode: FileMode.READ}) {
if (mode != FileMode.READ &&
mode != FileMode.WRITE &&
diff --git a/sdk/lib/io/io_service.dart b/sdk/lib/io/io_service.dart
index bf4b42b..4becb03 100644
--- a/sdk/lib/io/io_service.dart
+++ b/sdk/lib/io/io_service.dart
@@ -9,40 +9,41 @@
const int _FILE_CREATE = 1;
const int _FILE_DELETE = 2;
const int _FILE_RENAME = 3;
-const int _FILE_OPEN = 4;
-const int _FILE_RESOLVE_SYMBOLIC_LINKS = 5;
-const int _FILE_CLOSE = 6;
-const int _FILE_POSITION = 7;
-const int _FILE_SET_POSITION = 8;
-const int _FILE_TRUNCATE = 9;
-const int _FILE_LENGTH = 10;
-const int _FILE_LENGTH_FROM_PATH = 11;
-const int _FILE_LAST_MODIFIED = 12;
-const int _FILE_FLUSH = 13;
-const int _FILE_READ_BYTE = 14;
-const int _FILE_WRITE_BYTE = 15;
-const int _FILE_READ = 16;
-const int _FILE_READ_INTO = 17;
-const int _FILE_WRITE_FROM = 18;
-const int _FILE_CREATE_LINK = 19;
-const int _FILE_DELETE_LINK = 20;
-const int _FILE_RENAME_LINK = 21;
-const int _FILE_LINK_TARGET = 22;
-const int _FILE_TYPE = 23;
-const int _FILE_IDENTICAL = 24;
-const int _FILE_STAT = 25;
-const int _SOCKET_LOOKUP = 26;
-const int _SOCKET_LIST_INTERFACES = 27;
-const int _SOCKET_REVERSE_LOOKUP = 28;
-const int _DIRECTORY_CREATE = 29;
-const int _DIRECTORY_DELETE = 30;
-const int _DIRECTORY_EXISTS = 31;
-const int _DIRECTORY_CREATE_TEMP = 32;
-const int _DIRECTORY_LIST_START = 33;
-const int _DIRECTORY_LIST_NEXT = 34;
-const int _DIRECTORY_LIST_STOP = 35;
-const int _DIRECTORY_RENAME = 36;
-const int _SSL_PROCESS_FILTER = 37;
+const int _FILE_COPY = 4;
+const int _FILE_OPEN = 5;
+const int _FILE_RESOLVE_SYMBOLIC_LINKS = 6;
+const int _FILE_CLOSE = 7;
+const int _FILE_POSITION = 8;
+const int _FILE_SET_POSITION = 9;
+const int _FILE_TRUNCATE = 10;
+const int _FILE_LENGTH = 11;
+const int _FILE_LENGTH_FROM_PATH = 12;
+const int _FILE_LAST_MODIFIED = 13;
+const int _FILE_FLUSH = 14;
+const int _FILE_READ_BYTE = 15;
+const int _FILE_WRITE_BYTE = 16;
+const int _FILE_READ = 17;
+const int _FILE_READ_INTO = 18;
+const int _FILE_WRITE_FROM = 19;
+const int _FILE_CREATE_LINK = 20;
+const int _FILE_DELETE_LINK = 21;
+const int _FILE_RENAME_LINK = 22;
+const int _FILE_LINK_TARGET = 23;
+const int _FILE_TYPE = 24;
+const int _FILE_IDENTICAL = 25;
+const int _FILE_STAT = 26;
+const int _SOCKET_LOOKUP = 27;
+const int _SOCKET_LIST_INTERFACES = 28;
+const int _SOCKET_REVERSE_LOOKUP = 29;
+const int _DIRECTORY_CREATE = 30;
+const int _DIRECTORY_DELETE = 31;
+const int _DIRECTORY_EXISTS = 32;
+const int _DIRECTORY_CREATE_TEMP = 33;
+const int _DIRECTORY_LIST_START = 34;
+const int _DIRECTORY_LIST_NEXT = 35;
+const int _DIRECTORY_LIST_STOP = 36;
+const int _DIRECTORY_RENAME = 37;
+const int _SSL_PROCESS_FILTER = 38;
class _IOService {
external static Future dispatch(int request, List data);
diff --git a/sdk/lib/io/process.dart b/sdk/lib/io/process.dart
index 3c0f0fe..3b340c3 100644
--- a/sdk/lib/io/process.dart
+++ b/sdk/lib/io/process.dart
@@ -11,6 +11,7 @@
external static void _setExitCode(int status);
external static void _sleep(int millis);
external static int _pid(Process process);
+ external static Stream<ProcessSignal> _watchSignal(ProcessSignal signal);
}
/**
@@ -310,37 +311,60 @@
* to a child process, see [:Process.kill:].
*/
class ProcessSignal {
- static const ProcessSignal SIGHUP = const ProcessSignal._signal(1);
- static const ProcessSignal SIGINT = const ProcessSignal._signal(2);
- static const ProcessSignal SIGQUIT = const ProcessSignal._signal(3);
- static const ProcessSignal SIGILL = const ProcessSignal._signal(4);
- static const ProcessSignal SIGTRAP = const ProcessSignal._signal(5);
- static const ProcessSignal SIGABRT = const ProcessSignal._signal(6);
- static const ProcessSignal SIGBUS = const ProcessSignal._signal(7);
- static const ProcessSignal SIGFPE = const ProcessSignal._signal(8);
- static const ProcessSignal SIGKILL = const ProcessSignal._signal(9);
- static const ProcessSignal SIGUSR1 = const ProcessSignal._signal(10);
- static const ProcessSignal SIGSEGV = const ProcessSignal._signal(11);
- static const ProcessSignal SIGUSR2 = const ProcessSignal._signal(12);
- static const ProcessSignal SIGPIPE = const ProcessSignal._signal(13);
- static const ProcessSignal SIGALRM = const ProcessSignal._signal(14);
- static const ProcessSignal SIGTERM = const ProcessSignal._signal(15);
- static const ProcessSignal SIGCHLD = const ProcessSignal._signal(17);
- static const ProcessSignal SIGCONT = const ProcessSignal._signal(18);
- static const ProcessSignal SIGSTOP = const ProcessSignal._signal(19);
- static const ProcessSignal SIGTSTP = const ProcessSignal._signal(20);
- static const ProcessSignal SIGTTIN = const ProcessSignal._signal(21);
- static const ProcessSignal SIGTTOU = const ProcessSignal._signal(22);
- static const ProcessSignal SIGURG = const ProcessSignal._signal(23);
- static const ProcessSignal SIGXCPU = const ProcessSignal._signal(24);
- static const ProcessSignal SIGXFSZ = const ProcessSignal._signal(25);
- static const ProcessSignal SIGVTALRM = const ProcessSignal._signal(26);
- static const ProcessSignal SIGPROF = const ProcessSignal._signal(27);
- static const ProcessSignal SIGPOLL = const ProcessSignal._signal(29);
- static const ProcessSignal SIGSYS = const ProcessSignal._signal(31);
+ static const ProcessSignal SIGHUP = const ProcessSignal._(1, "SIGHUP");
+ static const ProcessSignal SIGINT = const ProcessSignal._(2, "SIGINT");
+ static const ProcessSignal SIGQUIT = const ProcessSignal._(3, "SIGQUIT");
+ static const ProcessSignal SIGILL = const ProcessSignal._(4, "SIGILL");
+ static const ProcessSignal SIGTRAP = const ProcessSignal._(5, "SIGTRAP");
+ static const ProcessSignal SIGABRT = const ProcessSignal._(6, "SIGABRT");
+ static const ProcessSignal SIGBUS = const ProcessSignal._(7, "SIGBUS");
+ static const ProcessSignal SIGFPE = const ProcessSignal._(8, "SIGFPE");
+ static const ProcessSignal SIGKILL = const ProcessSignal._(9, "SIGKILL");
+ static const ProcessSignal SIGUSR1 = const ProcessSignal._(10, "SIGUSR1");
+ static const ProcessSignal SIGSEGV = const ProcessSignal._(11, "SIGSEGV");
+ static const ProcessSignal SIGUSR2 = const ProcessSignal._(12, "SIGUSR2");
+ static const ProcessSignal SIGPIPE = const ProcessSignal._(13, "SIGPIPE");
+ static const ProcessSignal SIGALRM = const ProcessSignal._(14, "SIGALRM");
+ static const ProcessSignal SIGTERM = const ProcessSignal._(15, "SIGTERM");
+ static const ProcessSignal SIGCHLD = const ProcessSignal._(17, "SIGCHLD");
+ static const ProcessSignal SIGCONT = const ProcessSignal._(18, "SIGCONT");
+ static const ProcessSignal SIGSTOP = const ProcessSignal._(19, "SIGSTOP");
+ static const ProcessSignal SIGTSTP = const ProcessSignal._(20, "SIGTSTP");
+ static const ProcessSignal SIGTTIN = const ProcessSignal._(21, "SIGTTIN");
+ static const ProcessSignal SIGTTOU = const ProcessSignal._(22, "SIGTTOU");
+ static const ProcessSignal SIGURG = const ProcessSignal._(23, "SIGURG");
+ static const ProcessSignal SIGXCPU = const ProcessSignal._(24, "SIGXCPU");
+ static const ProcessSignal SIGXFSZ = const ProcessSignal._(25, "SIGXFSZ");
+ static const ProcessSignal SIGVTALRM = const ProcessSignal._(26, "SIGVTALRM");
+ static const ProcessSignal SIGPROF = const ProcessSignal._(27, "SIGPROF");
+ static const ProcessSignal SIGWINCH = const ProcessSignal._(28, "SIGWINCH");
+ static const ProcessSignal SIGPOLL = const ProcessSignal._(29, "SIGPOLL");
+ static const ProcessSignal SIGSYS = const ProcessSignal._(31, "SIGSYS");
- const ProcessSignal._signal(int this._signalNumber);
final int _signalNumber;
+ final String _name;
+
+ const ProcessSignal._(this._signalNumber, this._name);
+
+ String toString() => _name;
+
+ Stream<ProcessSignal> watch() => _ProcessUtils._watchSignal(this);
+}
+
+
+class SignalException implements IOException {
+ final String message;
+ final osError;
+
+ const SignalException(String this.message, [this.osError = null]);
+
+ String toString() {
+ var msg = "";
+ if (osError != null) {
+ msg = ", osError: $osError";
+ }
+ return "SignalException: $message$msg";
+ }
}
diff --git a/sdk/lib/io/secure_socket.dart b/sdk/lib/io/secure_socket.dart
index 7d8c685..9bfa032 100644
--- a/sdk/lib/io/secure_socket.dart
+++ b/sdk/lib/io/secure_socket.dart
@@ -540,7 +540,7 @@
_socketSubscription.onDone(_doneHandler);
}
_secureFilter.connect(address.host,
- (address as dynamic)._sockaddr_storage,
+ (address as dynamic)._in_addr,
port,
is_server,
certificateName,
diff --git a/sdk/lib/io/stdio.dart b/sdk/lib/io/stdio.dart
index ab2f03a..5626d84 100644
--- a/sdk/lib/io/stdio.dart
+++ b/sdk/lib/io/stdio.dart
@@ -159,6 +159,50 @@
}
+/**
+ * [Stdout] exposes methods to query the terminal for properties.
+ *
+ * Use [hasTerminal] to test if there is a terminal associated to stdout.
+ */
+class Stdout extends _StdSink {
+ // TODO(15721): Should implement IOSink (for documentation purpose).
+ Stdout._(IOSink sink) : super(sink);
+
+ /**
+ * Returns true if there is a terminal attached to stdout.
+ */
+ external bool get hasTerminal;
+
+ /**
+ * Get the number of columns of the terminal.
+ *
+ * If no terminal is attached to stdout, a [StdoutException] is thrown. See
+ * [hasTerminal] for more info.
+ */
+ external int get terminalColumns;
+
+ /**
+ * Get the number of lines of the terminal.
+ *
+ * If no terminal is attached to stdout, a [StdoutException] is thrown. See
+ * [hasTerminal] for more info.
+ */
+ external int get terminalLines;
+}
+
+
+class StdoutException implements IOException {
+ final String message;
+ final OSError osError;
+
+ const StdoutException(this.message, [this.osError]);
+
+ String toString() {
+ return "StdoutException: $message${osError == null ? "" : ", $osError"}";
+ }
+}
+
+
class _StdSink implements IOSink {
final IOSink _sink;
@@ -194,7 +238,7 @@
Stdin _stdin;
-IOSink _stdout;
+Stdout _stdout;
IOSink _stderr;
@@ -208,7 +252,7 @@
/// The standard output stream of data written by this program.
-IOSink get stdout {
+Stdout get stdout {
if (_stdout == null) {
_stdout = _StdIOUtils._getStdioOutputStream(1);
}
@@ -257,7 +301,7 @@
class _StdIOUtils {
- external static IOSink _getStdioOutputStream(int fd);
+ external static _getStdioOutputStream(int fd);
external static Stdin _getStdioInputStream();
external static int _socketType(nativeSocket);
}
diff --git a/sdk/lib/io/timer_impl.dart b/sdk/lib/io/timer_impl.dart
index 883d09e..5396a6a 100644
--- a/sdk/lib/io/timer_impl.dart
+++ b/sdk/lib/io/timer_impl.dart
@@ -4,19 +4,137 @@
part of dart.io;
-class _Timer extends LinkedListEntry<_Timer> implements Timer {
+// Timer heap implemented as a array-based binary heap[0].
+// This allows for O(1) `first`, O(log(n)) `remove`/`removeFirst` and O(log(n))
+// `add`.
+//
+// To ensure the timers are ordered by insertion time, the _Timer class has a
+// `_id` field set when added to the heap.
+//
+// [0] http://en.wikipedia.org/wiki/Binary_heap
+class _TimerHeap {
+ List<_Timer> _list;
+ int _used = 0;
+
+ _TimerHeap([int initSize = 7])
+ : _list = new List<_Timer>(initSize);
+
+ bool get isEmpty => _used == 0;
+ bool get isNotEmpty => _used > 0;
+
+ _Timer get first => _list[0];
+
+ bool isFirst(_Timer timer) => timer._indexOrNext == 0;
+
+ void add(_Timer timer) {
+ if (_used == _list.length) {
+ _resize();
+ }
+ timer._indexOrNext = _used++;
+ _list[timer._indexOrNext] = timer;
+ _bubbleUp(timer);
+ }
+
+ _Timer removeFirst() {
+ var f = first;
+ remove(f);
+ return f;
+ }
+
+ void remove(_Timer timer) {
+ _used--;
+ timer._id = -1;
+ if (isEmpty) {
+ _list[0] = null;
+ timer._indexOrNext = null;
+ return;
+ }
+ var last = _list[_used];
+ if (!identical(last, timer)) {
+ last._indexOrNext = timer._indexOrNext;
+ _list[last._indexOrNext] = last;
+ if (last._compareTo(timer) < 0) {
+ _bubbleUp(last);
+ } else {
+ _bubbleDown(last);
+ }
+ }
+ _list[_used] = null;
+ timer._indexOrNext = null;
+ }
+
+ void _resize() {
+ var newList = new List(_list.length * 2 + 1);
+ newList.setRange(0, _used, _list);
+ _list = newList;
+ }
+
+ void _bubbleUp(_Timer timer) {
+ while (!isFirst(timer)) {
+ Timer parent = _parent(timer);
+ if (timer._compareTo(parent) < 0) {
+ _swap(timer, parent);
+ } else {
+ break;
+ }
+ }
+ }
+
+ void _bubbleDown(_Timer timer) {
+ while (true) {
+ int leftIndex = _leftChildIndex(timer._indexOrNext);
+ int rightIndex = _rightChildIndex(timer._indexOrNext);
+ _Timer newest = timer;
+ if (leftIndex < _used && _list[leftIndex]._compareTo(newest) < 0) {
+ newest = _list[leftIndex];
+ }
+ if (rightIndex < _used && _list[rightIndex]._compareTo(newest) < 0) {
+ newest = _list[rightIndex];
+ }
+ if (identical(newest, timer)) {
+ // We are where we should be, break.
+ break;
+ }
+ _swap(newest, timer);
+ }
+ }
+
+ void _swap(_Timer first, _Timer second) {
+ int tmp = first._indexOrNext;
+ first._indexOrNext = second._indexOrNext;
+ second._indexOrNext = tmp;
+ _list[first._indexOrNext] = first;
+ _list[second._indexOrNext] = second;
+ }
+
+ Timer _parent(_Timer timer) => _list[_parentIndex(timer._indexOrNext)];
+ Timer _leftChild(_Timer timer) => _list[_leftChildIndex(timer._indexOrNext)];
+ Timer _rightChild(_Timer timer) =>
+ _list[_rightChildIndex(timer._indexOrNext)];
+
+ static int _parentIndex(int index) => (index - 1) ~/ 2;
+ static int _leftChildIndex(int index) => 2 * index + 1;
+ static int _rightChildIndex(int index) => 2 * index + 2;
+}
+
+class _Timer implements Timer {
// Disables the timer.
static const int _NO_TIMER = -1;
// Timers are ordered by wakeup time.
- static LinkedList<_Timer> _timers = new LinkedList<_Timer>();
+ static _TimerHeap _heap = new _TimerHeap();
+ static _Timer _firstZeroTimer;
+ static _Timer _lastZeroTimer;
+ static int _idCount = 0;
static RawReceivePort _receivePort;
- static bool _handling_callbacks = false;
+ static bool _handlingCallbacks = false;
Function _callback;
int _milliSeconds;
int _wakeupTime = 0;
+ var _indexOrNext;
+ int _id = -1;
static Timer _createTimer(void callback(Timer timer),
int milliSeconds,
@@ -32,10 +150,9 @@
new DateTime.now().millisecondsSinceEpoch + 1 + milliSeconds;
}
timer._milliSeconds = repeating ? milliSeconds : -1;
- timer._addTimerToList();
- if (identical(timer, _timers.first)) {
+ if (timer._addTimerToHeap()) {
// The new timer is the first in queue. Update event handler.
- timer._notifyEventHandler();
+ _notifyEventHandler();
}
return timer;
}
@@ -50,10 +167,16 @@
_Timer._internal() {}
+ bool get _isInHeap => _id >= 0;
+
void _clear() {
_callback = null;
- _milliSeconds = 0;
- _wakeupTime = 0;
+ }
+
+ int _compareTo(_Timer other) {
+ int c = _wakeupTime - other._wakeupTime;
+ if (c != 0) return c;
+ return _id - other._id;
}
bool get _repeating => _milliSeconds >= 0;
@@ -64,12 +187,11 @@
// the given timer is the earliest timer the native timer is reset.
void cancel() {
_clear();
- // Return if already canceled.
- if (list == null) return;
- assert(!_timers.isEmpty);
- _Timer first = _timers.first;
- unlink();
- if (identical(first, this)) {
+ if (!_isInHeap) return;
+ assert(_wakeupTime != 0);
+ bool update = _firstZeroTimer == null && _heap.isFirst(this);
+ _heap.remove(this);
+ if (update) {
_notifyEventHandler();
}
}
@@ -81,34 +203,32 @@
// Adds a timer to the timer list. Timers with the same wakeup time are
// enqueued in order and notified in FIFO order.
- void _addTimerToList() {
- _Timer entry = _timers.isEmpty ? null : _timers.first;
- // If timer is last, add to end.
- if (entry == null || _timers.last._wakeupTime <= _wakeupTime) {
- _timers.add(this);
- return;
- }
- // Otherwise scan through and find the right position.
- while (entry != null) {
- if (_wakeupTime < entry._wakeupTime) {
- entry.insertBefore(this);
- return;
+ bool _addTimerToHeap() {
+ if (_wakeupTime == 0) {
+ if (_firstZeroTimer == null) {
+ _lastZeroTimer = _firstZeroTimer = this;
+ return true;
+ } else {
+ _lastZeroTimer = _lastZeroTimer._indexOrNext = this;
+ return false;
}
- entry = entry.next;
+ } else {
+ _id = _idCount++;
+ _heap.add(this);
+ return _firstZeroTimer == null && _heap.isFirst(this);
}
- _timers.add(this);
}
- void _notifyEventHandler() {
- if (_handling_callbacks) {
+ static void _notifyEventHandler() {
+ if (_handlingCallbacks) {
// While we are already handling callbacks we will not notify the event
// handler. _handleTimeout will call _notifyEventHandler once all pending
// timers are processed.
return;
}
- if (_timers.isEmpty) {
+ if (_firstZeroTimer == null && _heap.isEmpty) {
// No pending timers: Close the receive port and let the event handler
// know.
if (_receivePort != null) {
@@ -123,65 +243,67 @@
}
_EventHandler._sendData(null,
_receivePort,
- _timers.first._wakeupTime);
+ _firstZeroTimer != null ?
+ 0 : _heap.first._wakeupTime);
}
}
+ static void _handleTimeout(_) {
+ int currentTime = new DateTime.now().millisecondsSinceEpoch;
+ // Collect all pending timers.
+ var timer = _firstZeroTimer;
+ var nextTimer = _lastZeroTimer;
+ _firstZeroTimer = _lastZeroTimer = null;
+ while (_heap.isNotEmpty && _heap.first._wakeupTime <= currentTime) {
+ var next = _heap.removeFirst();
+ if (timer == null) {
+ nextTimer = timer = next;
+ } else {
+ nextTimer = nextTimer._indexOrNext = next;
+ }
+ }
+
+ // Trigger all of the pending timers. New timers added as part of the
+ // callbacks will be enqueued now and notified in the next spin at the
+ // earliest.
+ _handlingCallbacks = true;
+ try {
+ while (timer != null) {
+ var next = timer._indexOrNext;
+ timer._indexOrNext = null;
+ // One of the timers in the pending_timers list can cancel
+ // one of the later timers which will set the callback to
+ // null.
+ if (timer._callback != null) {
+ var callback = timer._callback;
+ if (!timer._repeating) {
+ // Mark timer as inactive.
+ timer._callback = null;
+ }
+ callback(timer);
+ // Re-insert repeating timer if not canceled.
+ if (timer._repeating && timer._callback != null) {
+ timer._advanceWakeupTime();
+ timer._addTimerToHeap();
+ }
+ }
+ timer = next;
+ }
+ } finally {
+ _handlingCallbacks = false;
+ _notifyEventHandler();
+ }
+ }
// Creates a receive port and registers the timer handler on that
// receive port.
- void _createTimerHandler() {
-
- void _handleTimeout() {
- int currentTime = new DateTime.now().millisecondsSinceEpoch;
-
- // Collect all pending timers.
- var pending_timers = new List();
- while (!_timers.isEmpty) {
- _Timer entry = _timers.first;
- if (entry._wakeupTime <= currentTime) {
- entry.unlink();
- pending_timers.add(entry);
- } else {
- break;
- }
- }
-
- // Trigger all of the pending timers. New timers added as part of the
- // callbacks will be enqueued now and notified in the next spin at the
- // earliest.
- _handling_callbacks = true;
- try {
- for (var timer in pending_timers) {
- // One of the timers in the pending_timers list can cancel
- // one of the later timers which will set the callback to
- // null.
- if (timer._callback != null) {
- var callback = timer._callback;
- if (!timer._repeating) {
- //Mark timer as inactive.
- timer._callback = null;
- }
- callback(timer);
- // Re-insert repeating timer if not canceled.
- if (timer._repeating && timer._callback != null) {
- timer._advanceWakeupTime();
- timer._addTimerToList();
- }
- }
- }
- } finally {
- _handling_callbacks = false;
- _notifyEventHandler();
- }
- }
-
+ static void _createTimerHandler() {
if(_receivePort == null) {
- _receivePort = new RawReceivePort((_) { _handleTimeout(); });
+ _receivePort = new RawReceivePort(_handleTimeout);
}
}
- void _shutdownTimerHandler() {
+ static void _shutdownTimerHandler() {
_receivePort.close();
_receivePort = null;
}
diff --git a/tests/co19/co19-analyzer.status b/tests/co19/co19-analyzer.status
index 28c3b88..7c23629 100644
--- a/tests/co19/co19-analyzer.status
+++ b/tests/co19/co19-analyzer.status
@@ -129,7 +129,6 @@
Language/07_Classes/10_Superinterfaces_A07_t05: StaticWarning # co19-roll r667: Please triage this failure
LibTest/convert/JsonEncoder/JsonEncoder_A01_t01: StaticWarning # co19-roll r667: Please triage this failure
-LibTest/async/Zone/operator_subscript_A01_t01: StaticWarning # co19-roll r672: Please triage this failure
# co19 issue 656
LibTest/typed_data/Float32x4/equal_A01_t01: Skip # co19 issue 656
diff --git a/tests/co19/co19-co19.status b/tests/co19/co19-co19.status
index bd7e326..c126519 100644
--- a/tests/co19/co19-co19.status
+++ b/tests/co19/co19-co19.status
@@ -40,8 +40,6 @@
LibTest/collection/ListBase/ListBase_class_A01_t01: Skip, OK # co19 issue 661
LibTest/collection/ListMixin/ListMixin_class_A01_t01: Skip, OK # co19 issue 661
-LibTest/isolate/Isolate/spawnUri_A02_t04: Fail # co19-roll r672: Please triage this failure
-
[ $runtime == vm || $runtime == dartium || $compiler == dart2js ]
LibTest/math/acos_A01_t01: PASS, FAIL, OK # co19 issue 44
LibTest/math/asin_A01_t01: PASS, FAIL, OK # co19 issue 44
diff --git a/tests/co19/co19-dart2dart.status b/tests/co19/co19-dart2dart.status
index c3e7ab4..f42fb63 100644
--- a/tests/co19/co19-dart2dart.status
+++ b/tests/co19/co19-dart2dart.status
@@ -160,6 +160,9 @@
LibTest/core/Function/Function_class_A01_t01: RuntimeError # co19-roll r623: Please triage this failure
Language/13_Statements/04_Local_Function_Declaration_A04_t03: MissingCompileTimeError # co19-roll r667: Please triage this failure
+LibTest/isolate/Isolate/spawn_A02_t02: RuntimeError # Dart issue 15617
+LibTest/isolate/Isolate/spawnUri_A02_t01: RuntimeError # Dart issue 15617
+
[ $compiler == dart2dart && $minified ]
Language/12_Expressions/14_Function_Invocation/4_Function_Expression_Invocation_A01_t02: fail # co19-roll r559: Please triage this failure
Language/12_Expressions/17_Getter_Invocation_A02_t01: fail # co19-roll r559: Please triage this failure
diff --git a/tests/co19/co19-dart2js.status b/tests/co19/co19-dart2js.status
index ec96ae9..92d3ba4 100644
--- a/tests/co19/co19-dart2js.status
+++ b/tests/co19/co19-dart2js.status
@@ -62,6 +62,9 @@
LibTest/typed_data/Float32x4/lessThan_A01_t01: Skip # co19 issue 656
LibTest/typed_data/Float32x4/lessThanOrEqual_A01_t01: Skip # co19 issue 656
+LibTest/isolate/Isolate/spawnUri_A02_t01: RuntimeError # Dart issue 15617
+LibTest/isolate/Isolate/spawn_A02_t02: RuntimeError # Dart issue 15617
+
[ $compiler == dart2js && $runtime != ie9 ]
LibTest/typed_data/ByteData/ByteData_A02_t01: fail # co19-roll r576: Please triage this failure
@@ -648,8 +651,6 @@
LibTest/isolate/Isolate/spawnUri_A01_t03: Fail # co19-roll r672: Please triage this failure
LibTest/isolate/Isolate/spawnUri_A01_t04: Fail # co19-roll r672: Please triage this failure
LibTest/isolate/Isolate/spawnUri_A01_t05: Fail # co19-roll r672: Please triage this failure
-LibTest/isolate/Isolate/spawnUri_A02_t02: Fail # co19-roll r672: Please triage this failure
-LibTest/isolate/Isolate/spawnUri_A02_t03: Fail # co19-roll r672: Please triage this failure
[ $compiler == dart2js ]
LibTest/core/List/List_class_A01_t01: RuntimeError # co19-roll r623: Please triage this failure
diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status
index 16f1123..9f1ca00 100644
--- a/tests/co19/co19-runtime.status
+++ b/tests/co19/co19-runtime.status
@@ -33,8 +33,10 @@
LibTest/isolate/IsolateStream/contains_A02_t01: fail # co19-roll r546: Please triage this failure
LibTest/isolate/ReceivePort/receive_A01_t02: Fail # VM triage, check spec.
+LibTest/isolate/Isolate/spawnUri_A02_t01: RuntimeError # Dart issue 15617
LibTest/isolate/Isolate/spawnUri_A02_t02: Timeout # co19-roll r672: Please triage this failure
LibTest/isolate/Isolate/spawnUri_A02_t03: Timeout # co19-roll r672: Please triage this failure
+LibTest/isolate/Isolate/spawn_A02_t02: RuntimeError # Dart issue 15617
LibTest/core/Invocation/positionalArguments_A01_t01: RuntimeError # co19-roll r607: Please triage this failure
LibTest/core/RegExp/Pattern_semantics/splitQueryString_A02_t01: RuntimeError # co19-roll r607: Please triage this failure
@@ -77,6 +79,9 @@
[ $compiler == none && $runtime == vm && ($arch == simarm || $arch == simmips) ]
LibTest/core/Uri/Uri_A06_t03: Pass, Timeout # co19-roll r576: Please triage this failure
+[ $compiler == none && $runtime == vm && $arch == simarm ]
+LibTest/typed_data/Float32x4/sqrt_A01_t01: Pass, Fail # co19 issue 666.
+
[ $compiler == none && $checked && ($runtime == vm || $runtime == dartium) ]
Language/15_Types/1_Static_Types_A03_t01: RuntimeError # co19-roll r667: Please triage this failure
diff --git a/tests/compiler/dart2js/literal_map_test.dart b/tests/compiler/dart2js/literal_map_test.dart
index 0e30d4e..1b51336 100644
--- a/tests/compiler/dart2js/literal_map_test.dart
+++ b/tests/compiler/dart2js/literal_map_test.dart
@@ -19,5 +19,7 @@
Expect.isFalse(generated.contains('bailout'));
Expect.isFalse(generated.contains('interceptor'));
// Make sure we don't go through an interceptor.
- Expect.isTrue(generated.contains('a.\$indexSet'));
+ Expect.isTrue(
+ generated.contains(r'a.$indexSet(a') ||
+ generated.contains(r'.$indexSet(0'));
}
diff --git a/tests/compiler/dart2js/mirrors_used_test.dart b/tests/compiler/dart2js/mirrors_used_test.dart
index 50ca509..9415463 100644
--- a/tests/compiler/dart2js/mirrors_used_test.dart
+++ b/tests/compiler/dart2js/mirrors_used_test.dart
@@ -58,7 +58,7 @@
// 2. Some code was refactored, and there are more methods.
// Either situation could be problematic, but in situation 2, it is often
// acceptable to increase [expectedMethodCount] a little.
- int expectedMethodCount = 351;
+ int expectedMethodCount = 352;
Expect.isTrue(
generatedCode.length <= expectedMethodCount,
'Too many compiled methods: '
diff --git a/tests/compiler/dart2js/mock_compiler.dart b/tests/compiler/dart2js/mock_compiler.dart
index 1214f30..5a9cb74 100644
--- a/tests/compiler/dart2js/mock_compiler.dart
+++ b/tests/compiler/dart2js/mock_compiler.dart
@@ -151,7 +151,12 @@
operator ==(other) => true;
get hashCode => throw "JSNumber.hashCode not implemented.";
- _tdivFast(other) => 42;
+ // We force side effects on _tdivFast to mimic the shortcomings of
+ // the effect analysis: because the `_tdivFast` implementation of
+ // the core library has calls that may not already be analyzed,
+ // the analysis will conclude that `_tdivFast` may have side
+ // effects.
+ _tdivFast(other) => new List()..length = 42;
_shlPositive(other) => 42;
_shrBothPositive(other) => 42;
_shrReceiverPositive(other) => 42;
@@ -207,6 +212,7 @@
class Type {}
class Function {}
class List<E> {
+ var length;
List([length]);
List.filled(length, element);
}
diff --git a/tests/compiler/dart2js/side_effect_tdiv_regression_test.dart b/tests/compiler/dart2js/side_effect_tdiv_regression_test.dart
new file mode 100644
index 0000000..1cede18
--- /dev/null
+++ b/tests/compiler/dart2js/side_effect_tdiv_regression_test.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:expect/expect.dart';
+import "package:async_helper/async_helper.dart";
+
+import 'compiler_helper.dart';
+import 'parser_helper.dart';
+
+const String TEST = r'''
+class A {
+ var field = 42;
+}
+main() {
+ var a = new A();
+ var b = [42, -1];
+ // Force a setter on [field].
+ if (false) a.field = 12;
+ var c = a.field;
+ print(b[0] ~/ b[1]);
+ return c + a.field;
+}
+''';
+
+void main() {
+ asyncTest(() => compileAll(TEST).then((generated) {
+ Expect.isTrue(generated.contains('return c + c;'));
+ }));
+}
diff --git a/tests/compiler/dart2js/simple_inferrer_test.dart b/tests/compiler/dart2js/simple_inferrer_test.dart
index 81007d0..b2dd57f 100644
--- a/tests/compiler/dart2js/simple_inferrer_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_test.dart
@@ -538,6 +538,10 @@
return a;
}
+testReturnNotEquals() {
+ return new A() != 54;
+}
+
testReturnInvokeDynamicGetter() => new A().myFactory();
var topLevelConstList = const [42];
@@ -695,6 +699,7 @@
testReturnNull4();
testReturnNull5();
testReturnNull6();
+ testReturnNotEquals();
}
""";
@@ -837,5 +842,6 @@
checkReturn('testReturnNull4', typesTask.nullType);
checkReturn('testReturnNull5', typesTask.nullType);
checkReturn('testReturnNull6', typesTask.dynamicType);
+ checkReturn('testReturnNotEquals', typesTask.boolType);
}));
}
diff --git a/tests/compiler/dart2js_extra/dart2js_extra.status b/tests/compiler/dart2js_extra/dart2js_extra.status
index c694332..f9eed72 100644
--- a/tests/compiler/dart2js_extra/dart2js_extra.status
+++ b/tests/compiler/dart2js_extra/dart2js_extra.status
@@ -14,6 +14,12 @@
variable_type_test/03: Fail, OK
variable_type_test/01: Fail, OK
+[ $compiler == dart2js && $host_checked && $checked == false ]
+# Test that @IrRepresentation yields compile-time errors in host-checked mode.
+# The condition "$checked == false" is to be removed once we build IR in
+# target-checked mode.
+ir_representation_test: CompileTimeError, OK
+
[ $compiler == dart2js && $mode == debug ]
operator_test: Skip
string_interpolation_test: Skip
diff --git a/tests/compiler/dart2js_extra/ir_representation_test.dart b/tests/compiler/dart2js_extra/ir_representation_test.dart
new file mode 100644
index 0000000..4b037c4
--- /dev/null
+++ b/tests/compiler/dart2js_extra/ir_representation_test.dart
@@ -0,0 +1,62 @@
+// 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.
+
+// The multitest framework does not support import paths that contain '..',
+// therefore it's not used in this file.
+import '../dart2js_native/compiler_test_internals.dart';
+
+/**
+ * This test verifies that the @IrRepresentation annotation works as expected.
+ * It might fail when extending the IR to express more of Dart.
+ */
+
+// closure
+@IrRepresentation(true)
+test1() {
+ var f = () => 42;
+ return 1;
+}
+
+// parameter
+@IrRepresentation(true)
+test2(x) {
+ return x;
+}
+
+// dynamic invocation, construction
+@IrRepresentation(true)
+test3() {
+ new Object().hashCode;
+}
+
+// exceptions
+@IrRepresentation(true)
+test4() {
+ try {
+ throw "possum";
+ } catch (e) {
+ return e;
+ }
+}
+
+// control flow, loops
+@IrRepresentation(true)
+test5(x) {
+ while (x < 100) {
+ x += x;
+ }
+ if (x % 2 == 0) {
+ return 1;
+ } else {
+ return 2;
+ }
+}
+
+main() {
+ print(test1());
+ print(test2(1));
+ print(test3());
+ print(test4());
+ print(test5(2));
+}
diff --git a/tests/compiler/dart2js_extra/ssa_inlining_test.dart b/tests/compiler/dart2js_extra/ssa_inlining_test.dart
new file mode 100644
index 0000000..b043c77
--- /dev/null
+++ b/tests/compiler/dart2js_extra/ssa_inlining_test.dart
@@ -0,0 +1,118 @@
+// 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 '../dart2js_native/compiler_test_internals.dart';
+import 'package:expect/expect.dart';
+
+// The function ast01 is built by an SsaFromAstBuilder.
+// Ir functions are inlined by an SsaFromIrInliner.
+
+@NoInline()
+@IrRepresentation(false)
+ast01() {
+ checkAst01(JS('', 'arguments.callee'));
+ print(ir01());
+ print(ir02());
+ return ast02(11);
+}
+
+@IrRepresentation(true)
+ir01() => ir04();
+
+@IrRepresentation(true)
+ir02() => ast06(10, 20);
+
+@IrRepresentation(false)
+ast06(a,b) {
+ JS('', 'String("in ast06")');
+ return 3*a + b;
+}
+
+@IrRepresentation(true)
+ir04() => ir05();
+
+@IrRepresentation(true)
+ir05() => ast07(1, 22);
+
+@IrRepresentation(false)
+ast07(i, j) {
+ var x = 0;
+ return ast08(i,j) ? i : j;
+}
+
+@IrRepresentation(false)
+ast08(x,y) {
+ JS('', 'String("in ast08")');
+ return x - y < 0;
+}
+
+@IrRepresentation(false)
+ast02(x) {
+ print(x);
+ ir06();
+ print(ir07());
+}
+
+@IrRepresentation(true)
+ir06() => ast04(1,2,3);
+
+@IrRepresentation(false)
+ast04(a, b, c) {
+ print(a + b - c);
+ JS('', 'String("in ast04")');
+}
+
+@IrRepresentation(true)
+ir07() => ir03();
+
+@IrRepresentation(true)
+ir03() => ast05(1,3);
+
+@IrRepresentation(false)
+ast05(a, b) {
+ JS('', 'String("in ast05")');
+ return (a+b)/2;
+}
+
+// The function ir08 is built by an SsaFromIrBuilder.
+// Ast functions are inlined by an SsaFromAstInliner.
+
+@NoInline()
+@IrRepresentation(true)
+ir08() => ir09();
+
+ir09() => ast09();
+
+ast09() {
+ checkIr08(JS('', 'arguments.callee'));
+ JS('', 'String("in ast09")');
+ print(ir01());
+ print(ir02());
+ print(ast02(11));
+}
+
+main() {
+ ast01();
+ ir08();
+}
+
+@NoInline()
+check(func, names) {
+ var source = JS('String', 'String(#)', func);
+ print(source);
+ for (var f in names) {
+ Expect.isTrue(source.contains('"in $f"'), "should inline '$f'");
+ }
+}
+
+@NoInline
+checkAst01(func) {
+ var names = ["ast04", "ast05", "ast06", "ast08"];
+ check(func, names);
+}
+
+checkIr08(func) {
+ var names = ["ast09", "ast04", "ast05", "ast06", "ast08"];
+ check(func, names);
+}
diff --git a/tests/compiler/dart2js_native/bound_closure_test.dart b/tests/compiler/dart2js_native/bound_closure_test.dart
new file mode 100644
index 0000000..59dc306
--- /dev/null
+++ b/tests/compiler/dart2js_native/bound_closure_test.dart
@@ -0,0 +1,83 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:expect/expect.dart";
+
+// Test calling convention of property extraction closures.
+
+class AA {
+ bar(a, [b = 'A']) => 'AA.bar($a, $b)'; // bar is plain dart convention.
+ foo(a, [b = 'A']) => 'AA.foo($a, $b)'; // foo has interceptor convention.
+}
+
+class BB native "BB" {
+ foo(a, [b = 'B']) native;
+}
+
+class CC extends BB native "CC" {
+ foo(a, [b = 'C']) native;
+
+ get superfoo => super.foo;
+}
+
+makeBB() native;
+makeCC() native;
+inscrutable(a) native;
+
+void setup() native r"""
+function BB() {}
+BB.prototype.foo = function(u, v) {
+ return 'BB.foo(' + u + ', ' + v + ')';
+};
+
+function CC() {}
+CC.prototype.foo = function(u, v) {
+ return 'CC.foo(' + u + ', ' + v + ')';
+};
+
+makeBB = function(){return new BB;};
+makeCC = function(){return new CC;};
+inscrutable = function(a){return a;};
+""";
+
+
+main() {
+ setup();
+ var a = inscrutable(new AA());
+ var b = inscrutable(makeBB());
+ var c = inscrutable(makeCC);
+
+ Expect.equals('AA.bar(1, A)', inscrutable(a).bar(1));
+ Expect.equals('AA.bar(2, 3)', inscrutable(a).bar(2, 3));
+
+ Expect.equals('AA.foo(1, A)', inscrutable(a).foo(1));
+ Expect.equals('AA.foo(2, 3)', inscrutable(a).foo(2, 3));
+
+ Expect.equals('BB.foo(1, B)', inscrutable(b).foo(1));
+ Expect.equals('BB.foo(2, 3)', inscrutable(b).foo(2, 3));
+
+ Expect.equals('CC.foo(1, C)', inscrutable(c).foo(1));
+ Expect.equals('CC.foo(2, 3)', inscrutable(c).foo(2, 3));
+
+ var abar = inscrutable(a).bar;
+ var afoo = inscrutable(a).foo;
+ var bfoo = inscrutable(b).foo;
+ var cfoo = inscrutable(c).foo;
+ var csfoo = inscrutable(c).superfoo;
+
+ Expect.equals('AA.bar(1, A)', abar(1));
+ Expect.equals('AA.bar(2, 3)', abar(2, 3));
+
+ Expect.equals('AA.foo(1, A)', afoo(1));
+ Expect.equals('AA.foo(2, 3)', afoo(2, 3));
+
+ Expect.equals('BB.foo(1, B)', bfoo(1));
+ Expect.equals('BB.foo(2, 3)', bfoo(2, 3));
+
+ Expect.equals('CC.foo(1, C)', cfoo(1));
+ Expect.equals('CC.foo(2, 3)', cfoo(2, 3));
+
+ Expect.equals('BB.foo(1, B)', csfoo(1));
+ Expect.equals('BB.foo(2, 3)', csfoo(2, 3));
+}
diff --git a/tests/compiler/dart2js_native/compiler_test_internals.dart b/tests/compiler/dart2js_native/compiler_test_internals.dart
new file mode 100644
index 0000000..be2c4b6
--- /dev/null
+++ b/tests/compiler/dart2js_native/compiler_test_internals.dart
@@ -0,0 +1,10 @@
+// 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 compiler_test_internals;
+
+export 'dart:_js_helper' show
+ NoSideEffects, NoThrows, NoInline, IrRepresentation;
+
+export 'dart:_foreign_helper' show JS;
diff --git a/tests/compiler/dart2js_native/dart2js_native.status b/tests/compiler/dart2js_native/dart2js_native.status
index 10785bb..499d474 100644
--- a/tests/compiler/dart2js_native/dart2js_native.status
+++ b/tests/compiler/dart2js_native/dart2js_native.status
@@ -6,9 +6,10 @@
*: Skip
[ $compiler == dart2js ]
+bound_closure_test: Fail
+call_on_native_class_test: CompileTimeError # Issue 14813
native_no_such_method_exception4_frog_test: Fail # Issue 9631
native_no_such_method_exception5_frog_test: Fail # Issue 9631
-call_on_native_class_test: CompileTimeError # Issue 14813
[ $compiler == dart2js && $unminified ]
fake_thing_test: Fail # Issue 13010
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index e97e429..6fce1d2 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -54,6 +54,7 @@
[ $compiler == none || $compiler == dart2dart ]
symbol_test/none: Fail # bug 11669
+symbol_operator_test/03: Fail # bug 11669
[ $compiler == none && $runtime == drt ]
main_test: Fail # Dartium needs to check for both main() and main(args).
@@ -88,6 +89,10 @@
string_base_vm_test: RuntimeError, OK # VM specific test.
nan_infinity_test/01: Fail # Issue 11551
+[ $compiler == dart2js || $compiler == dart2dart]
+symbol_operator_test/01: CompileTimeError # Issue 15653.
+symbol_operator_test/02: CompileTimeError # Issue 15653.
+
[ $compiler == dart2js && $runtime == none ]
*: Fail, Pass # TODO(ahe): Triage these tests.
diff --git a/tests/corelib/for_in_test.dart b/tests/corelib/for_in_test.dart
index 82ea7b9..616d721 100644
--- a/tests/corelib/for_in_test.dart
+++ b/tests/corelib/for_in_test.dart
@@ -53,10 +53,9 @@
count += i;
}
Expect.equals(7, count);
- // TODO(ngeoffray): We should really test that [i] is 4 with a set
- // that preserves order. For now, making sure [i] is in the set
- // will have to do.
Expect.equals(true, set.contains(i));
+ // The default implementation of [Set] preserves order.
+ Expect.equals(4, i);
}
static void testBreak() {
diff --git a/tests/corelib/hash_map_test.dart b/tests/corelib/hash_map_test.dart
index 1bdc7be..52848e1 100644
--- a/tests/corelib/hash_map_test.dart
+++ b/tests/corelib/hash_map_test.dart
@@ -9,8 +9,6 @@
class HashMapTest {
static testMain() {
- // TODO(srdjan/ngeoffray): Add more meaningful testing below. For now this
- // is used to verify that the test script is picking up these tests.
var m = new Map();
Expect.equals(0, m.length);
Expect.equals(true, m.isEmpty);
diff --git a/tests/corelib/num_sign_test.dart b/tests/corelib/num_sign_test.dart
new file mode 100644
index 0000000..d2ee968
--- /dev/null
+++ b/tests/corelib/num_sign_test.dart
@@ -0,0 +1,107 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Test num.clamp.
+
+import "package:expect/expect.dart";
+
+// Pedestrian implementation of sign, following its specification directly.
+num sign(num value) {
+ if (value is int) {
+ if (value < 0) return -1;
+ if (value > 0) return 1;
+ return 0;
+ }
+ if (value.isNaN) return value;
+ if (value == 0.0) return value;
+ if (value > 0.0) return 1.0;
+ return -1.0;
+}
+
+var numbers = [
+ // Integers
+ 0,
+ 1,
+ 2,
+ 0x7f, // ~7 bits
+ 0x80,
+ 0xff, // ~8 bits
+ 0x100,
+ 0xffff, // ~16 bits
+ 0x10000,
+ 0x3fffffff, // ~30 bits (max positive 32-bit tagged smi)
+ 0x40000000,
+ 0x40000001,
+ 0x7fffffff, // ~31 bits
+ 0x80000000,
+ 0x80000001,
+ 0xfffffffff, // ~32 bits
+ 0x100000000,
+ 0x100000001,
+ 0x10000000000000, // ~53 bits
+ 0x10000000000001,
+ 0x1fffffffffffff,
+ 0x20000000000000,
+ 0x20000000000001, // first integer not representable as double.
+ 0x20000000000002,
+ 0x7fffffffffffffff, // ~63 bits
+ 0x8000000000000000,
+ 0x8000000000000001,
+ 0xffffffffffffffff, // ~64 bits
+ 0x10000000000000000,
+ 0x10000000000000001,
+ // Integers around the max-double range (2^1024, ~1025 bits).
+ 0xfffffffffffff800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,
+ 0xfffffffffffffc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,
+ 0x10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000,
+ // Doubles.
+ 0.0,
+ 5e-324, // min positive
+ 2.225073858507201e-308, // max denormal
+ 2.2250738585072014e-308, // min normal
+ 0.49999999999999994, // ~0.5
+ 0.5,
+ 0.5000000000000001,
+ 0.9999999999999999, // ~1.0
+ 1.0,
+ 1.0000000000000002,
+ 4294967295.0, // ~32 bits
+ 4294967296.0,
+ 4503599627370495.5, // max fractional
+ 4503599627370497.0,
+ 9007199254740991.0,
+ 9007199254740992.0, // max exact (+1 is not a double)
+ 1.7976931348623157e+308, // max finite double
+ 1.0 / 0.0, // Infinity
+ 0.0 / 0.0, // NaN
+];
+
+main() {
+ for (num number in numbers) {
+ test(number);
+ test(-number);
+ }
+}
+
+void test(number) {
+ num expectSign = sign(number);
+ num actualSign = number.sign;
+ if (expectSign.isNaN) {
+ Expect.isTrue(actualSign.isNaN, "$number: $actualSign != NaN");
+ } else {
+ if (number is int) {
+ Expect.isTrue(actualSign is int, "$number.sign is int");
+ } else {
+ Expect.isTrue(actualSign is double, "$number.sign is double");
+ }
+ Expect.equals(expectSign, actualSign, "$number");
+ Expect.equals(number.isNegative, actualSign.isNegative, "$number:negative");
+ var renumber = actualSign * number.abs();
+ Expect.equals(number, renumber, "$number (sign*abs)");
+ if (number is int) {
+ Expect.isTrue(renumber is int, "$number (sign*abs) is int");
+ } else {
+ Expect.isTrue(renumber is double, "$number (sign*abs) is double");
+ }
+ }
+}
diff --git a/tests/corelib/string_test.dart b/tests/corelib/string_test.dart
index aeb00c3..2d34c063 100644
--- a/tests/corelib/string_test.dart
+++ b/tests/corelib/string_test.dart
@@ -4,7 +4,6 @@
import "package:expect/expect.dart";
-// TODO(ngeoffray): test String methods with null arguments.
class StringTest {
static testMain() {
diff --git a/tests/corelib/symbol_operator_test.dart b/tests/corelib/symbol_operator_test.dart
new file mode 100644
index 0000000..13cd8bc
--- /dev/null
+++ b/tests/corelib/symbol_operator_test.dart
@@ -0,0 +1,81 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test of Symbol class for operators..
+
+var $ = new Symbolize();
+
+main() {
+ testSymbol(#+, $+$, "+");
+ testSymbol(#-, $-$, "-");
+ testSymbol(#*, $*$, "*");
+ testSymbol(#/, $/$, "/");
+ testSymbol(#~/, $~/$, "~/");
+ testSymbol(#%, $%$, "%");
+ testSymbol(#<<, $<<$, "<<");
+ testSymbol(#>>, $>>$, ">>");
+ testSymbol(#~, ~$, "~");
+ testSymbol(#|, $|$, "|");
+ testSymbol(#&, $&$, "&");
+ testSymbol(#^, $^$, "^");
+ testSymbol(#<, $<$, "<");
+ testSymbol(#<=, $<=$, "<=");
+ testSymbol(#>, $>$, ">");
+ testSymbol(#>=, $>=$, ">=");
+ testSymbol(#==, new Symbol("=="), "=="); // Can't hit noSuchMethod.
+ testSymbol(#[], $[$], "[]"); /// 01: ok
+ testSymbol(#[]=, ($[$]=$).lastMember, "[]="); /// 02: ok
+ testSymbol(const Symbol("unary-"), -$, "unary-");
+
+ testSymbolThrows(">>>"); /// 03: ok
+ testSymbolThrows("!"); /// 03: continued
+ testSymbolThrows("&&"); /// 03: continued
+ testSymbolThrows("||"); /// 03: continued
+ testSymbolThrows("?"); /// 03: continued
+ testSymbolThrows("?:"); /// 03: continued
+ testSymbolThrows("#"); /// 03: continued
+ testSymbolThrows("//"); /// 03: continued
+}
+
+void testSymbol(Symbol constSymbol, var mirrorSymbol, String name) {
+ Symbol dynamicSymbol = new Symbol(name);
+ if (constSymbol != mirrorSymbol) {
+ throw "Not equal #$name, \$$name: $constSymbol, $mirrorSymbol";
+ }
+ if (constSymbol != dynamicSymbol) {
+ throw "Not equal #$name, new Symbol('$name'): $constSymbol, $dynamicSymbol";
+ }
+ if (mirrorSymbol != dynamicSymbol) {
+ throw "Not equal \$$name, new Symbol('$name'): "
+ "$mirrorSymbol, $dynamicSymbol";
+ }
+ if (constSymbol.hashCode != mirrorSymbol.hashCode) {
+ throw "HashCode not equal #$name, \$$name: $constSymbol, $mirrorSymbol";
+ }
+ if (constSymbol.hashCode != dynamicSymbol.hashCode) {
+ throw "HashCode not equal #$name, new Symbol('$name'): "
+ "$constSymbol, $dynamicSymbol";
+ }
+ if (mirrorSymbol.hashCode != dynamicSymbol.hashCode) {
+ throw "HashCode not equal \$$name, new Symbol('$name'): "
+ "$mirrorSymbol, $dynamicSymbol";
+ }
+}
+
+void testSymbolThrows(name) {
+ bool fails = false;
+ try {
+ new Symbol(name);
+ } catch (e) {
+ fails = true;
+ }
+ if (!fails) {
+ throw "Didn't throw: $name";
+ }
+}
+
+class Symbolize {
+ Symbol lastMember;
+ noSuchMethod(m) => lastMember = m.memberName;
+}
diff --git a/tests/html/custom/mirrors_test.dart b/tests/html/custom/mirrors_test.dart
new file mode 100644
index 0000000..ea6b091
--- /dev/null
+++ b/tests/html/custom/mirrors_test.dart
@@ -0,0 +1,66 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library tests.html.mirrors_test;
+
+import 'dart:mirrors';
+import 'dart:html';
+import 'package:unittest/unittest.dart';
+import 'package:unittest/html_config.dart';
+import '../utils.dart';
+
+/// Regression test for a tricky mirrors+custom_elements issue:
+/// dart2js mirrors cache dispatch information on the Object's constructor.
+/// This was failing for custom elements on IE 10, because the constructor was
+/// HTMLUnknownElement for all of them. So mirrors called the wrong method.
+main() {
+ useHtmlConfiguration();
+
+ var registered = false;
+ setUp(() => loadPolyfills().then((_) {
+ if (!registered) {
+ registered = true;
+ document.register(A.tag, A);
+ document.register(B.tag, B);
+ }
+ }));
+
+ test('dynamic dispatch', () {
+ var a = new A();
+ expect(a.fooBar, 1);
+ reflect(a).setField(#fooBar, 123);
+ expect(a.fooBar, 123);
+
+ // Even though A was set first, B.fooBar= should dispatch to B.
+ var b = new B();
+ expect(b.fooBar, 2);
+ expect(b._fooBarSet, 0);
+ reflect(b).setField(#fooBar, 123);
+ expect(b.fooBar, 123);
+ expect(b._fooBarSet, 1);
+ });
+}
+
+class A extends HtmlElement {
+ static final tag = 'x-a';
+ factory A() => new Element.tag(tag);
+ A.created() : super.created();
+
+ int fooBar = 1;
+}
+
+class B extends HtmlElement {
+ static final tag = 'x-b';
+ factory B() => new Element.tag(tag);
+ B.created() : super.created();
+
+ int _fooBar = 2;
+ int _fooBarSet = 0;
+
+ int get fooBar => _fooBar;
+ set fooBar(value) {
+ _fooBarSet++;
+ _fooBar = value;
+ }
+}
diff --git a/tests/html/html.status b/tests/html/html.status
index 9eaefff..b7fa8d6 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -6,9 +6,6 @@
interactive_test: Skip # Must be run manually.
dromaeo_smoke_test: Skip # Issue 14521, 8257
-[ $compiler == dart2js && $csp && $runtime == drt ]
-mutationobserver_test: Skip # http://dartbug.com/15497
-
[ $compiler == dart2js && $csp ]
custom/js_custom_test: Fail # Issue 14643
@@ -280,7 +277,7 @@
canvasrenderingcontext2d_test/drawImage_video_element_dataUrl: Fail # Safari does not support drawImage w/ video element
audiocontext_test/functional: Fail # Issue 14354
websql_test/functional: RuntimeError # Issue 14523
-
+custom/mirrors_test: Fail # Issue 15737
# Safari Feature support statuses-
# All changes should be accompanied by platform support annotation changes.
@@ -341,6 +338,10 @@
speechrecognition_test/supported: Fail
websql_test/supported: Fail
+[ $runtime == ff && $system == windows ]
+messageevent_test: RuntimeError # Issue 15651
+serialized_script_value_test: RuntimeError # Issue 15651
+
[ $runtime == ff ]
xhr_test/xhr: Pass, Fail # Issue 11602
dart_object_local_storage_test: Skip # sessionStorage NS_ERROR_DOM_NOT_SUPPORTED_ERR
diff --git a/tests/html/mutationobserver_test.dart b/tests/html/mutationobserver_test.dart
index 0af69c5..582f084 100644
--- a/tests/html/mutationobserver_test.dart
+++ b/tests/html/mutationobserver_test.dart
@@ -7,6 +7,12 @@
import '../../pkg/unittest/lib/html_individual_config.dart';
import 'dart:html';
+// Due to https://code.google.com/p/chromium/issues/detail?id=329103
+// mutationObservers sometimes do not fire if the node being observed is GCed
+// so we keep around references to all nodes we have created mutation
+// observers for.
+var keepAlive = [];
+
/**
* Test suite for Mutation Observers. This is just a small set of sanity
* checks, not a complete test suite.
@@ -61,6 +67,7 @@
test('direct-parallel options-named', () {
expect(() {
var container = new DivElement();
+ keepAlive.add(container);
var div1 = new DivElement();
var div2 = new DivElement();
var mutationObserver = new MutationObserver(
@@ -75,6 +82,7 @@
test('direct-nested options-named', () {
expect(() {
var container = new DivElement();
+ keepAlive.add(container);
var div1 = new DivElement();
var div2 = new DivElement();
var mutationObserver =
@@ -89,6 +97,7 @@
test('subtree options-named', () {
expect(() {
var container = new DivElement();
+ keepAlive.add(container);
var div1 = new DivElement();
var div2 = new DivElement();
var mutationObserver = new MutationObserver(
diff --git a/tests/isolate/static_function_test.dart b/tests/isolate/static_function_test.dart
index db0beba..28e06b4 100644
--- a/tests/isolate/static_function_test.dart
+++ b/tests/isolate/static_function_test.dart
@@ -70,9 +70,11 @@
});
}
-void throwsTest(name, function) {
+void functionFailTest(name, function) {
test("throws on $name", () {
- expect(() { Isolate.spawn(function, null); }, throws);
+ Isolate.spawn(function, null).catchError(expectAsync1((e) {
+ /* do nothing */
+ }));
});
}
@@ -97,12 +99,14 @@
spawnTest("lib._class._function", lib.privateClassAndFunction, "_LIBPRIVATE");
// Negative tests
- throwsTest("static closure", staticClosure);
- throwsTest("dynamic closure", dynamicClosure);
- throwsTest("named dynamic closure", namedDynamicClosure);
- throwsTest("instance closure", new C().instanceClosure);
- throwsTest("initializer closure", new C().constructorInitializerClosure);
- throwsTest("constructor closure", new C().constructorBodyClosure);
- throwsTest("named constructor closure", new C().namedConstructorBodyClosure);
- throwsTest("instance method", new C().instanceMethod);
+ functionFailTest("static closure", staticClosure);
+ functionFailTest("dynamic closure", dynamicClosure);
+ functionFailTest("named dynamic closure", namedDynamicClosure);
+ functionFailTest("instance closure", new C().instanceClosure);
+ functionFailTest("initializer closure",
+ new C().constructorInitializerClosure);
+ functionFailTest("constructor closure", new C().constructorBodyClosure);
+ functionFailTest("named constructor closure",
+ new C().namedConstructorBodyClosure);
+ functionFailTest("instance method", new C().instanceMethod);
}
diff --git a/tests/language/assert_assignable_type_test.dart b/tests/language/assert_assignable_type_test.dart
new file mode 100644
index 0000000..246f13e
--- /dev/null
+++ b/tests/language/assert_assignable_type_test.dart
@@ -0,0 +1,31 @@
+// 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.
+// Dart test program to test arithmetic operations.
+// VMOptions=--optimization-counter-threshold=10 --checked
+
+// This test crashes if we recompute type of AssertAssignableInstr based on its
+// output types. By doing that we would eliminate not only the unnecessary
+// AssertAssignableInstr but also the trailing class check.
+
+main() {
+ // Foul up IC data in integer's unary minus.
+ var y = -0x80000000;
+ testInt64List();
+}
+
+testInt64List() {
+ var array = new List(10);
+ testInt64ListImpl(array);
+}
+
+
+testInt64ListImpl(array) {
+ for (int i = 0; i < 10; ++i) {
+ }
+ int sum = 0;
+ for (int i = 0; i < 10; ++i) {
+ array[i] = -0x80000000000000 + i;
+ }
+}
+
diff --git a/tests/language/guess_cid_test.dart b/tests/language/guess_cid_test.dart
new file mode 100644
index 0000000..3759cb9
--- /dev/null
+++ b/tests/language/guess_cid_test.dart
@@ -0,0 +1,88 @@
+// 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.
+// Dart test program to test cid guessing optimizations.
+// VMOptions=--optimization-counter-threshold=10
+
+import "package:expect/expect.dart";
+
+main() {
+ // Warmup optimizes methods.
+ for (int i = 0; i < 100; i++) {
+ Expect.equals(i, compareInt(i));
+ Expect.equals(i.toDouble(), compareDouble(i.toDouble()));
+ Expect.equals(i, binOpInt(i, i));
+ Expect.equals(i.toDouble(), binOpDouble(i.toDouble(), i.toDouble()));
+ }
+ Expect.equals(3, compareInt(3));
+ Expect.equals(-2, compareInt(-2));
+ Expect.equals(0, compareInt(-1));
+
+ Expect.equals(3, binOpInt(3, 3));
+ Expect.equals(0, binOpInt(-2, -2));
+
+ Expect.equals(3.0, binOpDouble(3.0, 3.0));
+ Expect.equals(0.0, binOpDouble(-2.0, -2.0));
+
+ Expect.equals(3.0, compareDouble(3.0));
+ Expect.equals(-2.0, compareDouble(-2.0));
+ Expect.equals(0.0, compareDouble(-1.0));
+
+ testOSR();
+}
+
+int compareInt(int i) {
+ if (i < 0) {
+ // Not visited in before optimization.
+ // Guess cid of comparison below.
+ if (i == -1) return 0;
+ }
+ return i;
+}
+
+double compareDouble(double i) {
+ if (i < 0.0) {
+ // Not visited in before optimization.
+ // Guess cid of comparison below.
+ if (i == -1.0) return 0.0;
+ }
+ return i;
+}
+
+int binOpInt(int i, int x) {
+ if (i < 0) {
+ // Not visited in before optimization.
+ // Guess cid of binary operation below.
+ return x + 2;
+ }
+ return i;
+}
+
+double binOpDouble(double i, double x) {
+ if (i < 0.0) {
+ // Not visited in before optimization.
+ // Guess cid of binary operation below.
+ return x + 2.0;
+ }
+ return i;
+}
+
+testOSR() {
+ // Foul up IC data in integer's unary minus.
+ var y = -0x80000000;
+ Expect.equals(1475739525896764129300, testLoop(10, 0x80000000000000000));
+ // Second time no deoptimization can occur, since runtime feedback has been collected.
+ Expect.equals(1475739525896764129300, testLoop(10, 0x80000000000000000));
+}
+
+testLoop(N, x) {
+ for (int i = 0; i < N; ++i) {
+ // Will trigger OSR. Operation in loop below will use guessed cids.
+ }
+ int sum = 0;
+ for (int i = 0; i < N; ++i) {
+ // Guess 'x' is Smi, but is actually Bigint: deoptimize.
+ sum += x + 2;
+ }
+ return sum;
+}
diff --git a/tests/language/illegal_initializer_test.dart b/tests/language/illegal_initializer_test.dart
new file mode 100644
index 0000000..64d54f9
--- /dev/null
+++ b/tests/language/illegal_initializer_test.dart
@@ -0,0 +1,43 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class A {
+ A();
+ A.foo();
+}
+
+class B extends A {
+ B.c1() : super.foo
+ /* /// 01: compile-time error
+ ()
+ */ /// 01: continued
+ ;
+
+ B.foo();
+ B.c2() : this.foo
+ /* /// 02: compile-time error
+ ()
+ */ /// 02: continued
+ ;
+
+ B.c3() : super
+ /* /// 03: compile-time error
+ ()
+ */ /// 03: continued
+ ;
+
+ B();
+ B.c4() : this
+ /* /// 04: compile-time error
+ ()
+ */ /// 04: continued
+ ;
+}
+
+main() {
+ new B.c1();
+ new B.c2();
+ new B.c3();
+ new B.c4();
+}
diff --git a/tests/language/inferrer_closure_test.dart b/tests/language/inferrer_closure_test.dart
new file mode 100644
index 0000000..0106ce6
--- /dev/null
+++ b/tests/language/inferrer_closure_test.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for dart2js that used to not see a closure could be
+// invoked through a getter access followed by an invocation.
+
+var closure = (a) => a.toString();
+
+get foo => closure;
+
+main() {
+ if (foo(42) != '42') {
+ throw 'Test failed';
+ }
+}
diff --git a/tests/language/invocation_mirror2_test.dart b/tests/language/invocation_mirror2_test.dart
index c07330c..3e64ba4 100644
--- a/tests/language/invocation_mirror2_test.dart
+++ b/tests/language/invocation_mirror2_test.dart
@@ -9,7 +9,7 @@
set flif(_) => "flif=";
}
-String getName(im) => reflect(new GetName()).delegate(im);
+int getName(im) => reflect(new GetName()).delegate(im);
class C {
var im;
@@ -20,6 +20,6 @@
main() {
var c = new C();
c.flif = 42;
- Expect.equals('flif=', getName(c.im));
+ Expect.equals(42, getName(c.im));
Expect.equals(42, c.im.positionalArguments[0]);
}
diff --git a/tests/language/issue15606_test.dart b/tests/language/issue15606_test.dart
new file mode 100644
index 0000000..d50b576
--- /dev/null
+++ b/tests/language/issue15606_test.dart
@@ -0,0 +1,21 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Foo<T> {}
+
+var a = [new Object(), 42];
+
+main() {
+ while (false) { // Comply to inlining heuristics.
+ // Use an unresolved prefix.
+ var foo = Unresolved.foo( /// 01: static type warning
+ // Make dart2js generate a call to setRuntimeTypeInfo.
+ new Foo<int>(), /// 01: continued
+ // Use a one-shot interceptor.
+ a[0].toString()); /// 01: continued
+
+ // Do an is test on `Foo` to require setRuntimeTypeInfo.
+ print(foo is Foo<int>); /// 01: continued
+ }
+}
diff --git a/tests/language/issue15702_test.dart b/tests/language/issue15702_test.dart
new file mode 100644
index 0000000..283a021
--- /dev/null
+++ b/tests/language/issue15702_test.dart
@@ -0,0 +1,16 @@
+// 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.
+
+main() {
+ Amount stake = new Amount(2.5);
+ if ((stake.value * 10).toInt() != 25) {
+ throw 'Test failed';
+ }
+}
+
+class Amount {
+ num value;
+ Amount(this.value);
+}
+
diff --git a/tests/language/language_analyzer.status b/tests/language/language_analyzer.status
index bcdd6cf..ee85f4c 100644
--- a/tests/language/language_analyzer.status
+++ b/tests/language/language_analyzer.status
@@ -314,7 +314,6 @@
malbounded_type_literal_test: StaticWarning
malformed_type_test: StaticWarning
malformed2_test/01: MissingCompileTimeError
-map_literal11_test: StaticWarning
map_literal2_negative_test: CompileTimeError
map_literal3_test: StaticWarning
map_literal4_test: StaticWarning
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 8b873d9..1942eb0 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -137,6 +137,7 @@
mixin_regress_13688_test: RuntimeError # Issue 13109.
modulo_test: RuntimeError # Issue 15246
truncdiv_test: RuntimeError # Issue 15246
+invocation_mirror2_test: RuntimeError # Issue 6490 (wrong retval).
# Compilation errors.
const_var_test: CompileTimeError # Issue 12793
diff --git a/tests/language/list_tracer_return_from_tearoff_closure_test.dart b/tests/language/list_tracer_return_from_tearoff_closure_test.dart
new file mode 100644
index 0000000..47e1bb49
--- /dev/null
+++ b/tests/language/list_tracer_return_from_tearoff_closure_test.dart
@@ -0,0 +1,20 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test for dart2js's list tracer, that used to not see a
+// returned value of a method can escape to places where that method
+// is closurized and invoked.
+
+var a = [42];
+
+foo() {
+ return a;
+}
+
+main() {
+ (foo)().clear();
+ if (a.length == 1) {
+ throw 'Test failed';
+ }
+}
diff --git a/tests/language/load_indexed_constant_test.dart b/tests/language/load_indexed_constant_test.dart
new file mode 100644
index 0000000..cf45b18
--- /dev/null
+++ b/tests/language/load_indexed_constant_test.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Test constant propgation of load-indexed operations
+// VMOptions=--optimization-counter-threshold=10
+
+import "package:expect/expect.dart";
+
+
+main() {
+ Expect.equals(101, stringIndexedLoad());
+ Expect.equals(102, arrayIndexedLoad());
+ for (int i = 0; i < 20; i++) {
+ stringIndexedLoad();
+ arrayIndexedLoad();
+ }
+ Expect.equals(101, stringIndexedLoad());
+ Expect.equals(102, arrayIndexedLoad());
+}
+
+stringIndexedLoad() => ("Hello").codeUnitAt(1);
+arrayIndexedLoad() => (const [101, 102, 103])[1];
\ No newline at end of file
diff --git a/tests/language/super_abstract_method_test.dart b/tests/language/super_abstract_method_test.dart
index fbb3648..b501b7f 100644
--- a/tests/language/super_abstract_method_test.dart
+++ b/tests/language/super_abstract_method_test.dart
@@ -17,6 +17,7 @@
class B extends A {
testSuperCall() => super.foo();
+ foo() => 42; // required since if is removed, then a warning is introduced on 'B' above
}
main() {
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index 789712d..1762ceb 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -21,6 +21,7 @@
mirrors/closures_test/none: RuntimeError # Issue 6490
mirrors/constructor_kinds_test: RuntimeError # Issue 13799
mirrors/constructor_private_name_test: CompileTimeError # Issue 13597
+mirrors/delegate_call_through_getter_test: RuntimeError # Issue 15138
mirrors/equality_test/02: RuntimeError # Issue 12785
mirrors/fake_function_with_call_test: RuntimeError # Issue 11612
mirrors/fake_function_without_call_test: RuntimeError # Issue 11612
@@ -41,6 +42,7 @@
mirrors/instance_members_test: RuntimeError # Issue 14633
mirrors/instance_members_with_override_test: RuntimeError # Issue 14633
mirrors/instance_members_unimplemented_interface_test: RuntimeError # Issue 14633
+mirrors/instantiate_abstract_class_test: RuntimeError # Issue 6490
mirrors/intercepted_superclass_test: RuntimeError # Issue 13644
mirrors/invoke_test: RuntimeError # Issue 11954
mirrors/invoke_call_through_getter_test: RuntimeError # Issue 15138
@@ -64,7 +66,6 @@
mirrors/mirrors_test: RuntimeError # TODO(ahe): I'm working on fixing this.
mirrors/mixin_test: RuntimeError # Issue 12464
mirrors/mixin_application_test/none: RuntimeError # Issue 12464
-mirrors/new_instance_with_type_arguments_test: RuntimeError # Issue 12333
mirrors/null_test : RuntimeError # Issue 12129
mirrors/parameter_test/none: RuntimeError # Issue 6490
mirrors/parameter_metadata_test: CompileTimeError # Issue 10905
@@ -72,7 +73,6 @@
mirrors/proxy_type_test: RuntimeError # Issue 13842
mirrors/redirecting_factory_test/none: RuntimeError # Issue 6490
mirrors/redirecting_factory_test/02: RuntimeError # Issue 6490
-mirrors/reflected_type_test: RuntimeError # Issue 12607
mirrors/repeated_private_anon_mixin_app_test: RuntimeError # Issue 14670
mirrors/symbol_validation_test: RuntimeError # Issue 13597
mirrors/static_members_test: RuntimeError # Issue 14633, Issue 12164
@@ -161,6 +161,8 @@
[ $compiler == dart2js && $minified ]
mirrors/typedef_test/01: Fail # http://dartbug.com/6490
mirrors/list_constructor_test/none: Fail # http://dartbug.com/15555
+mirrors/mirrors_used_get_name_test: RuntimeError
+mirrors/mirrors_used_get_name2_test: RuntimeError
[ $runtime == ff ]
# FF setTimeout can fire early: https://bugzilla.mozilla.org/show_bug.cgi?id=291386
@@ -207,7 +209,7 @@
mirrors/generic_local_function_test: RuntimeError # Issue 14913
mirrors/symbol_validation_test: RuntimeError # Issue 13596
mirrors/synthetic_accessor_properties_test/none: RuntimeError # Issue 14632
-mirrors/toplevel_members_test: RuntimeError # Issue 14632
+mirrors/toplevel_members_test/01: RuntimeError # Issue 14632
async/timer_not_available_test: SkipByDesign # only meant to test when there is no way to implement timer (currently only in d8)
@@ -254,7 +256,6 @@
[ $compiler == dartanalyzer || $compiler == dart2analyzer ]
mirrors/generic_f_bounded_mixin_application_test: CompileTimeError # Issue 14116
-mirrors/invoke_named_test: StaticWarning # Issue 14522
mirrors/redirecting_factory_test/01: StaticWarning # test issue X, The return type 'Class<T2, T1>' of the redirected constructor is not assignable to 'Class<T1, T2>'
mirrors/redirecting_factory_test/none: StaticWarning # test issue X, The return type 'Class<T2, T1>' of the redirected constructor is not assignable to 'Class<T1, T2>
diff --git a/tests/lib/mirrors/delegate_call_through_getter_test.dart b/tests/lib/mirrors/delegate_call_through_getter_test.dart
new file mode 100644
index 0000000..4d0d088
--- /dev/null
+++ b/tests/lib/mirrors/delegate_call_through_getter_test.dart
@@ -0,0 +1,45 @@
+// 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 test.invoke_call_through_getter;
+
+import 'dart:mirrors';
+
+import 'package:expect/expect.dart';
+
+class FakeFunctionCall {
+ call(x, y) => '1 $x $y';
+}
+class FakeFunctionNSM {
+ noSuchMethod(msg) => msg.positionalArguments.join(', ');
+}
+
+class C {
+ get fakeFunctionCall => new FakeFunctionCall();
+ get fakeFunctionNSM => new FakeFunctionNSM();
+ get closure => (x, y) => '2 $this $x $y';
+ get closureOpt => (x, y, [z, w]) => '3 $this $x $y $z $w';
+ get closureNamed => (x, y, {z, w}) => '4 $this $x $y $z $w';
+ get notAClosure => 'Not a closure';
+ noSuchMethod(msg) => 'DNU';
+
+ toString() => 'C';
+}
+
+class Forwarder {
+ noSuchMethod(msg) => reflect(new C()).delegate(msg);
+}
+
+main() {
+ var f = new Forwarder();
+
+ Expect.equals('1 5 6', f.fakeFunctionCall(5, 6));
+ Expect.equals('7, 8', f.fakeFunctionNSM(7, 8));
+ Expect.equals('2 C 9 10', f.closure(9, 10));
+ Expect.equals('3 C 11 12 13 null', f.closureOpt(11, 12, 13));
+ Expect.equals('4 C 14 15 null 16', f.closureNamed(14, 15, w: 16));
+ Expect.equals('DNU', f.doesNotExist(17, 18));
+ Expect.throws(() => f.closure('wrong arity'), (e) => e is NoSuchMethodError);
+ Expect.throws(() => f.notAClosure(), (e) => e is NoSuchMethodError);
+}
diff --git a/tests/lib/mirrors/initializing_formals_test.dart b/tests/lib/mirrors/initializing_formals_test.dart
index 2729524..cbb0812 100644
--- a/tests/lib/mirrors/initializing_formals_test.dart
+++ b/tests/lib/mirrors/initializing_formals_test.dart
@@ -46,7 +46,7 @@
Expect.isFalse(pm.isPrivate);
Expect.isFalse(pm.isStatic);
Expect.isFalse(pm.isTopLevel);
-
+
mm = reflectClass(Class).declarations[#Class.named];
pm = mm.parameters.single;
Expect.equals(#boolField, pm.simpleName);
@@ -71,11 +71,11 @@
Expect.isFalse(pm.isPrivate);
Expect.isFalse(pm.isStatic);
Expect.isFalse(pm.isTopLevel);
-
+
mm = reflectClass(Class).declarations[#Class.generic];
pm = mm.parameters.single;
Expect.equals(#tField, pm.simpleName);
- Expect.equals(reflectClass(Class).typeVariables.single, pm.type);
+ Expect.equals(reflectClass(Class).typeVariables.single, pm.type);
Expect.isFalse(pm.isNamed); /// 01: ok
Expect.isFalse(pm.isFinal); /// 01: ok
Expect.isFalse(pm.isOptional); /// 01: ok
diff --git a/tests/lib/mirrors/instantiate_abstract_class_test.dart b/tests/lib/mirrors/instantiate_abstract_class_test.dart
new file mode 100644
index 0000000..e86e534
--- /dev/null
+++ b/tests/lib/mirrors/instantiate_abstract_class_test.dart
@@ -0,0 +1,46 @@
+// 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 test.instantiate_abstract_class;
+
+import 'dart:mirrors';
+import 'package:expect/expect.dart';
+
+
+assertInstanitationErrorOnGenerativeConstructors(classMirror) {
+ classMirror.declarations.values.forEach((decl) {
+ if (decl is! MethodMirror) return;
+ if (!decl.isGenerativeConstructor) return;
+ var args = new List(decl.parameters.length);
+ Expect.throws(() => classMirror.newInstance(decl.constructorName, args),
+ (e) => e is AbstractClassInstantiationError,
+ '${decl.qualifiedName} should have failed');
+ });
+}
+
+runFactoryConstructors(classMirror) {
+ classMirror.declarations.values.forEach((decl) {
+ if (decl is! MethodMirror) return;
+ if (!decl.isFactoryConstructor) return;
+ var args = new List(decl.parameters.length);
+ classMirror.newInstance(decl.constructorName, args); // Should not throw.
+ });
+}
+
+abstract class AbstractClass {
+ AbstractClass();
+ AbstractClass.named();
+ factory AbstractClass.named2() => new ConcreteClass();
+}
+
+class ConcreteClass implements AbstractClass {}
+
+main() {
+ assertInstanitationErrorOnGenerativeConstructors(reflectType(num));
+ assertInstanitationErrorOnGenerativeConstructors(reflectType(double));
+ assertInstanitationErrorOnGenerativeConstructors(reflectType(StackTrace));
+
+ assertInstanitationErrorOnGenerativeConstructors(reflectType(AbstractClass));
+ runFactoryConstructors(reflectType(AbstractClass));
+}
diff --git a/tests/lib/mirrors/mirrors_used_get_name2_test.dart b/tests/lib/mirrors/mirrors_used_get_name2_test.dart
new file mode 100644
index 0000000..762665e
--- /dev/null
+++ b/tests/lib/mirrors/mirrors_used_get_name2_test.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test to make sure that the names of classes that are marked with meta
+// annotations of MirrorsUsed are preserved.
+// In the test the class B is not instantiated, but we still want its names
+// ("foo") to be preserved.
+
+@MirrorsUsed(metaTargets: "Meta")
+import 'dart:mirrors';
+import 'package:expect/expect.dart';
+
+class A {
+ noSuchMethod(invocationMirror) {
+ return MirrorSystem.getName(invocationMirror.memberName);
+ }
+}
+
+class B {
+ @Meta()
+ foo() => 499;
+}
+
+class Meta {
+ const Meta();
+}
+
+void main() {
+ var a = new A();
+ if (new DateTime.now().year == 1984) {
+ a = A;
+ }
+ Expect.equals("foo", a.foo());
+}
diff --git a/tests/lib/mirrors/mirrors_used_get_name_test.dart b/tests/lib/mirrors/mirrors_used_get_name_test.dart
new file mode 100644
index 0000000..f87ee52
--- /dev/null
+++ b/tests/lib/mirrors/mirrors_used_get_name_test.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Test to make sure that the names of classes that are marked with mirrors-used
+// are preserved.
+// In the test the class B is not instantiated, but we still want its names (the
+// "foo") to be preserved.
+
+@MirrorsUsed(targets: "B")
+import 'dart:mirrors';
+import 'package:expect/expect.dart';
+
+class A {
+ noSuchMethod(invocationMirror) {
+ return MirrorSystem.getName(invocationMirror.memberName);
+ }
+}
+
+class B {
+ foo() => 499;
+}
+
+void main() {
+ var a = new A();
+ if (new DateTime.now().year == 1984) {
+ a = A;
+ }
+ Expect.equals("foo", a.foo());
+}
diff --git a/tests/lib/mirrors/new_instance_with_type_arguments_test.dart b/tests/lib/mirrors/new_instance_with_type_arguments_test.dart
index 44238ad..2885bbb 100644
--- a/tests/lib/mirrors/new_instance_with_type_arguments_test.dart
+++ b/tests/lib/mirrors/new_instance_with_type_arguments_test.dart
@@ -20,7 +20,7 @@
ClassMirror cmA = reflectClass(A);
ClassMirror cmB = reflectClass(B);
ClassMirror cmC = reflectClass(C);
-
+
var a_int = new A<int>();
var a_dynamic = new A();
var b = new B();
@@ -36,31 +36,26 @@
Expect.equals(String, c_string.s);
Expect.equals(dynamic, c_dynamic.s);
-
var reflective_a_int =
cmB.superclass.newInstance(const Symbol(''), []).reflectee;
var reflective_a_dynamic =
cmA.newInstance(const Symbol(''), []).reflectee;
var reflective_b =
cmB.newInstance(const Symbol(''), []).reflectee;
- // TODO(rmacnak): Uncomment when reflectType is added to the API.
- // var reflective_c_string =
- // reflectType(cmC.runtimeType).newInstance(const Symbol(''), []).reflectee;
var reflective_c_dynamic =
cmC.newInstance(const Symbol(''), []).reflectee;
Expect.equals(int, reflective_a_int.t);
Expect.equals(dynamic, reflective_a_dynamic.t);
Expect.equals(int, reflective_b.t);
- // Expect.equals(num, c_string.t);
+ Expect.equals(num, c_string.t);
Expect.equals(num, reflective_c_dynamic.t);
- // Expect.equals(String, c_string.s);
+ Expect.equals(String, c_string.s);
Expect.equals(dynamic, reflective_c_dynamic.s);
Expect.equals(a_int.runtimeType, reflective_a_int.runtimeType);
Expect.equals(a_dynamic.runtimeType, reflective_a_dynamic.runtimeType);
Expect.equals(b.runtimeType, reflective_b.runtimeType);
- // Expect.equals(c_string.runtimeType, reflective_c_string.runtimeType);
Expect.equals(c_dynamic.runtimeType, reflective_c_dynamic.runtimeType);
}
diff --git a/tests/lib/mirrors/reflected_type_test.dart b/tests/lib/mirrors/reflected_type_test.dart
index 70ebcf3..a574434 100644
--- a/tests/lib/mirrors/reflected_type_test.dart
+++ b/tests/lib/mirrors/reflected_type_test.dart
@@ -19,17 +19,27 @@
expectReflectedType(classMirror, expectedType) {
if (expectedType == null) {
- Expect.isFalse(classMirror.hasReflectedType);
+ Expect.isFalse(classMirror.hasReflectedType,
+ "$classMirror should not have a reflected type");
Expect.throws(() => classMirror.reflectedType,
- (e) => e is UnsupportedError,
- "Should not have a reflected type");
+ (e) => e is UnsupportedError);
} else {
- Expect.isTrue(classMirror.hasReflectedType);
+ Expect.isTrue(classMirror.hasReflectedType,
+ "$classMirror should have a reflected type");
Expect.equals(expectedType, classMirror.reflectedType);
}
}
main() {
+ // Basic non-generic types, including intercepted types.
+ expectReflectedType(reflectClass(Object), Object);
+ expectReflectedType(reflectClass(String), String);
+ expectReflectedType(reflectClass(int), int);
+ expectReflectedType(reflectClass(num), num);
+ expectReflectedType(reflectClass(double), double);
+ expectReflectedType(reflectClass(bool), bool);
+ expectReflectedType(reflectClass(Null), Null);
+
// Declarations.
expectReflectedType(reflectClass(A), null);
expectReflectedType(reflectClass(B), B);
diff --git a/tests/lib/mirrors/synthetic_accessor_properties_test.dart b/tests/lib/mirrors/synthetic_accessor_properties_test.dart
index fc96b6d..215d3a3 100644
--- a/tests/lib/mirrors/synthetic_accessor_properties_test.dart
+++ b/tests/lib/mirrors/synthetic_accessor_properties_test.dart
@@ -68,7 +68,6 @@
mm = cm.staticMembers[const Symbol('finalStaticField=')];
Expect.isNull(mm);
- return; /// 01: ok
mm = lm.topLevelMembers[#topLevelField];
expect('Method(s(topLevelField) in s(test.synthetic_accessor_properties),'
@@ -93,6 +92,8 @@
mm = lm.topLevelMembers[const Symbol('finalTopLevelField=')];
Expect.isNull(mm);
+ return; /// 01: ok
+
mm = lm.topLevelMembers[#C];
expect('Method(s(C) in s(test.synthetic_accessor_properties),'
' top-level, synthetic, static, getter)', mm);
diff --git a/tests/lib/mirrors/toplevel_members_test.dart b/tests/lib/mirrors/toplevel_members_test.dart
index 1fe613b..84839d8 100644
--- a/tests/lib/mirrors/toplevel_members_test.dart
+++ b/tests/lib/mirrors/toplevel_members_test.dart
@@ -29,13 +29,14 @@
MirrorSystem.getSymbol('_libraryGetter', lm),
MirrorSystem.getSymbol('_librarySetter=', lm),
MirrorSystem.getSymbol('_libraryMethod', lm),
- #Predicate,
- #Superclass,
- #Interface,
- #Mixin,
- #Class,
- MirrorSystem.getSymbol('_PrivateClass', lm),
- #ConcreteClass],
+ #Predicate, /// 01: ok
+ #Superclass, /// 01: continued
+ #Interface, /// 01: continued
+ #Mixin, /// 01: continued
+ #Class, /// 01: continued
+ MirrorSystem.getSymbol('_PrivateClass', lm), /// 01: continued
+ #ConcreteClass /// 01: continued
+ ],
selectKeys(lm.topLevelMembers, (dm) => true));
Expect.setEquals(
@@ -43,12 +44,13 @@
const Symbol('libraryVariable='),
MirrorSystem.getSymbol('_libraryVariable', lm),
MirrorSystem.getSymbol('_libraryVariable=', lm),
- #Predicate,
- #Superclass,
- #Interface,
- #Mixin,
- #Class,
- MirrorSystem.getSymbol('_PrivateClass', lm),
- #ConcreteClass],
+ #Predicate, /// 01: continued
+ #Superclass, /// 01: continued
+ #Interface, /// 01: continued
+ #Mixin, /// 01: continued
+ #Class, /// 01: continued
+ MirrorSystem.getSymbol('_PrivateClass', lm), /// 01: continued
+ #ConcreteClass /// 01: continued
+ ],
selectKeys(lm.topLevelMembers, (dm) => dm.isSynthetic));
}
diff --git a/tests/lib/mirrors/unused_mirrors_used_test.dart b/tests/lib/mirrors/unused_mirrors_used_test.dart
new file mode 100644
index 0000000..0fe1e37
--- /dev/null
+++ b/tests/lib/mirrors/unused_mirrors_used_test.dart
@@ -0,0 +1,17 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test.
+// The MirrorsUsed annotation made dart2js to mark List as needed for reflection
+// but tree-shaking wasn't turned off (since there is no actual mirror use)
+// which led to a broken output.
+
+@MirrorsUsed(targets: "List")
+import 'dart:mirrors';
+
+void main() {
+ var l = new List<int>();
+ var f = l.retainWhere;
+ f((x) => true);
+}
diff --git a/tests/standalone/io/file_copy_test.dart b/tests/standalone/io/file_copy_test.dart
new file mode 100644
index 0000000..2ef7358
--- /dev/null
+++ b/tests/standalone/io/file_copy_test.dart
@@ -0,0 +1,86 @@
+// 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.
+//
+// Dart test program for testing File.copy*
+
+import 'dart:io';
+
+import "package:expect/expect.dart";
+import "package:async_helper/async_helper.dart";
+
+const FILE_CONTENT1 = 'some string';
+const FILE_CONTENT2 = 'some other string';
+
+void testCopySync() {
+ var tmp = Directory.systemTemp.createTempSync('dart-file-copy');
+
+ var file1 = new File('${tmp.path}/file1');
+ file1.writeAsStringSync(FILE_CONTENT1);
+ Expect.equals(FILE_CONTENT1, file1.readAsStringSync());
+
+ // Copy to new file works.
+ var file2 = file1.copySync('${tmp.path}/file2');
+ Expect.equals(FILE_CONTENT1, file1.readAsStringSync());
+ Expect.equals(FILE_CONTENT1, file2.readAsStringSync());
+
+ // Override works for files.
+ file2.writeAsStringSync(FILE_CONTENT2);
+ file2.copySync(file1.path);
+ Expect.equals(FILE_CONTENT2, file1.readAsStringSync());
+ Expect.equals(FILE_CONTENT2, file2.readAsStringSync());
+
+ // Fail when coping to directory.
+ var dir = new Directory('${tmp.path}/dir')..createSync();
+ Expect.throws(() => file1.copySync(dir.path));
+ Expect.equals(FILE_CONTENT2, file1.readAsStringSync());
+
+ tmp.deleteSync(recursive: true);
+}
+
+
+void testCopy() {
+ asyncStart();
+ var tmp = Directory.systemTemp.createTempSync('dart-file-copy');
+
+ var file1 = new File('${tmp.path}/file1');
+ file1.writeAsStringSync(FILE_CONTENT1);
+ Expect.equals(FILE_CONTENT1, file1.readAsStringSync());
+
+ // Copy to new file works.
+ file1.copy('${tmp.path}/file2')
+ .then((file2) {
+ Expect.equals(FILE_CONTENT1, file1.readAsStringSync());
+ Expect.equals(FILE_CONTENT1, file2.readAsStringSync());
+
+ // Override works for files.
+ file2.writeAsStringSync(FILE_CONTENT2);
+ return file2.copy(file1.path)
+ .then((_) {
+ Expect.equals(FILE_CONTENT2, file1.readAsStringSync());
+ Expect.equals(FILE_CONTENT2, file2.readAsStringSync());
+
+ // Fail when coping to directory.
+ var dir = new Directory('${tmp.path}/dir')..createSync();
+
+ return file1.copy(dir.path)
+ .then((_) => Expect.fail('expected error'),
+ onError: (_) {})
+ .then((_) {
+ Expect.equals(FILE_CONTENT2, file1.readAsStringSync());
+ });
+
+ });
+ })
+ .whenComplete(() {
+ tmp.deleteSync(recursive: true);
+ asyncEnd();
+ });
+
+}
+
+
+main() {
+ testCopySync();
+ testCopy();
+}
diff --git a/tests/standalone/io/internet_address_invalid_arguments_test.dart b/tests/standalone/io/internet_address_invalid_arguments_test.dart
new file mode 100644
index 0000000..59610e1
--- /dev/null
+++ b/tests/standalone/io/internet_address_invalid_arguments_test.dart
@@ -0,0 +1,21 @@
+// 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:io';
+
+import "package:expect/expect.dart";
+
+void testIllegalArguments() {
+ var args = [
+ null, 1, 1.1, new Object(), [], {'a' : '127.0.0.1'},
+ "", "." , ":", ":::"];
+ args.forEach((arg) {
+ Expect.throws(() => new InternetAddress(arg),
+ (e) => e is ArgumentError);
+ });
+}
+
+void main() {
+ testIllegalArguments();
+}
diff --git a/tests/standalone/io/raw_datagram_socket_test.dart b/tests/standalone/io/raw_datagram_socket_test.dart
index 6f3ebef..86fb5e4 100644
--- a/tests/standalone/io/raw_datagram_socket_test.dart
+++ b/tests/standalone/io/raw_datagram_socket_test.dart
@@ -25,7 +25,9 @@
RawDatagramSocket.bind(address, 0).then((socket) {
Expect.isFalse(socket.broadcastEnabled);
socket.broadcastEnabled = true;
- Expect.isTrue(socket.broadcastEnabled);
+ if (!Platform.isMacOS) {
+ Expect.isTrue(socket.broadcastEnabled);
+ }
socket.broadcastEnabled = false;
Expect.isFalse(socket.broadcastEnabled);
asyncEnd();
@@ -177,8 +179,10 @@
test(InternetAddress.ANY_IP_V4, new InternetAddress("228.0.0.4"), true);
test(InternetAddress.ANY_IP_V4, new InternetAddress("224.0.0.0"), false);
- test(InternetAddress.ANY_IP_V6, new InternetAddress("ff11::0"), true);
- test(InternetAddress.ANY_IP_V6, new InternetAddress("ff11::0"), false);
+ if (!Platform.isMacOS) {
+ test(InternetAddress.ANY_IP_V6, new InternetAddress("ff11::0"), true);
+ test(InternetAddress.ANY_IP_V6, new InternetAddress("ff11::0"), false);
+ }
}
testSendReceive(InternetAddress bindAddress) {
@@ -297,7 +301,9 @@
main() {
testDatagramBroadcastOptions();
testDatagramMulticastOptions();
- testDatagramSocketReuseAddress();
+ if (!Platform.isMacOS) {
+ testDatagramSocketReuseAddress();
+ }
testBroadcast();
testLoopbackMulticast();
testSendReceive(InternetAddress.LOOPBACK_IP_V4);
diff --git a/tests/standalone/io/signals_test.dart b/tests/standalone/io/signals_test.dart
new file mode 100644
index 0000000..00805a5
--- /dev/null
+++ b/tests/standalone/io/signals_test.dart
@@ -0,0 +1,64 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:io";
+
+import "package:expect/expect.dart";
+import "package:async_helper/async_helper.dart";
+
+void testSignals(int usr1Expect,
+ int usr2Expect,
+ [int usr1Send,
+ int usr2Send,
+ bool shouldFail = false]) {
+ if (usr1Send == null) usr1Send = usr1Expect;
+ if (usr2Send == null) usr2Send = usr2Expect;
+ asyncStart();
+ Process.start(Platform.executable,
+ [Platform.script.resolve('signals_test_script.dart').toFilePath(),
+ usr1Expect.toString(),
+ usr2Expect.toString()])
+ .then((process) {
+ process.stdin.close();
+ process.stderr.drain();
+ int v = 0;
+ process.stdout.listen((out) {
+ // Send as many signals as 'ready\n' received on stdout
+ int count = out.where((c) => c == '\n'.codeUnitAt(0)).length;
+ for (int i = 0; i < count; i++) {
+ if (v < usr1Send) {
+ process.kill(ProcessSignal.SIGUSR1);
+ } else if (v < usr1Send + usr2Send) {
+ process.kill(ProcessSignal.SIGUSR2);
+ }
+ v++;
+ }
+ });
+ process.exitCode.then((exitCode) {
+ Expect.equals(shouldFail, exitCode != 0);
+ asyncEnd();
+ });
+ });
+}
+
+
+void testListenCancel() {
+ for (int i = 0; i < 10; i++) {
+ ProcessSignal.SIGINT.watch().listen(null).cancel();
+ }
+}
+
+void main() {
+ testListenCancel();
+ if (Platform.isWindows) return;
+ testSignals(0, 0);
+ testSignals(1, 0);
+ testSignals(0, 1);
+ testSignals(1, 1);
+ testSignals(10, 10);
+ testSignals(10, 1);
+ testSignals(1, 10);
+ testSignals(1, 0, 0, 1, true);
+ testSignals(0, 1, 1, 0, true);
+}
diff --git a/tests/standalone/io/signals_test_script.dart b/tests/standalone/io/signals_test_script.dart
new file mode 100644
index 0000000..5a2c7bc
--- /dev/null
+++ b/tests/standalone/io/signals_test_script.dart
@@ -0,0 +1,31 @@
+// 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:io";
+
+void main(args) {
+ int usr1Count = int.parse(args[0]);
+ int usr2Count = int.parse(args[1]);
+ var sub1;
+ var sub2;
+ void check() {
+ if (usr1Count < 0 || usr2Count < 0) exit(1);
+ if (usr1Count == 0 && usr2Count == 0) {
+ sub1.cancel();
+ sub2.cancel();
+ }
+ print("ready");
+ }
+ sub1 = ProcessSignal.SIGUSR1.watch().listen((signal) {
+ if (signal != ProcessSignal.SIGUSR1) exit(1);
+ usr1Count--;
+ check();
+ });
+ sub2 = ProcessSignal.SIGUSR2.watch().listen((signal) {
+ if (signal != ProcessSignal.SIGUSR2) exit(1);
+ usr2Count--;
+ check();
+ });
+ check();
+}
diff --git a/tests/standalone/io/skipping_dart2js_compilations_test.dart b/tests/standalone/io/skipping_dart2js_compilations_test.dart
index 95ae623..55ef68b 100644
--- a/tests/standalone/io/skipping_dart2js_compilations_test.dart
+++ b/tests/standalone/io/skipping_dart2js_compilations_test.dart
@@ -160,8 +160,7 @@
false,
bootstrapDeps,
executable,
- arguments,
- 'ReleaseIA32');
+ arguments, {});
}
void main() {
diff --git a/tests/standalone/io/stdin_sync_test.dart b/tests/standalone/io/stdin_sync_test.dart
index 03e794c..97c4b58 100644
--- a/tests/standalone/io/stdin_sync_test.dart
+++ b/tests/standalone/io/stdin_sync_test.dart
@@ -44,6 +44,7 @@
test("hej", ['hej']);
}
+
void testEchoMode() {
stdin.echoMode = true;
Expect.isTrue(stdin.echoMode);
@@ -55,6 +56,7 @@
}
}
+
void testLineMode() {
stdin.lineMode = true;
Expect.isTrue(stdin.lineMode);
@@ -70,7 +72,7 @@
void main() {
testReadByte();
- // testEchoMode and testLineMode is an developer-interactive test, thus not
+ // testEchoMode and testLineMode is developer-interactive tests, thus not
// enabled.
//testEchoMode();
//testLineMode();
diff --git a/tests/standalone/io/stdout_test.dart b/tests/standalone/io/stdout_test.dart
new file mode 100644
index 0000000..57a7e1c
--- /dev/null
+++ b/tests/standalone/io/stdout_test.dart
@@ -0,0 +1,22 @@
+// 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:io";
+
+import "package:expect/expect.dart";
+
+void testTerminalSize() {
+ if (stdout.hasTerminal) {
+ Expect.notEquals(0, stdout.terminalColumns);
+ Expect.notEquals(0, stdout.terminalLines);
+ } else {
+ Expect.throws(() => stdout.terminalColumns, (e) => e is StdoutException);
+ Expect.throws(() => stdout.terminalLines, (e) => e is StdoutException);
+ }
+}
+
+
+void main() {
+ testTerminalSize();
+}
diff --git a/tests/standalone/io/test_runner_test.dart b/tests/standalone/io/test_runner_test.dart
index 4b2fe2a..61e762b 100644
--- a/tests/standalone/io/test_runner_test.dart
+++ b/tests/standalone/io/test_runner_test.dart
@@ -82,16 +82,16 @@
}
TestCase _makeNormalTestCase(name, expectations) {
- var command = CommandBuilder.instance.getCommand(
+ var command = CommandBuilder.instance.getProcessCommand(
'custom', Platform.executable, [Platform.script.toFilePath(), name],
- 'ReleaseIA32');
+ {});
return _makeTestCase(name, DEFAULT_TIMEOUT, command, expectations);
}
_makeCrashTestCase(name, expectations) {
- var crashCommand = CommandBuilder.instance.getCommand(
+ var crashCommand = CommandBuilder.instance.getProcessCommand(
'custom_crash', getProcessTestFileName(), ["0", "0", "1", "1"],
- 'ReleaseIA32');
+ {});
// The crash test sometimes times out. Run it with a large timeout
// to help diagnose the delay.
// The test loads a new executable, which may sometimes take a long time.
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index fcab8b1..6cc81d2 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -19,6 +19,7 @@
io/process_invalid_arguments_test: Fail, OK
io/directory_invalid_arguments_test: Fail, OK
io/file_invalid_arguments_test: Fail, OK
+io/internet_address_invalid_arguments_test: Fail, OK
io/socket_invalid_arguments_test: Fail, OK
io/stdout_bad_argument_test: Fail, OK
# These test have type errors on purpose and take very long to run in
@@ -31,9 +32,6 @@
# This is expected as MacOS by default runs with a very low number
# of allowed open files ('ulimit -n' says something like 256).
io/socket_many_connections_test: Skip
-# The UDP tests are currently skipped on Mac OS as multicast configuration
-# needs to be resolved.
-io/raw_datagram_socket_test: Skip # Issue 1975
[ $compiler == none && ($runtime == drt || $runtime == dartium) ]
typed_array_test: Fail # Issue 13921
diff --git a/tests/standalone/vmservice/isolate_bad_class_test.dart b/tests/standalone/vmservice/isolate_bad_class_test.dart
index 8e0b2d3..1b6c0ca 100644
--- a/tests/standalone/vmservice/isolate_bad_class_test.dart
+++ b/tests/standalone/vmservice/isolate_bad_class_test.dart
@@ -22,7 +22,7 @@
super('http://127.0.0.1:$port/isolates/$id/$collection');
onRequestCompleted(Map reply) {
- Expect.equals('error', reply['type']);
+ Expect.equals('Error', reply['type']);
}
}
diff --git a/tests/standalone/vmservice/isolate_bad_object_test.dart b/tests/standalone/vmservice/isolate_bad_object_test.dart
index b7d2ef5..314c608 100644
--- a/tests/standalone/vmservice/isolate_bad_object_test.dart
+++ b/tests/standalone/vmservice/isolate_bad_object_test.dart
@@ -22,7 +22,7 @@
super('http://127.0.0.1:$port/isolates/$id/objects');
onRequestCompleted(Map reply) {
- Expect.equals('error', reply['type']);
+ Expect.equals('Error', reply['type']);
}
}
diff --git a/tests/standalone/vmservice/test_helper.dart b/tests/standalone/vmservice/test_helper.dart
index 94c8ab8..b584a86 100644
--- a/tests/standalone/vmservice/test_helper.dart
+++ b/tests/standalone/vmservice/test_helper.dart
@@ -9,6 +9,47 @@
import 'dart:io';
import 'package:expect/expect.dart';
+abstract class ServiceWebSocketRequestHelper {
+ final String url;
+ final Completer _completer = new Completer();
+ WebSocket _socket;
+
+ ServiceWebSocketRequestHelper(this.url);
+
+ // Returns [this] when connected.
+ Future connect() {
+ return WebSocket.connect(url).then((ws) {
+ _socket = ws;
+ _socket.listen((message) {
+ var map = JSON.decode(message);
+ var response = JSON.decode(map['response']);
+ onResponse(map['seq'], response);
+ });
+ return this;
+ });
+ }
+
+ void complete() {
+ _completer.complete(this);
+ }
+
+ Future get completed => _completer.future;
+
+ // Must call complete.
+ void onResponse(var seq, Map response);
+ void runTest();
+
+ Future sendMessage(var seq, List<String> path) {
+ var map = {
+ 'seq': seq,
+ 'path': path
+ };
+ var message = JSON.encode(map);
+ _socket.add(message);
+ return _completer.future;
+ }
+}
+
abstract class VmServiceRequestHelper {
final Uri uri;
final HttpClient client;
@@ -99,7 +140,7 @@
var first = true;
process.stdout.transform(UTF8.decoder)
.transform(new LineSplitter()).listen((line) {
- if (line.startsWith('VmService listening on port ')) {
+ if (line.startsWith('VMService listening on port ')) {
RegExp portExp = new RegExp(r"\d+");
var port = portExp.stringMatch(line);
portNumber = int.parse(port);
diff --git a/tests/standalone/vmservice/websocket_client_test.dart b/tests/standalone/vmservice/websocket_client_test.dart
new file mode 100644
index 0000000..97f4492
--- /dev/null
+++ b/tests/standalone/vmservice/websocket_client_test.dart
@@ -0,0 +1,49 @@
+// 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 unknown_command_test;
+
+import 'test_helper.dart';
+import 'package:expect/expect.dart';
+
+class ClientsRequestTest extends ServiceWebSocketRequestHelper {
+ ClientsRequestTest(port) : super('ws://127.0.0.1:$port/ws');
+ int _count = 0;
+
+ onResponse(var seq, Map response) {
+ if (seq == 'cli') {
+ // Verify response is correct for 'cli' sequence id.
+ Expect.equals('ClientList', response['type']);
+ Expect.equals(1, response['members'].length);
+ _count++;
+ } else if (seq == 'iso') {
+ // Verify response is correct for 'iso' sequence id.
+ Expect.equals('IsolateList', response['type']);
+ _count++;
+ }
+ if (_count == 2) {
+ // After receiving both responses, the test is complete.
+ complete();
+ }
+ }
+
+ runTest() {
+ // Send a request for clients with 'cli' sequence id.
+ sendMessage('cli', ['clients']);
+ // Send a request for isolates with 'iso' sequence id.
+ sendMessage('iso', ['isolates']);
+ }
+}
+
+main() {
+ var process = new TestLauncher('unknown_command_script.dart');
+ process.launch().then((port) {
+ new ClientsRequestTest(port).connect().then((test) {
+ test.completed.then((_) {
+ process.requestExit();
+ });
+ test.runTest();
+ });
+ });
+}
\ No newline at end of file
diff --git a/tools/VERSION b/tools/VERSION
index 575e350..64ffd99 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
MAJOR 1
MINOR 1
PATCH 0
-PRERELEASE 4
+PRERELEASE 5
PRERELEASE_PATCH 0
diff --git a/tools/bots/compiler.py b/tools/bots/compiler.py
index 7087a31..fd4880a 100644
--- a/tools/bots/compiler.py
+++ b/tools/bots/compiler.py
@@ -33,6 +33,8 @@
'windows' : [
{'runtime' : 'ie9'},
{'runtime' : 'ie9', 'additional_flags' : ['--checked']},
+ {'runtime' : 'ff'},
+ {'runtime' : 'chrome'},
],
}
diff --git a/tools/create_sdk.py b/tools/create_sdk.py
index 97b14a4..5261e71 100755
--- a/tools/create_sdk.py
+++ b/tools/create_sdk.py
@@ -195,7 +195,6 @@
for library in [join('_chrome', 'dart2js'), join('_chrome', 'dartium'),
join('_internal', 'compiler'),
join('_internal', 'dartdoc'),
- join('_internal', 'pub', 'resource'),
join('_internal', 'lib'),
'async', 'collection', '_collection_dev', 'convert',
'core', 'crypto', 'io', 'isolate',
@@ -231,8 +230,10 @@
# Copy in 7zip for Windows.
if HOST_OS == 'win32':
+ RESOURCE = join(SDK_tmp, 'lib', '_internal', 'pub', 'resource')
+ os.makedirs(RESOURCE)
copytree(join(HOME, 'third_party', '7zip'),
- join(SDK_tmp, 'lib', '_internal', 'pub', 'resource', '7zip'),
+ join(RESOURCE, '7zip'),
ignore=ignore_patterns('.svn'))
# Copy dart2js/dartdoc/pub.
diff --git a/tools/ddbg.dart b/tools/ddbg.dart
index 7e53ab6..504d67b 100644
--- a/tools/ddbg.dart
+++ b/tools/ddbg.dart
@@ -78,11 +78,27 @@
bool checkCurrentIsolate() {
- if (currentIsolate != null) {
- return true;
+ if (vmSock == null) {
+ print("There is no active script. Try 'help run'.");
+ return false;
}
- print("Need valid current isolate");
- return false;
+ if (currentIsolate == null) {
+ print('There is no current isolate.');
+ return false;
+ }
+ return true;
+}
+
+
+void setCurrentIsolate(TargetIsolate isolate) {
+ if (isolate != currentIsolate) {
+ currentIsolate = isolate;
+ if (mainIsolate == null) {
+ print("Main isolate is ${isolate.id}");
+ mainIsolate = isolate;
+ }
+ print("Current isolate is now ${isolate.id}");
+ }
}
@@ -526,22 +542,37 @@
var resume_commands =
{ 'r':'resume', 's':'stepOver', 'si':'stepInto', 'so':'stepOut'};
if (resume_commands[command] != null) {
- if (!checkPaused()) return;
+ if (!checkPaused()) {
+ cmdo.show();
+ return;
+ }
var cmd = { "id": seqNum,
"command": resume_commands[command],
"params": { "isolateId" : currentIsolate.id } };
sendCmd(cmd).then(showPromptAfter(handleResumedResponse));
} else if (command == "bt") {
+ if (!checkCurrentIsolate()) {
+ cmdo.show();
+ return;
+ }
var cmd = { "id": seqNum,
"command": "getStackTrace",
"params": { "isolateId" : currentIsolate.id } };
sendCmd(cmd).then(showPromptAfter(handleStackTraceResponse));
} else if (command == "ll") {
+ if (!checkCurrentIsolate()) {
+ cmdo.show();
+ return;
+ }
var cmd = { "id": seqNum,
"command": "getLibraries",
"params": { "isolateId" : currentIsolate.id } };
sendCmd(cmd).then(showPromptAfter(handleGetLibraryResponse));
} else if (command == "sbp" && args.length >= 2) {
+ if (!checkCurrentIsolate()) {
+ cmdo.show();
+ return;
+ }
var url, line;
if (args.length == 2 && currentIsolate.pausedLocation != null) {
url = currentIsolate.pausedLocation["url"];
@@ -558,18 +589,30 @@
"line": line }};
sendCmd(cmd).then(showPromptAfter(handleSetBpResponse));
} else if (command == "rbp" && args.length == 2) {
+ if (!checkCurrentIsolate()) {
+ cmdo.show();
+ return;
+ }
var cmd = { "id": seqNum,
"command": "removeBreakpoint",
"params": { "isolateId" : currentIsolate.id,
"breakpointId": int.parse(args[1]) } };
sendCmd(cmd).then(showPromptAfter(handleGenericResponse));
} else if (command == "ls" && args.length == 2) {
+ if (!checkCurrentIsolate()) {
+ cmdo.show();
+ return;
+ }
var cmd = { "id": seqNum,
"command": "getScriptURLs",
"params": { "isolateId" : currentIsolate.id,
"libraryId": int.parse(args[1]) } };
sendCmd(cmd).then(showPromptAfter(handleGetScriptsResponse));
} else if (command == "eval" && args.length > 3) {
+ if (!checkCurrentIsolate()) {
+ cmdo.show();
+ return;
+ }
var expr = args.getRange(3, args.length).join(" ");
var target = args[1];
if (target == "obj") {
@@ -589,12 +632,20 @@
"expression": expr } };
sendCmd(cmd).then(showPromptAfter(handleEvalResponse));
} else if (command == "po" && args.length == 2) {
+ if (!checkCurrentIsolate()) {
+ cmdo.show();
+ return;
+ }
var cmd = { "id": seqNum,
"command": "getObjectProperties",
"params": { "isolateId" : currentIsolate.id,
"objectId": int.parse(args[1]) } };
sendCmd(cmd).then(showPromptAfter(handleGetObjPropsResponse));
} else if (command == "pl" && args.length >= 3) {
+ if (!checkCurrentIsolate()) {
+ cmdo.show();
+ return;
+ }
var cmd;
if (args.length == 3) {
cmd = { "id": seqNum,
@@ -612,18 +663,30 @@
}
sendCmd(cmd).then(showPromptAfter(handleGetListResponse));
} else if (command == "pc" && args.length == 2) {
+ if (!checkCurrentIsolate()) {
+ cmdo.show();
+ return;
+ }
var cmd = { "id": seqNum,
"command": "getClassProperties",
"params": { "isolateId" : currentIsolate.id,
"classId": int.parse(args[1]) } };
sendCmd(cmd).then(showPromptAfter(handleGetClassPropsResponse));
} else if (command == "plib" && args.length == 2) {
+ if (!checkCurrentIsolate()) {
+ cmdo.show();
+ return;
+ }
var cmd = { "id": seqNum,
"command": "getLibraryProperties",
"params": {"isolateId" : currentIsolate.id,
"libraryId": int.parse(args[1]) } };
sendCmd(cmd).then(showPromptAfter(handleGetLibraryPropsResponse));
} else if (command == "slib" && args.length == 3) {
+ if (!checkCurrentIsolate()) {
+ cmdo.show();
+ return;
+ }
var cmd = { "id": seqNum,
"command": "setLibraryProperties",
"params": {"isolateId" : currentIsolate.id,
@@ -631,12 +694,20 @@
"debuggingEnabled": args[2] } };
sendCmd(cmd).then(showPromptAfter(handleSetLibraryPropsResponse));
} else if (command == "pg" && args.length == 2) {
+ if (!checkCurrentIsolate()) {
+ cmdo.show();
+ return;
+ }
var cmd = { "id": seqNum,
"command": "getGlobalVariables",
"params": { "isolateId" : currentIsolate.id,
"libraryId": int.parse(args[1]) } };
sendCmd(cmd).then(showPromptAfter(handleGetGlobalVarsResponse));
} else if (command == "gs" && args.length == 3) {
+ if (!checkCurrentIsolate()) {
+ cmdo.show();
+ return;
+ }
var cmd = { "id": seqNum,
"command": "getScriptSource",
"params": { "isolateId" : currentIsolate.id,
@@ -644,6 +715,10 @@
"url": args[2] } };
sendCmd(cmd).then(showPromptAfter(handleGetSourceResponse));
} else if (command == "tok" && args.length == 3) {
+ if (!checkCurrentIsolate()) {
+ cmdo.show();
+ return;
+ }
var cmd = { "id": seqNum,
"command": "getLineNumberTable",
"params": { "isolateId" : currentIsolate.id,
@@ -651,19 +726,26 @@
"url": args[2] } };
sendCmd(cmd).then(showPromptAfter(handleGetLineTableResponse));
} else if (command == "epi" && args.length == 2) {
+ if (!checkCurrentIsolate()) {
+ cmdo.show();
+ return;
+ }
var cmd = { "id": seqNum,
"command": "setPauseOnException",
"params": { "isolateId" : currentIsolate.id,
"exceptions": args[1] } };
sendCmd(cmd).then(showPromptAfter(handleGenericResponse));
} else if (command == "li") {
+ if (!checkCurrentIsolate()) {
+ cmdo.show();
+ return;
+ }
var cmd = { "id": seqNum, "command": "getIsolateIds" };
sendCmd(cmd).then(showPromptAfter(handleGetIsolatesResponse));
} else if (command == "sci" && args.length == 2) {
var id = int.parse(args[1]);
if (targetIsolates[id] != null) {
- currentIsolate = targetIsolates[id];
- print("Setting current target isolate to $id");
+ setCurrentIsolate(targetIsolates[id]);
} else {
print("$id is not a valid isolate id");
}
@@ -1027,6 +1109,7 @@
assert(!isolate.isPaused);
var location = msg["params"]["location"];;
assert(location != null);
+ setCurrentIsolate(isolate);
isolate.pausedLocation = location;
if (reason == "breakpoint") {
var bpId = (msg["params"]["breakpointId"]);
@@ -1052,11 +1135,6 @@
print("Isolate $isolateId has been created.");
assert(targetIsolates[isolateId] == null);
targetIsolates[isolateId] = new TargetIsolate(isolateId);
- if (mainIsolate == null) {
- mainIsolate = targetIsolates[isolateId];
- currentIsolate = mainIsolate;
- print("Current isolate set to ${currentIsolate.id}.");
- }
} else {
assert(reason == "shutdown");
var isolate = targetIsolates.remove(isolateId);
@@ -1070,7 +1148,7 @@
if (isolate == currentIsolate) {
currentIsolate = mainIsolate;
if (currentIsolate == null && !targetIsolates.isEmpty) {
- currentIsolate = targetIsolates.first;
+ currentIsolate = targetIsolates.values.first;
}
if (currentIsolate != null) {
print("Setting current isolate to ${currentIsolate.id}.");
diff --git a/tools/dom/scripts/systemnative.py b/tools/dom/scripts/systemnative.py
index 6871269..e016f3f 100644
--- a/tools/dom/scripts/systemnative.py
+++ b/tools/dom/scripts/systemnative.py
@@ -1078,8 +1078,10 @@
cpp_callback_name = '%s%s' % (idl_name, native_suffix)
self._cpp_resolver_emitter.Emit(
- ' if (argumentCount == $ARGC && name == "$NATIVE_BINDING")\n'
- ' return Dart$(INTERFACE_NAME)Internal::$CPP_CALLBACK_NAME;\n',
+ ' if (argumentCount == $ARGC && name == "$NATIVE_BINDING") {\n'
+ ' *autoSetupScope = true;\n'
+ ' return Dart$(INTERFACE_NAME)Internal::$CPP_CALLBACK_NAME;\n'
+ ' }\n',
ARGC=argument_count,
NATIVE_BINDING=native_binding,
INTERFACE_NAME=self._interface.id,
@@ -1181,7 +1183,7 @@
path = os.path.relpath(header_file, output_dir)
includes_emitter.Emit('#include "$PATH"\n', PATH=path)
body_emitter.Emit(
- ' if (Dart_NativeFunction func = $CLASS_NAME::resolver(name, argumentCount))\n'
+ ' if (Dart_NativeFunction func = $CLASS_NAME::resolver(name, argumentCount, autoSetupScope))\n'
' return func;\n',
CLASS_NAME=os.path.splitext(os.path.basename(path))[0])
diff --git a/tools/dom/templates/html/dartium/cpp_header.template b/tools/dom/templates/html/dartium/cpp_header.template
index d3e9582..a8a0340 100644
--- a/tools/dom/templates/html/dartium/cpp_header.template
+++ b/tools/dom/templates/html/dartium/cpp_header.template
@@ -39,7 +39,7 @@
return returnToDart(args, value.get());
}
- static Dart_NativeFunction resolver(Dart_Handle name, int argumentCount);
+ static Dart_NativeFunction resolver(Dart_Handle name, int argumentCount, bool* autoSetupScope);
};
Dart_Handle $(WEBCORE_CLASS_NAME_ESCAPED)_toDart(PassRefPtr< $WEBCORE_CLASS_NAME > value);
diff --git a/tools/dom/templates/html/dartium/cpp_implementation.template b/tools/dom/templates/html/dartium/cpp_implementation.template
index 15eaa70..9f978790 100644
--- a/tools/dom/templates/html/dartium/cpp_implementation.template
+++ b/tools/dom/templates/html/dartium/cpp_implementation.template
@@ -19,7 +19,7 @@
$CALLBACKS
}
-Dart_NativeFunction Dart$(INTERFACE)::resolver(Dart_Handle nameHandle, int argumentCount)
+Dart_NativeFunction Dart$(INTERFACE)::resolver(Dart_Handle nameHandle, int argumentCount, bool* autoSetupScope)
{
String name = DartUtilities::toString(nameHandle);
diff --git a/tools/dom/templates/html/dartium/cpp_resolver.template b/tools/dom/templates/html/dartium/cpp_resolver.template
index 2a021c1..9b6eaf8 100644
--- a/tools/dom/templates/html/dartium/cpp_resolver.template
+++ b/tools/dom/templates/html/dartium/cpp_resolver.template
@@ -10,7 +10,7 @@
namespace WebCore {
-Dart_NativeFunction $(LIBRARY_NAME)SnapshotResolver(Dart_Handle name, int argumentCount)
+Dart_NativeFunction $(LIBRARY_NAME)SnapshotResolver(Dart_Handle name, int argumentCount, bool* autoSetupScope)
{
$!RESOLVER_BODY
return 0;
diff --git a/tools/gyp/configurations_make.gypi b/tools/gyp/configurations_make.gypi
index 73d7350..6ffc920 100644
--- a/tools/gyp/configurations_make.gypi
+++ b/tools/gyp/configurations_make.gypi
@@ -93,6 +93,9 @@
'-O<(dart_debug_optimization_level)',
# The sampling profiler uses the frame pointer to walk the stack.
'-fno-omit-frame-pointer',
+ # Clang on Linux will still omit frame pointers from leaf functions
+ # unless told otherwise:
+ # '-mno-omit-leaf-frame-pointer',
],
},
@@ -101,6 +104,9 @@
'-O3',
# The sampling profiler uses the frame pointer to walk the stack.
'-fno-omit-frame-pointer',
+ # Clang on Linux will still omit frame pointers from leaf functions
+ # unless told otherwise:
+ # '-mno-omit-leaf-frame-pointer',
],
},
},
diff --git a/tools/testing/dart/co19_test.dart b/tools/testing/dart/co19_test.dart
index e793344..a55f0a7 100644
--- a/tools/testing/dart/co19_test.dart
+++ b/tools/testing/dart/co19_test.dart
@@ -19,14 +19,10 @@
import "dart:io";
import "test_options.dart";
-import "test_progress.dart";
-import "test_runner.dart";
import "test_suite.dart";
import "utils.dart" show Path;
import "../../test.dart" as test_dart;
-import "../../../tests/co19/test_config.dart";
-
const List<String> COMMON_ARGUMENTS =
const <String>['--report', '--progress=diff', 'co19'];
diff --git a/tools/testing/dart/launch_browser.dart b/tools/testing/dart/launch_browser.dart
index 269d151..66264d9 100644
--- a/tools/testing/dart/launch_browser.dart
+++ b/tools/testing/dart/launch_browser.dart
@@ -10,7 +10,6 @@
* DARTBIN should be the checked in stable binary.
*/
-import "dart:io";
import "browser_controller.dart";
import "utils.dart";
diff --git a/tools/testing/dart/record_and_replay.dart b/tools/testing/dart/record_and_replay.dart
index f60be45..5abb41c 100644
--- a/tools/testing/dart/record_and_replay.dart
+++ b/tools/testing/dart/record_and_replay.dart
@@ -55,7 +55,7 @@
_cwd = Directory.current.path;
}
- void nextCommand(Command command, int timeout) {
+ void nextCommand(ProcessCommand command, int timeout) {
// Convert arguments from absolute to relative paths (relative to the dart
// directory) because the absolute path on the machine where we record
// may be different from the absolute path on the machine where we execute
@@ -100,7 +100,7 @@
}
}
- CommandOutput outputOf(Command command) {
+ CommandOutput outputOf(ProcessCommand command) {
// Convert arguments from absolute to relative paths (relative to the dart
// directory) because the absolute path on the machine where we record
// may be different from the absolute path on the machine where we execute
diff --git a/tools/testing/dart/test_runner.dart b/tools/testing/dart/test_runner.dart
index 38f500b..8792355 100644
--- a/tools/testing/dart/test_runner.dart
+++ b/tools/testing/dart/test_runner.dart
@@ -45,49 +45,23 @@
/** A command executed as a step in a test case. */
class Command {
- /** Path to the executable of this command. */
- String executable;
+ /** A descriptive name for this command. */
+ String displayName;
/** The actual command line that will be executed. */
String commandLine;
- /** A descriptive name for this command. */
- String displayName;
-
- /** Command line arguments to the executable. */
- List<String> arguments;
-
- /** Environment for the command */
- Map<String, String> environmentOverrides;
-
/** Number of times this command *can* be retried */
int get maxNumRetries => 2;
+ /** Reproduction command */
+ String get reproductionCommand => null;
+
// We compute the Command.hashCode lazily and cache it here, since it might
// be expensive to compute (and hashCode is called often).
int _cachedHashCode;
- Command._(this.displayName, this.executable,
- this.arguments, String configurationDir,
- [this.environmentOverrides = null]) {
- if (io.Platform.operatingSystem == 'windows') {
- // Windows can't handle the first command if it is a .bat file or the like
- // with the slashes going the other direction.
- // TODO(efortuna): Remove this when fixed (Issue 1306).
- executable = executable.replaceAll('/', '\\');
- }
- var quotedArguments = [];
- quotedArguments.add(escapeCommandLineArgument(executable));
- quotedArguments.addAll(arguments.map(escapeCommandLineArgument));
- commandLine = quotedArguments.join(' ');
-
- if (configurationDir != null) {
- if (environmentOverrides == null) {
- environmentOverrides = new Map<String, String>();
- }
- environmentOverrides['DART_CONFIGURATION'] = configurationDir;
- }
- }
+ Command._(this.displayName);
int get hashCode {
if (_cachedHashCode == null) {
@@ -106,9 +80,46 @@
}
void _buildHashCode(HashCodeBuilder builder) {
- builder.add(executable);
builder.add(commandLine);
builder.add(displayName);
+ }
+
+ bool _equal(Command other) {
+ return hashCode == other.hashCode &&
+ commandLine == other.commandLine &&
+ displayName == other.displayName;
+ }
+
+ String toString() => reproductionCommand;
+
+ Future<bool> get outputIsUpToDate => new Future.value(false);
+}
+
+class ProcessCommand extends Command {
+ /** Path to the executable of this command. */
+ String executable;
+
+ /** Command line arguments to the executable. */
+ List<String> arguments;
+
+ /** Environment for the command */
+ Map<String, String> environmentOverrides;
+
+ ProcessCommand._(String displayName, this.executable,
+ this.arguments,
+ [this.environmentOverrides = null])
+ : super._(displayName) {
+ if (io.Platform.operatingSystem == 'windows') {
+ // Windows can't handle the first command if it is a .bat file or the like
+ // with the slashes going the other direction.
+ // NOTE: Issue 1306
+ executable = executable.replaceAll('/', '\\');
+ }
+ }
+
+ void _buildHashCode(HashCodeBuilder builder) {
+ super._buildHashCode(builder);
+ builder.add(executable);
for (var object in arguments) builder.add(object);
if (environmentOverrides != null) {
for (var key in environmentOverrides.keys) {
@@ -119,45 +130,34 @@
}
bool _equal(Command other) {
- if (hashCode != other.hashCode ||
- executable != other.executable ||
- commandLine != other.commandLine ||
- displayName != other.displayName ||
- arguments.length != other.arguments.length) {
- return false;
- }
+ if (!super._equal(other)) return false;
+ if (other is ProcessCommand) {
- if ((environmentOverrides != other.environmentOverrides) &&
- (environmentOverrides == null || other.environmentOverrides == null)) {
- return false;
- }
-
- if (environmentOverrides != null &&
- environmentOverrides.length != other.environmentOverrides.length) {
- return false;
- }
-
- for (var i = 0; i < arguments.length; i++) {
- if (arguments[i] != other.arguments[i]) return false;
- }
-
- if (environmentOverrides != null) {
- for (var key in environmentOverrides.keys) {
- if (!other.environmentOverrides.containsKey(key) ||
- environmentOverrides[key] != other.environmentOverrides[key]) {
- return false;
- }
+ if (hashCode != other.hashCode ||
+ executable != other.executable ||
+ arguments.length != other.arguments.length) {
+ return false;
}
+
+ if (!deepJsonCompare(arguments, other.arguments)) return false;
+ if (!deepJsonCompare(environmentOverrides, other.environmentOverrides)) {
+ return false;
+ }
+
+ return true;
}
- return true;
+ return false;
}
- String toString() => commandLine;
+ String get reproductionCommand {
+ return ([executable]..addAll(arguments))
+ .map(escapeCommandLineArgument).join(' ');
+ }
Future<bool> get outputIsUpToDate => new Future.value(false);
}
-class CompilationCommand extends Command {
+class CompilationCommand extends ProcessCommand {
String _outputFile;
bool _neverSkipCompilation;
List<Uri> _bootstrapDependencies;
@@ -165,11 +165,11 @@
CompilationCommand._(String displayName,
this._outputFile,
this._neverSkipCompilation,
- List<String> bootstrapDependencies,
+ List<Uri> bootstrapDependencies,
String executable,
List<String> arguments,
- String configurationDir)
- : super._(displayName, executable, arguments, configurationDir) {
+ Map<String, String> environmentOverrides)
+ : super._(displayName, executable, arguments, environmentOverrides) {
// We sort here, so we can do a fast hashCode/operator==
_bootstrapDependencies = new List.from(bootstrapDependencies);
_bootstrapDependencies.sort();
@@ -240,24 +240,26 @@
}
}
-class ContentShellCommand extends Command {
+class ContentShellCommand extends ProcessCommand {
ContentShellCommand._(String executable,
String htmlFile,
List<String> options,
List<String> dartFlags,
- String configurationDir)
+ Map<String, String> environmentOverrides)
: super._("content_shell",
executable,
_getArguments(options, htmlFile),
- configurationDir,
- _getEnvironment(dartFlags));
+ _getEnvironment(environmentOverrides, dartFlags));
- static Map _getEnvironment(List<String> dartFlags) {
+ static Map _getEnvironment(Map<String, String> env, List<String> dartFlags) {
var needDartFlags = dartFlags != null && dartFlags.length > 0;
- var env = null;
if (needDartFlags) {
- env = new Map<String, String>();
+ if (env != null) {
+ env = new Map<String, String>.from(env);
+ } else {
+ env = new Map<String, String>();
+ }
env['DART_FLAGS'] = dartFlags.join(" ");
env['DART_FORWARDING_PRINT'] = '1';
}
@@ -285,12 +287,8 @@
BrowserTestCommand._(String _browser,
this.url,
- String executable,
- List<String> arguments,
- String configurationDir,
{bool this.checkedMode: false})
- : super._(_browser, executable, arguments, configurationDir),
- browser = _browser;
+ : super._(_browser), browser = _browser;
void _buildHashCode(HashCodeBuilder builder) {
super._buildHashCode(builder);
@@ -307,17 +305,25 @@
url == other.url &&
checkedMode == other.checkedMode;
}
+
+ String get reproductionCommand {
+ var parts = [TestUtils.dartTestExecutable.toString(),
+ 'tools/testing/dart/launch_browser.dart',
+ browser,
+ url];
+ return parts.map(escapeCommandLineArgument).join(' ');
+ }
}
-class AnalysisCommand extends Command {
+class AnalysisCommand extends ProcessCommand {
final String flavor;
AnalysisCommand._(this.flavor,
String displayName,
String executable,
List<String> arguments,
- String configurationDir)
- : super._(displayName, executable, arguments, configurationDir);
+ Map<String, String> environmentOverrides)
+ : super._(displayName, executable, arguments, environmentOverrides);
void _buildHashCode(HashCodeBuilder builder) {
super._buildHashCode(builder);
@@ -332,28 +338,26 @@
}
}
-class VmCommand extends Command {
+class VmCommand extends ProcessCommand {
VmCommand._(String executable,
List<String> arguments,
- String configurationDir)
- : super._("vm", executable, arguments, configurationDir);
+ Map<String,String> environmentOverrides)
+ : super._("vm", executable, arguments, environmentOverrides);
}
-class JSCommandlineCommand extends Command {
+class JSCommandlineCommand extends ProcessCommand {
JSCommandlineCommand._(String displayName,
String executable,
List<String> arguments,
- String configurationDir,
[Map<String, String> environmentOverrides = null])
: super._(displayName,
executable,
arguments,
- configurationDir,
environmentOverrides);
}
class CommandBuilder {
- static final instance = new CommandBuilder._();
+ static final CommandBuilder instance = new CommandBuilder._();
final _cachedCommands = new Map<Command, Command>();
@@ -363,64 +367,60 @@
String htmlFile,
List<String> options,
List<String> dartFlags,
- String configurationDir) {
+ Map<String, String> environment) {
ContentShellCommand command = new ContentShellCommand._(
- executable, htmlFile, options, dartFlags, configurationDir);
+ executable, htmlFile, options, dartFlags, environment);
return _getUniqueCommand(command);
}
BrowserTestCommand getBrowserTestCommand(String browser,
String url,
- String executable,
- List<String> arguments,
- String configurationDir,
{bool checkedMode: false}) {
var command = new BrowserTestCommand._(
- browser, url, executable, arguments, configurationDir,
- checkedMode: checkedMode);
+ browser, url, checkedMode: checkedMode);
return _getUniqueCommand(command);
}
CompilationCommand getCompilationCommand(String displayName,
outputFile,
neverSkipCompilation,
- List<String> bootstrapDependencies,
+ List<Uri> bootstrapDependencies,
String executable,
List<String> arguments,
- String configurationDir) {
+ Map<String, String> environment) {
var command =
- new CompilationCommand._(displayName, outputFile, neverSkipCompilation,
- bootstrapDependencies, executable, arguments,
- configurationDir);
+ new CompilationCommand._(
+ displayName, outputFile, neverSkipCompilation,
+ bootstrapDependencies, executable, arguments, environment);
return _getUniqueCommand(command);
}
AnalysisCommand getAnalysisCommand(
- String displayName, executable, arguments, String configurationDir,
+ String displayName, executable, arguments, environmentOverrides,
{String flavor: 'dartanalyzer'}) {
var command = new AnalysisCommand._(
- flavor, displayName, executable, arguments, configurationDir);
+ flavor, displayName, executable, arguments, environmentOverrides);
return _getUniqueCommand(command);
}
VmCommand getVmCommand(String executable,
List<String> arguments,
- String configurationDir) {
- var command = new VmCommand._(executable, arguments, configurationDir);
+ Map<String, String> environmentOverrides) {
+ var command = new VmCommand._(executable, arguments, environmentOverrides);
return _getUniqueCommand(command);
}
Command getJSCommandlineCommand(String displayName, executable, arguments,
- String configurationDir, [environment = null]) {
+ [environment = null]) {
var command = new JSCommandlineCommand._(displayName, executable, arguments,
- configurationDir, environment);
+ environment);
return _getUniqueCommand(command);
}
- Command getCommand(String displayName, executable, arguments,
- String configurationDir, [environment = null]) {
- var command = new Command._(displayName, executable, arguments,
- configurationDir, environment);
+ Command getProcessCommand(String displayName, executable, arguments,
+ [environment = null]) {
+ var command = new ProcessCommand._(displayName, executable, arguments,
+ environment);
return _getUniqueCommand(command);
}
@@ -516,7 +516,10 @@
return "$compiler-$runtime$checked ${mode}_$arch";
}
- List<String> get batchTestArguments => commands.last.arguments;
+ List<String> get batchTestArguments {
+ assert(commands.last is ProcessCommand);
+ return (commands.last as ProcessCommand).arguments;
+ }
bool get isFlaky {
if (expectedOutcomes.contains(Expectation.SKIP) ||
@@ -1367,7 +1370,7 @@
* be garbage collected as soon as it is done.
*/
class RunningProcess {
- Command command;
+ ProcessCommand command;
int timeout;
bool timedOut = false;
DateTime startTime;
@@ -1377,7 +1380,7 @@
bool compilationSkipped = false;
Completer<CommandOutput> completer;
- RunningProcess(Command this.command, this.timeout);
+ RunningProcess(this.command, this.timeout);
Future<CommandOutput> run() {
completer = new Completer<CommandOutput>();
@@ -1432,7 +1435,7 @@
completer.complete(commandOutput);
}
- CommandOutput _createCommandOutput(Command command, int exitCode) {
+ CommandOutput _createCommandOutput(ProcessCommand command, int exitCode) {
var commandOutput = createCommandOutput(
command,
exitCode,
@@ -1504,7 +1507,7 @@
BatchRunnerProcess();
- Future<CommandOutput> runCommand(String runnerType, Command command,
+ Future<CommandOutput> runCommand(String runnerType, ProcessCommand command,
int timeout, List<String> arguments) {
assert(_completer == null);
assert(!_currentlyRunning);
@@ -1794,10 +1797,12 @@
});
eventCondition((e) => e is dgraph.StateChangedEvent).listen((event) {
- if (event.from == dgraph.NodeState.Processing) {
- assert(FINISHED_STATES.contains(event.to));
- for (var dependendNode in event.node.neededFor) {
- _changeNodeStateIfNecessary(dependendNode);
+ if ([dgraph.NodeState.Waiting,
+ dgraph.NodeState.Processing].contains(event.from)) {
+ if (FINISHED_STATES.contains(event.to)){
+ for (var dependendNode in event.node.neededFor) {
+ _changeNodeStateIfNecessary(dependendNode);
+ }
}
}
});
@@ -1806,23 +1811,25 @@
// Called when either a new node was added or if one of it's dependencies
// changed it's state.
void _changeNodeStateIfNecessary(dgraph.Node node) {
- assert(INIT_STATES.contains(node.state));
- bool allDependenciesFinished =
- node.dependencies.every((node) => FINISHED_STATES.contains(node.state));
+ if (INIT_STATES.contains(node.state)) {
+ bool anyDependenciesUnsuccessful = node.dependencies.any(
+ (dep) => [dgraph.NodeState.Failed,
+ dgraph.NodeState.UnableToRun].contains(dep.state));
- var newState = dgraph.NodeState.Waiting;
- if (allDependenciesFinished) {
- bool allDependenciesSuccessful = node.dependencies.every(
- (dep) => dep.state == dgraph.NodeState.Successful);
-
- if (allDependenciesSuccessful) {
- newState = dgraph.NodeState.Enqueuing;
- } else {
+ var newState = dgraph.NodeState.Waiting;
+ if (anyDependenciesUnsuccessful) {
newState = dgraph.NodeState.UnableToRun;
+ } else {
+ bool allDependenciesSuccessful = node.dependencies.every(
+ (dep) => dep.state == dgraph.NodeState.Successful);
+
+ if (allDependenciesSuccessful) {
+ newState = dgraph.NodeState.Enqueuing;
+ }
}
- }
- if (node.state != newState) {
- _graph.changeState(node, newState);
+ if (node.state != newState) {
+ _graph.changeState(node, newState);
+ }
}
}
}
@@ -2113,7 +2120,7 @@
RecordingCommandExecutor(Path path)
: _recorder = new TestCaseRecorder(path);
- Future<CommandOutput> runCommand(node, Command command, int timeout) {
+ Future<CommandOutput> runCommand(node, ProcessCommand command, int timeout) {
assert(node.dependencies.length == 0);
assert(_cleanEnvironmentOverrides(command.environmentOverrides));
_recorder.nextCommand(command, timeout);
@@ -2147,7 +2154,7 @@
Future cleanup() => new Future.value();
- Future<CommandOutput> runCommand(node, Command command, int timeout) {
+ Future<CommandOutput> runCommand(node, ProcessCommand command, int timeout) {
assert(node.dependencies.length == 0);
return new Future.value(_archive.outputOf(command));
}
diff --git a/tools/testing/dart/test_suite.dart b/tools/testing/dart/test_suite.dart
index 9745387..686c6e0 100644
--- a/tools/testing/dart/test_suite.dart
+++ b/tools/testing/dart/test_suite.dart
@@ -15,7 +15,6 @@
library test_suite;
import "dart:async";
-import "dart:convert" show LineSplitter, UTF8;
import "dart:io";
import "drt_updater.dart";
import "multitest.dart";
@@ -111,8 +110,10 @@
TestSuite(this.configuration, this.suiteName);
- String get configurationDir {
- return TestUtils.configurationDir(configuration);
+ Map<String, String> get environmentOverrides {
+ return {
+ 'DART_CONFIGURATION' : TestUtils.configurationDir(configuration),
+ };
}
/**
@@ -389,8 +390,8 @@
var args = TestUtils.standardOptions(configuration);
args.add(testName);
- var command = CommandBuilder.instance.getCommand(
- 'run_vm_unittest', targetRunnerPath, args, configurationDir);
+ var command = CommandBuilder.instance.getProcessCommand(
+ 'run_vm_unittest', targetRunnerPath, args, environmentOverrides);
enqueueNewTestCase(
new TestCase(constructedName, [command], configuration, expectations));
}
@@ -739,7 +740,8 @@
var command = CommandBuilder.instance.getCompilationCommand(
compiler, "$tempDir/out.js", !useSdk,
- dart2JsBootstrapDependencies, compilerPath, args, configurationDir);
+ dart2JsBootstrapDependencies, compilerPath, args,
+ environmentOverrides);
List<Command> commands = <Command>[command];
if (info.hasCompileError) {
@@ -747,10 +749,11 @@
// error should be reported by the compilation command.
} else if (configuration['runtime'] == 'd8') {
commands.add(CommandBuilder.instance.getJSCommandlineCommand(
- "d8", d8FileName, ['$tempDir/out.js'], configurationDir));
+ "d8", d8FileName, ['$tempDir/out.js'], environmentOverrides));
} else if (configuration['runtime'] == 'jsshell') {
commands.add(CommandBuilder.instance.getJSCommandlineCommand(
- "jsshell", jsShellFileName, ['$tempDir/out.js'], configurationDir));
+ "jsshell", jsShellFileName, ['$tempDir/out.js'],
+ environmentOverrides));
}
return commands;
case 'dart2dart':
@@ -764,7 +767,7 @@
<Command>[CommandBuilder.instance.getCompilationCommand(
compiler, "$tempDir/out.dart", !useSdk,
dart2JsBootstrapDependencies, compilerPath, args,
- configurationDir)];
+ environmentOverrides)];
if (info.hasCompileError) {
// Do not attempt to run the compiled result. A compilation
// error should be reported by the compilation command.
@@ -774,7 +777,7 @@
vmArguments.addAll([
'--ignore-unrecognized-flags', '$tempDir/out.dart']);
commands.add(CommandBuilder.instance.getVmCommand(
- vmFileName, vmArguments, configurationDir));
+ vmFileName, vmArguments, environmentOverrides));
} else {
throw 'Unsupported runtime ${configuration["runtime"]} for dart2dart';
}
@@ -785,7 +788,7 @@
arguments.addAll(sharedOptions);
arguments.addAll(args);
return <Command>[CommandBuilder.instance.getVmCommand(
- dartShellFileName, arguments, configurationDir)];
+ dartShellFileName, arguments, environmentOverrides)];
case 'dartanalyzer':
case 'dart2analyzer':
@@ -800,7 +803,8 @@
List<String> arguments) {
return CommandBuilder.instance.getAnalysisCommand(
configuration['compiler'], dartShellFileName, arguments,
- configurationDir, flavor: configuration['compiler']);
+ environmentOverrides,
+ flavor: configuration['compiler']);
}
CreateTest makeTestCaseCreator(Map optionsFromFile) {
@@ -827,7 +831,6 @@
};
}
-
/**
* _createUrlPathFromFile takes a [file], which is either located in the dart
* or in the build directory, and will return a String representing
@@ -1073,16 +1076,10 @@
commandSet.add(CommandBuilder.instance.getContentShellCommand(
contentShellFilename, fullHtmlPath, contentShellOptions,
- dartFlags, configurationDir));
+ dartFlags, environmentOverrides));
} else {
- // This command is not actually run, it is used for reproducing
- // the failure.
- args = ['tools/testing/dart/launch_browser.dart',
- runtime,
- fullHtmlPath];
commandSet.add(CommandBuilder.instance.getBrowserTestCommand(
- runtime, fullHtmlPath, TestUtils.dartTestExecutable.toString(),
- args, configurationDir, checkedMode: configuration['checked']));
+ runtime, fullHtmlPath, checkedMode: configuration['checked']));
}
// Create BrowserTestCase and queue it.
@@ -1127,7 +1124,7 @@
}
return CommandBuilder.instance.getCompilationCommand(
compiler, outputFile, !useSdk,
- dart2JsBootstrapDependencies, compilerPath, args, configurationDir);
+ dart2JsBootstrapDependencies, compilerPath, args, environmentOverrides);
}
/** Helper to create a Polymer deploy command for a single HTML file. */
@@ -1141,8 +1138,8 @@
..add('--out')..add(outputDir);
if (configuration['csp']) args.add('--csp');
- return CommandBuilder.instance.getCommand(
- 'polymer_deploy', vmFileName, args, configurationDir);
+ return CommandBuilder.instance.getProcessCommand(
+ 'polymer_deploy', vmFileName, args, environmentOverrides);
}
/**
@@ -1579,123 +1576,12 @@
List<String> arguments) {
return CommandBuilder.instance.getAnalysisCommand(
configuration['compiler'], dartShellFileName, arguments,
- configurationDir, flavor: configuration['compiler']);
+ environmentOverrides, flavor: configuration['compiler']);
}
bool get listRecursively => true;
}
-class JUnitTestSuite extends TestSuite {
- String directoryPath;
- String statusFilePath;
- final String dartDir;
- String classPath;
- List<String> testClasses;
- VoidFunction doDone;
- TestExpectations testExpectations;
-
- JUnitTestSuite(Map configuration,
- String suiteName,
- String this.directoryPath,
- String this.statusFilePath)
- : super(configuration, suiteName),
- dartDir = TestUtils.dartDir().toNativePath();
-
- bool isTestFile(String filename) => filename.endsWith("Tests.java") &&
- !filename.contains('com/google/dart/compiler/vm') &&
- !filename.contains('com/google/dart/corelib/SharedTests.java');
-
- void forEachTest(TestCaseEvent onTest,
- Map testCacheIgnored,
- [VoidFunction onDone]) {
- doTest = onTest;
- doDone = onDone;
-
- if (!configuration['analyzer']) {
- // Do nothing. Asynchronously report that the suite is enqueued.
- asynchronously(doDone);
- return;
- }
- RegExp pattern = configuration['selectors']['dartc'];
- if (!pattern.hasMatch('junit_tests')) {
- asynchronously(doDone);
- return;
- }
-
- computeClassPath();
- testClasses = <String>[];
- // Do not read the status file.
- // All exclusions are hardcoded in this script, as they are in testcfg.py.
- processDirectory();
- }
-
- void processDirectory() {
- directoryPath = '$dartDir/$directoryPath';
- Directory dir = new Directory(directoryPath);
-
- dir.list(recursive: true).listen((FileSystemEntity fse) {
- if (fse is File) processFile(fse.path);
- },
- onDone: createTest);
- }
-
- void processFile(String filename) {
- if (!isTestFile(filename)) return;
-
- int index = filename.indexOf('compiler/javatests/com/google/dart');
- if (index != -1) {
- String testRelativePath =
- filename.substring(index + 'compiler/javatests/'.length,
- filename.length - '.java'.length);
- String testClass = testRelativePath.replaceAll('/', '.');
- testClasses.add(testClass);
- }
- }
-
- void createTest() {
- var sdkDir = "$buildDir/dart-sdk".trim();
- List<String> args = <String>[
- '-ea',
- '-classpath', classPath,
- '-Dcom.google.dart.sdk=$sdkDir',
- '-Dcom.google.dart.corelib.SharedTests.test_py=$dartDir/tools/test.py',
- 'org.junit.runner.JUnitCore'];
- args.addAll(testClasses);
-
- // Lengthen the timeout for JUnit tests. It is normal for them
- // to run for a few minutes.
- Map updatedConfiguration = new Map();
- configuration.forEach((key, value) {
- updatedConfiguration[key] = value;
- });
- updatedConfiguration['timeout'] *= 3;
- var command = CommandBuilder.instance.getCommand(
- 'junit_test', 'java', args, configurationDir);
- enqueueNewTestCase(
- new TestCase(suiteName,
- [command],
- updatedConfiguration,
- new Set<Expectation>.from([Expectation.PASS])));
- doDone();
- }
-
- void computeClassPath() {
- classPath =
- ['$buildDir/analyzer/util/analyzer/dart_analyzer.jar',
- '$buildDir/analyzer/dart_analyzer_tests.jar',
- // Third party libraries.
- '$dartDir/third_party/args4j/2.0.12/args4j-2.0.12.jar',
- '$dartDir/third_party/guava/r13/guava-13.0.1.jar',
- '$dartDir/third_party/rhino/1_7R3/js.jar',
- '$dartDir/third_party/hamcrest/v1_3/hamcrest-core-1.3.0RC2.jar',
- '$dartDir/third_party/hamcrest/v1_3/hamcrest-generator-1.3.0RC2.jar',
- '$dartDir/third_party/hamcrest/v1_3/hamcrest-integration-1.3.0RC2.jar',
- '$dartDir/third_party/hamcrest/v1_3/hamcrest-library-1.3.0RC2.jar',
- '$dartDir/third_party/junit/v4_8_2/junit.jar']
- .join(Platform.operatingSystem == 'windows'? ';': ':');
- }
-}
-
class LastModifiedCache {
Map<String, DateTime> _cache = <String, DateTime>{};
diff --git a/tools/testing/dart/utils.dart b/tools/testing/dart/utils.dart
index ab81b51..eacba54 100644
--- a/tools/testing/dart/utils.dart
+++ b/tools/testing/dart/utils.dart
@@ -178,7 +178,7 @@
if (location != null && location != '') {
return location;
}
- final browserLocations = const {
+ var browserLocations = {
'firefox': const {
'windows': 'C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe',
'linux': 'firefox',
@@ -205,6 +205,7 @@
'ie10': const {
'windows': 'C:\\Program Files\\Internet Explorer\\iexplore.exe'
}};
+ browserLocations['ff'] = browserLocations['firefox'];
assert(browserLocations[browserName] != null);
location = browserLocations[browserName][Platform.operatingSystem];
@@ -235,6 +236,36 @@
int get value => _value;
}
+bool deepJsonCompare(Object a, Object b) {
+ if (a == null || a is num || a is String) {
+ return a == b;
+ } else if (a is List) {
+ if (b is List) {
+ if (a.length != b.length) return false;
+
+ for (int i = 0; i < a.length; i++) {
+ if (!deepJsonCompare(a[i], b[i])) return false;
+ }
+ return true;
+ }
+ return false;
+ } else if (a is Map) {
+ if (b is Map) {
+ if (a.length != b.length) return false;
+
+ for (var key in a.keys) {
+ if (!b.containsKey(key)) return false;
+ if (!deepJsonCompare(a[key], b[key])) return false;
+ }
+ return true;
+ }
+ return false;
+ } else {
+ throw new Exception("Can't compare two non json-like objects "
+ "(a: ${a.runtimeType}, b: ${b.runtimeType})");
+ }
+}
+
class UniqueObject {
static int _nextId = 1;
final int _hashCode;
diff --git a/tools/tracemerge.dart b/tools/tracemerge.dart
new file mode 100644
index 0000000..6c7d5dd
--- /dev/null
+++ b/tools/tracemerge.dart
@@ -0,0 +1,361 @@
+// 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.
+
+// Merge multiple isolate profiler tracing dumps into one.
+
+import 'dart:convert';
+import 'dart:io';
+
+/**
+ * Sort a list using insertion sort.
+ *
+ * Insertion sort is a simple sorting algorithm. For `n` elements it does on
+ * the order of `n * log(n)` comparisons but up to `n` squared moves. The
+ * sorting is performed in-place, without using extra memory.
+ *
+ * For short lists the many moves have less impact than the simple algorithm,
+ * and it is often the favored sorting algorithm for short lists.
+ *
+ * This insertion sort is stable: Equal elements end up in the same order
+ * as they started in.
+ */
+void insertionSort(List list,
+ { int compare(a, b),
+ int start: 0,
+ int end: null }) {
+ // If the same method could have both positional and named optional
+ // parameters, this should be (list, [start, end], {compare}).
+ if (end == null) end = list.length;
+ if (compare == null) compare = Comparable.compare;
+ _insertionSort(list, compare, start, end, start + 1);
+}
+
+/**
+ * Internal helper function that assumes arguments correct.
+ *
+ * Assumes that the elements up to [sortedUntil] (not inclusive) are
+ * already sorted. The [sortedUntil] values should always be at least
+ * `start + 1`.
+ */
+void _insertionSort(List list, int compare(a, b), int start, int end,
+ int sortedUntil) {
+ for (int pos = sortedUntil; pos < end; pos++) {
+ int min = start;
+ int max = pos;
+ var element = list[pos];
+ while (min < max) {
+ int mid = min + ((max - min) >> 1);
+ int comparison = compare(element, list[mid]);
+ if (comparison < 0) {
+ max = mid;
+ } else {
+ min = mid + 1;
+ }
+ }
+ list.setRange(min + 1, pos + 1, list, min);
+ list[min] = element;
+ }
+}
+
+/** Limit below which merge sort defaults to insertion sort. */
+const int _MERGE_SORT_LIMIT = 32;
+
+/**
+ * Sorts a list, or a range of a list, using the merge sort algorithm.
+ *
+ * Merge-sorting works by splitting the job into two parts, sorting each
+ * recursively, and then merging the two sorted parts.
+ *
+ * This takes on the order of `n * log(n)` comparisons and moves to sort
+ * `n` elements, but requires extra space of about the same size as the list
+ * being sorted.
+ *
+ * This merge sort is stable: Equal elements end up in the same order
+ * as they started in.
+ */
+void mergeSort(List list, {int start: 0, int end: null, int compare(a, b)}) {
+ if (end == null) end = list.length;
+ if (compare == null) compare = Comparable.compare;
+ int length = end - start;
+ if (length < 2) return;
+ if (length < _MERGE_SORT_LIMIT) {
+ _insertionSort(list, compare, start, end, start + 1);
+ return;
+ }
+ // Special case the first split instead of directly calling
+ // _mergeSort, because the _mergeSort requires its target to
+ // be different from its source, and it requires extra space
+ // of the same size as the list to sort.
+ // This split allows us to have only half as much extra space,
+ // and it ends up in the original place.
+ int middle = start + ((end - start) >> 1);
+ int firstLength = middle - start;
+ int secondLength = end - middle;
+ // secondLength is always the same as firstLength, or one greater.
+ List scratchSpace = new List(secondLength);
+ _mergeSort(list, compare, middle, end, scratchSpace, 0);
+ int firstTarget = end - firstLength;
+ _mergeSort(list, compare, start, middle, list, firstTarget);
+ _merge(compare,
+ list, firstTarget, end,
+ scratchSpace, 0, secondLength,
+ list, start);
+}
+
+/**
+ * Performs an insertion sort into a potentially different list than the
+ * one containing the original values.
+ *
+ * It will work in-place as well.
+ */
+void _movingInsertionSort(List list, int compare(a, b), int start, int end,
+ List target, int targetOffset) {
+ int length = end - start;
+ if (length == 0) return;
+ target[targetOffset] = list[start];
+ for (int i = 1; i < length; i++) {
+ var element = list[start + i];
+ int min = targetOffset;
+ int max = targetOffset + i;
+ while (min < max) {
+ int mid = min + ((max - min) >> 1);
+ if (compare(element, target[mid]) < 0) {
+ max = mid;
+ } else {
+ min = mid + 1;
+ }
+ }
+ target.setRange(min + 1, targetOffset + i + 1,
+ target, min);
+ target[min] = element;
+ }
+}
+
+/**
+ * Sorts [list] from [start] to [end] into [target] at [targetOffset].
+ *
+ * The `target` list must be able to contain the range from `start` to `end`
+ * after `targetOffset`.
+ *
+ * Allows target to be the same list as [list], as long as it's not
+ * overlapping the `start..end` range.
+ */
+void _mergeSort(List list, int compare(a, b), int start, int end,
+ List target, int targetOffset) {
+ int length = end - start;
+ if (length < _MERGE_SORT_LIMIT) {
+ _movingInsertionSort(list, compare, start, end, target, targetOffset);
+ return;
+ }
+ int middle = start + (length >> 1);
+ int firstLength = middle - start;
+ int secondLength = end - middle;
+ // Here secondLength >= firstLength (differs by at most one).
+ int targetMiddle = targetOffset + firstLength;
+ // Sort the second half into the end of the target area.
+ _mergeSort(list, compare, middle, end,
+ target, targetMiddle);
+ // Sort the first half into the end of the source area.
+ _mergeSort(list, compare, start, middle,
+ list, middle);
+ // Merge the two parts into the target area.
+ _merge(compare,
+ list, middle, middle + firstLength,
+ target, targetMiddle, targetMiddle + secondLength,
+ target, targetOffset);
+}
+
+/**
+ * Merges two lists into a target list.
+ *
+ * One of the input lists may be positioned at the end of the target
+ * list.
+ *
+ * For equal object, elements from [firstList] are always preferred.
+ * This allows the merge to be stable if the first list contains elements
+ * that started out earlier than the ones in [secondList]
+ */
+void _merge(int compare(a, b),
+ List firstList, int firstStart, int firstEnd,
+ List secondList, int secondStart, int secondEnd,
+ List target, int targetOffset) {
+ // No empty lists reaches here.
+ assert(firstStart < firstEnd);
+ assert(secondStart < secondEnd);
+ int cursor1 = firstStart;
+ int cursor2 = secondStart;
+ var firstElement = firstList[cursor1++];
+ var secondElement = secondList[cursor2++];
+ while (true) {
+ if (compare(firstElement, secondElement) <= 0) {
+ target[targetOffset++] = firstElement;
+ if (cursor1 == firstEnd) break; // Flushing second list after loop.
+ firstElement = firstList[cursor1++];
+ } else {
+ target[targetOffset++] = secondElement;
+ if (cursor2 != secondEnd) {
+ secondElement = secondList[cursor2++];
+ continue;
+ }
+ // Second list empties first. Flushing first list here.
+ target[targetOffset++] = firstElement;
+ target.setRange(targetOffset, targetOffset + (firstEnd - cursor1),
+ firstList, cursor1);
+ return;
+ }
+ }
+ // First list empties first. Reached by break above.
+ target[targetOffset++] = secondElement;
+ target.setRange(targetOffset, targetOffset + (secondEnd - cursor2),
+ secondList, cursor2);
+}
+
+class TraceMerge {
+ Map _processes = {};
+ List _metaEvents = [];
+
+ void _processEventsFromFile(String name) {
+ var file = new File(name);
+ var events = [];
+ try {
+ var contents = file.readAsStringSync();
+ events = JSON.decode(contents);
+ } catch (e) {
+ print('Exception for $name $e');
+ }
+ _processEvents(events);
+ }
+
+ List _findOrAddProcessThread(pid, tid) {
+ var process = _processes[pid];
+ if (process == null) {
+ process = {};
+ _processes[pid] = process;
+ }
+ var thread = process[tid];
+ if (thread == null) {
+ thread = [];
+ process[tid] = thread;
+ }
+ return thread;
+ }
+
+ void _processEvents(List events) {
+ for (var i = 0; i < events.length; i++) {
+ Map event = events[i];
+ if (event['ph'] == 'M') {
+ _metaEvents.add(event);
+ } else {
+ var pid = event['pid'];
+ if (pid == null) {
+ throw "No pid in ${event}";
+ }
+ var tid = event['tid'];
+ if (tid == null) {
+ throw "No tid in ${event}";
+ }
+ var thread = _findOrAddProcessThread(pid, tid);
+ if (thread == null) {
+ throw "No thread list returned.";
+ }
+ thread.add(event);
+ }
+ }
+ }
+
+ int _compare(Map a, Map b) {
+ if (a['ts'] > b['ts']) {
+ return 1;
+ } else if (a['ts'] < b['ts']) {
+ return -1;
+ }
+ return 0;
+ }
+
+ void _sortEvents() {
+ _processes.forEach((k, Map process) {
+ process.forEach((k, List thread) {
+ mergeSort(thread, compare:_compare);
+ });
+ });
+ }
+
+ void _mergeEventsForThread(List thread) {
+ List<Map> stack = [];
+ int stackDepth = 0;
+ thread.forEach((event) {
+ if (event['ph'] == 'B') {
+ if (stackDepth == stack.length) {
+ stack.add(null);
+ }
+ stackDepth++;
+ var end_event = stack[stackDepth - 1];
+ if (end_event != null) {
+ if (end_event['name'] == event['name'] && stackDepth > 1) {
+ // Kill these events.
+ // event['dead'] = true;
+ // end_event['dead'] = true;
+ }
+ }
+ } else {
+ if (event['ph'] != 'E') {
+ throw 'Expected E event: ${event}';
+ }
+ if (stackDepth <= 0) {
+ throw 'Stack out of sync ${event}.';
+ }
+ stackDepth--;
+ stack[stackDepth] = event;
+ }
+ });
+ }
+
+ void _mergeEvents() {
+ _processes.forEach((k, Map process) {
+ process.forEach((k, List thread) {
+ _mergeEventsForThread(thread);
+ });
+ });
+ }
+
+ void writeEventsToFile(String name) {
+ var file = new File(name);
+ List final_events = _metaEvents;
+ _processes.forEach((pid, Map process) {
+ process.forEach((tid, List thread) {
+ thread.forEach((event) {
+ if (event['dead'] == null) {
+ // Not dead.
+ final_events.add(event);
+ }
+ });
+ });
+ });
+ file.writeAsStringSync(JSON.encode(final_events));
+ }
+
+ void merge(List<String> inputs) {
+ for (var i = 0; i < inputs.length; i++) {
+ _processEventsFromFile(inputs[i]);
+ }
+ _sortEvents();
+ _mergeEvents();
+ }
+}
+
+main(List<String> arguments) {
+ if (arguments.length < 2) {
+ print('${Platform.executable} ${Platform.script} <output> <inputs>');
+ return;
+ }
+ String output = arguments[0];
+ List<String> inputs = new List<String>();
+ for (var i = 1; i < arguments.length; i++) {
+ inputs.add(arguments[i]);
+ }
+ print('Merging $inputs into $output.');
+ TraceMerge tm = new TraceMerge();
+ tm.merge(inputs);
+ tm.writeEventsToFile(output);
+}
diff --git a/tools/tracesummary.dart b/tools/tracesummary.dart
new file mode 100644
index 0000000..587894c
--- /dev/null
+++ b/tools/tracesummary.dart
@@ -0,0 +1,163 @@
+// 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.
+
+// Print a summary of a profile trace.
+
+import 'dart:convert';
+import 'dart:io';
+
+class TraceSymbol {
+ final String name;
+ int exclusive = 0;
+ int inclusive = 0;
+ TraceSymbol(this.name);
+}
+
+class TraceSummary {
+ final int numSymbols;
+
+ Map<String, TraceSymbol> _symbols = {};
+ List _events = [];
+ List<TraceSymbol> _stack = [];
+ List<TraceSymbol> _topExclusive = [];
+ List<TraceSymbol> _topInclusive = [];
+ bool _marked = false;
+ int _totalSamples = 0;
+
+ TraceSummary(this.numSymbols);
+
+ void _processEventsFromFile(String name) {
+ var file = new File(name);
+ var events = [];
+ try {
+ var contents = file.readAsStringSync();
+ events = JSON.decode(contents);
+ } catch (e) {
+ print('Exception for $name $e');
+ }
+ _processEvents(events);
+ }
+
+ void _processBegin(Map event) {
+ var name = event['name'];
+ if (name == '<no frame>') {
+ return;
+ }
+ var symbol = _symbols[name];
+ if (symbol == null) {
+ symbol = new TraceSymbol(name);
+ _symbols[name] = symbol;
+ }
+ _stack.add(symbol);
+ _marked = false;
+ }
+
+ void _processEnd(Map event) {
+ var name = event['name'];
+ if (name == '<no frame>') {
+ return;
+ }
+ var symbol = _stack.last;
+ if (symbol.name != name) {
+ throw new StateError('$name not found at top of stack.');
+ }
+ if ((_stack.length > 1) && (_marked == false)) {
+ // We are transitioning from the sequence of begins to the sequence
+ // of ends. Mark the symbols on the stack.
+ _marked = true;
+ _totalSamples++;
+ // Mark all symbols except the top with an inclusive tick.
+ for (int i = 1; i < _stack.length; i++) {
+ _stack[i].inclusive++;
+ }
+ _stack.last.exclusive++;
+ }
+ _stack.removeLast();
+ }
+
+ void _processEvents(List events) {
+ for (var i = 0; i < events.length; i++) {
+ Map event = events[i];
+ if (event['ph'] == 'M') {
+ // Ignore.
+ } else if (event['ph'] == 'B') {
+ _processBegin(event);
+ } else if (event['ph'] == 'E') {
+ _processEnd(event);
+ }
+ }
+ }
+
+ void _findTopExclusive() {
+ _topExclusive = _symbols.values.toList();
+ _topExclusive.sort((a, b) {
+ return b.exclusive - a.exclusive;
+ });
+ }
+
+
+ void _findTopInclusive() {
+ _topInclusive = _symbols.values.toList();
+ _topInclusive.sort((a, b) {
+ return b.inclusive - a.inclusive;
+ });
+ }
+
+ void summarize(String input) {
+ _processEventsFromFile(input);
+ _findTopExclusive();
+ _findTopInclusive();
+ _print();
+ }
+
+ String _pad(String input, int minLength) {
+ int length = input.length;
+ for (int i = 0; i < minLength - length; i++) {
+ input = ' $input';
+ }
+ return input;
+ }
+
+ static const TICKS_LENGTH = 10;
+ static const PERCENT_LENGTH = 7;
+
+ void _printSymbol(int t, String name) {
+ String ticks = t.toString();
+ ticks = _pad(ticks, TICKS_LENGTH);
+ double total = (t / _totalSamples);
+ String percent = (total * 100.0).toStringAsFixed(2);
+ percent = _pad(percent, PERCENT_LENGTH);
+ print('$ticks $percent $name');
+ }
+
+ void _print() {
+ print('Top ${numSymbols} inclusive symbols');
+ print('--------------------------');
+ print(' ticks percent name');
+ _topInclusive.getRange(0, numSymbols).forEach((a) {
+ _printSymbol(a.inclusive, a.name);
+ });
+ print('');
+ print('Top ${numSymbols} exclusive symbols');
+ print('--------------------------');
+ print(' ticks percent name');
+ _topExclusive.getRange(0, numSymbols).forEach((a) {
+ _printSymbol(a.exclusive, a.name);
+ });
+ }
+}
+
+main(List<String> arguments) {
+ if (arguments.length < 1) {
+ print('${Platform.executable} ${Platform.script} <input> [symbol count]');
+ return;
+ }
+ String input = arguments[0];
+ int numSymbols = 10;
+ if (arguments.length >= 2) {
+ numSymbols = int.parse(arguments[1]);
+ }
+ TraceSummary ts = new TraceSummary(numSymbols);
+ ts.summarize(input);
+}