Version 0.5.13.0 .
svn merge -r 23342:23474 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
svn merge -c 23501 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
git-svn-id: http://dart.googlecode.com/svn/trunk@23503 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/pkg/analyzer_experimental/lib/options.dart b/pkg/analyzer_experimental/lib/options.dart
index c6fd30d..9ada7ac4 100644
--- a/pkg/analyzer_experimental/lib/options.dart
+++ b/pkg/analyzer_experimental/lib/options.dart
@@ -9,7 +9,7 @@
import 'dart:io';
-const _BINARY_NAME = 'analyzer';
+const _BINARY_NAME = 'dartanalyzer';
/**
* Analyzer commandline configuration options.
@@ -22,6 +22,9 @@
/** Whether to use machine format for error display */
final bool machineFormat;
+ /** Whether to display version information */
+ final bool displayVersion;
+
/** Whether to ignore unrecognized flags */
final bool ignoreUnrecognizedFlags;
@@ -48,7 +51,8 @@
*/
CommandLineOptions._fromArgs(ArgResults args)
: shouldBatch = args['batch'],
- machineFormat = args['machine-format'],
+ machineFormat = args['machine'],
+ displayVersion = args['version'],
ignoreUnrecognizedFlags = args['ignore-unrecognized-flags'],
showPackageWarnings = args['show-package-warnings'],
showSdkWarnings = args['show-sdk-warnings'],
@@ -87,20 +91,23 @@
defaultsTo: false, negatable: false)
..addOption('dart-sdk', help: 'The path to the Dart SDK')
..addOption('package-root', help: 'The path to the package root')
- ..addFlag('machine-format', help: 'Specify whether errors '
- 'should be in machine format',
+ ..addFlag('machine',
+ help: 'Print errors in a format suitable for parsing',
+ defaultsTo: false, negatable: false)
+ ..addFlag('version', help: 'Print the analyzer version',
defaultsTo: false, negatable: false)
..addFlag('ignore-unrecognized-flags',
help: 'Ignore unrecognized command line flags',
defaultsTo: false, negatable: false)
..addFlag('fatal-warnings', help: 'Treat non-type warnings as fatal',
defaultsTo: false, negatable: false)
- ..addFlag('show-package-warnings', help: 'Show warnings from package: imports',
- defaultsTo: false, negatable: false)
+ ..addFlag('show-package-warnings',
+ help: 'Show warnings from package: imports',
+ defaultsTo: false, negatable: false)
..addFlag('show-sdk-warnings', help: 'Show warnings from SDK imports',
- defaultsTo: false, negatable: false)
+ defaultsTo: false, negatable: false)
..addFlag('help', abbr: 'h', help: 'Display this help message',
- defaultsTo: false, negatable: false);
+ defaultsTo: false, negatable: false);
try {
var results = parser.parse(args);
@@ -116,6 +123,9 @@
_showUsage(parser);
exit(15);
}
+ } if (results['version']) {
+ print('$_BINARY_NAME version ${_getVersion()}');
+ exit(0);
} else {
if (results.rest.length == 0) {
_showUsage(parser);
@@ -134,8 +144,22 @@
static _showUsage(parser) {
print('Usage: $_BINARY_NAME [options...] <libraries to analyze...>');
print(parser.getUsage());
+ print('');
+ print('For more information, see http://www.dartlang.org/tools/analyzer.');
}
+ static String _getVersion() {
+ try {
+ Path path = new Path(new Options().script);
+ Path versionPath = path.directoryPath.append('..').append('version');
+ File versionFile = new File.fromPath(versionPath);
+
+ return versionFile.readAsStringSync().trim();
+ } catch (_) {
+ // This happens when the script is not running in the context of an SDK.
+ return "<unknown>";
+ }
+ }
}
/**
diff --git a/pkg/analyzer_experimental/lib/src/error_formatter.dart b/pkg/analyzer_experimental/lib/src/error_formatter.dart
index d36cab4..34d0fb4 100644
--- a/pkg/analyzer_experimental/lib/src/error_formatter.dart
+++ b/pkg/analyzer_experimental/lib/src/error_formatter.dart
@@ -124,18 +124,10 @@
out.write('|');
out.writeln(escapePipe(error.message));
} else {
- // [warning] 'foo' is not a method or function (/Users/devoncarew/temp/foo.dart:-1:-1)
- out.write('[');
- out.write(severity.displayName);
- out.write('] ');
- out.write(error.message);
- out.write(' (');
- out.write(source.fullName);
- out.write(':');
- out.write(location.lineNumber);
- out.write(':');
- out.write(location.columnNumber);
- out.writeln(')');
+ // [warning] 'foo' is not a... (/Users/.../tmp/foo.dart, line 1, col 2)
+ out.write('[${severity.displayName}] ${error.message} ');
+ out.write('(${source.fullName}');
+ out.write(', line ${location.lineNumber}, col ${location.columnNumber})');
}
}
diff --git a/pkg/expect/lib/expect.dart b/pkg/expect/lib/expect.dart
index 0f83041..20d216f 100644
--- a/pkg/expect/lib/expect.dart
+++ b/pkg/expect/lib/expect.dart
@@ -17,11 +17,88 @@
*/
class Expect {
/**
+ * Return a slice of a string.
+ *
+ * The slice will contain at least the substring from [start] to the lower of
+ * [end] and `start + length`.
+ * If the result is no more than `length - 10` characters long,
+ * context may be added by extending the range of the slice, by decreasing
+ * [start] and increasing [end], up to at most length characters.
+ * If the start or end of the slice are not matching the start or end of
+ * the string, ellipses are added before or after the slice.
+ * Control characters may be encoded as "\xhh" codes.
+ */
+ static String _truncateString(String string, int start, int end, int length) {
+ if (end - start > length) {
+ end = start + length;
+ } else if (end - start < length) {
+ int overflow = length - (end - start);
+ if (overflow > 10) overflow = 10;
+ // Add context.
+ start = start - ((overflow + 1) ~/ 2);
+ end = end + (overflow ~/ 2);
+ if (start < 0) start = 0;
+ if (end > string.length) end = string.length;
+ }
+ if (start == 0 && end == string.length) return string;
+ StringBuffer buf = new StringBuffer();
+ if (start > 0) buf.write("...");
+ for (int i = start; i < end; i++) {
+ int code = string.codeUnitAt(i);
+ if (code < 0x20) {
+ buf.write(r"\x");
+ buf.write("0123456789abcdef"[code ~/ 16]);
+ buf.write("0123456789abcdef"[code % 16]);
+ } else {
+ buf.writeCharCode(string.codeUnitAt(i));
+ }
+ }
+ if (end < string.length) buf.write("...");
+ return buf.toString();
+ }
+
+ /**
+ * Find the difference between two strings.
+ *
+ * This finds the first point where two strings differ, and returns
+ * a text describing the difference.
+ *
+ * For small strings (length less than 20) nothing is done, and null is
+ * returned. Small strings can be compared visually, but for longer strings
+ * only a slice containing the first difference will be shown.
+ */
+ static String _stringDifference(String expected, String actual) {
+ if (expected.length < 20 && actual.length < 20) return null;
+ for (int i = 0; i < expected.length && i < actual.length; i++) {
+ if (expected.codeUnitAt(i) != actual.codeUnitAt(i)) {
+ int start = i;
+ i++;
+ while (i < expected.length && i < actual.length) {
+ if (expected.codeUnitAt(i) == actual.codeUnitAt(i)) break;
+ i++;
+ }
+ int end = i;
+ var truncExpected = _truncateString(expected, start, end, 20);
+ var truncActual = _truncateString(actual, start, end, 20);
+ return "at index $start: Expected <$truncExpected>, "
+ "Found: <$truncActual>";
+ }
+ }
+ return null;
+ }
+
+ /**
* Checks whether the expected and actual values are equal (using `==`).
*/
static void equals(var expected, var actual, [String reason = null]) {
if (expected == actual) return;
String msg = _getMessage(reason);
+ if (expected is String && actual is String) {
+ String stringDifference = _stringDifference(expected, actual);
+ if (stringDifference != null) {
+ _fail("Expect.equals($stringDifference$msg) fails.");
+ }
+ }
_fail("Expect.equals(expected: <$expected>, actual: <$actual>$msg) fails.");
}
diff --git a/pkg/http/lib/src/multipart_request.dart b/pkg/http/lib/src/multipart_request.dart
index 6d8f03b..051ac76 100644
--- a/pkg/http/lib/src/multipart_request.dart
+++ b/pkg/http/lib/src/multipart_request.dart
@@ -89,7 +89,7 @@
headers['content-transfer-encoding'] = 'binary';
super.finalize();
- var controller = new StreamController<List<int>>();
+ var controller = new StreamController<List<int>>(sync: true);
void writeAscii(String string) {
assert(isPlainAscii(string));
diff --git a/pkg/http/lib/src/streamed_request.dart b/pkg/http/lib/src/streamed_request.dart
index 1b72eab..ceff1a1 100644
--- a/pkg/http/lib/src/streamed_request.dart
+++ b/pkg/http/lib/src/streamed_request.dart
@@ -32,7 +32,7 @@
/// Creates a new streaming request.
StreamedRequest(String method, Uri url)
: super(method, url),
- _controller = new StreamController<List<int>>();
+ _controller = new StreamController<List<int>>(sync: true);
/// Freezes all mutable fields other than [stream] and returns a
/// single-subscription [ByteStream] that emits the data being written to
diff --git a/pkg/http/lib/src/utils.dart b/pkg/http/lib/src/utils.dart
index 4a3b84c..7be3938 100644
--- a/pkg/http/lib/src/utils.dart
+++ b/pkg/http/lib/src/utils.dart
@@ -173,7 +173,7 @@
/// Creates a single-subscription stream that emits the items in [iter] and then
/// ends.
Stream streamFromIterable(Iterable iter) {
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
iter.forEach(controller.add);
controller.close();
return controller.stream;
@@ -184,8 +184,8 @@
/// errors from [stream]. This is useful if [stream] is single-subscription but
/// multiple subscribers are necessary.
Pair<Stream, Stream> tee(Stream stream) {
- var controller1 = new StreamController();
- var controller2 = new StreamController();
+ var controller1 = new StreamController(sync: true);
+ var controller2 = new StreamController(sync: true);
stream.listen((value) {
controller1.add(value);
controller2.add(value);
diff --git a/pkg/http/test/mock_client_test.dart b/pkg/http/test/mock_client_test.dart
index 8e46ccc..f9f7769 100644
--- a/pkg/http/test/mock_client_test.dart
+++ b/pkg/http/test/mock_client_test.dart
@@ -35,7 +35,7 @@
test('handles a streamed request', () {
var client = new MockClient.streaming((request, bodyStream) {
return bodyStream.bytesToString().then((bodyString) {
- var controller = new StreamController<List<int>>();
+ var controller = new StreamController<List<int>>(sync: true);
async.then((_) {
controller.add('Request body was "$bodyString"'.codeUnits);
controller.close();
diff --git a/pkg/http/test/multipart_test.dart b/pkg/http/test/multipart_test.dart
index 1be547d..78121f6 100644
--- a/pkg/http/test/multipart_test.dart
+++ b/pkg/http/test/multipart_test.dart
@@ -154,7 +154,7 @@
test('with a stream file', () {
var request = new http.MultipartRequest('POST', dummyUrl);
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
request.files.add(new http.MultipartFile('file', controller.stream, 5));
expect(request, bodyMatches('''
@@ -172,7 +172,7 @@
test('with an empty stream file', () {
var request = new http.MultipartRequest('POST', dummyUrl);
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
request.files.add(new http.MultipartFile('file', controller.stream, 0));
expect(request, bodyMatches('''
diff --git a/pkg/http/test/response_test.dart b/pkg/http/test/response_test.dart
index 17b2b60..5fafa37 100644
--- a/pkg/http/test/response_test.dart
+++ b/pkg/http/test/response_test.dart
@@ -44,7 +44,7 @@
group('.fromStream()', () {
test('sets body', () {
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
var streamResponse = new http.StreamedResponse(
controller.stream, 200, 13);
var future = http.Response.fromStream(streamResponse)
@@ -57,7 +57,7 @@
});
test('sets bodyBytes', () {
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
var streamResponse = new http.StreamedResponse(controller.stream, 200, 5);
var future = http.Response.fromStream(streamResponse)
.then((response) => response.bodyBytes);
diff --git a/pkg/http/test/safe_http_server.dart b/pkg/http/test/safe_http_server.dart
index c9885f1..a580770b 100644
--- a/pkg/http/test/safe_http_server.dart
+++ b/pkg/http/test/safe_http_server.dart
@@ -76,7 +76,6 @@
int get contentLength => _inner.contentLength;
String get method => _inner.method;
Uri get uri => _inner.uri;
- Map<String, String> get queryParameters => _inner.queryParameters;
HttpHeaders get headers => _inner.headers;
List<Cookie> get cookies => _inner.cookies;
bool get persistentConnection => _inner.persistentConnection;
diff --git a/pkg/http/test/utils.dart b/pkg/http/test/utils.dart
index 786bb84..c2ce9c4 100644
--- a/pkg/http/test/utils.dart
+++ b/pkg/http/test/utils.dart
@@ -59,7 +59,7 @@
new ByteStream(request).toBytes().then((requestBodyBytes) {
var outputEncoding;
- var encodingName = request.queryParameters['response-encoding'];
+ var encodingName = request.uri.queryParameters['response-encoding'];
if (encodingName != null) {
outputEncoding = requiredEncodingForCharset(encodingName);
} else {
diff --git a/pkg/logging/lib/logging.dart b/pkg/logging/lib/logging.dart
index 94bf5f3..b29f076c 100644
--- a/pkg/logging/lib/logging.dart
+++ b/pkg/logging/lib/logging.dart
@@ -196,7 +196,7 @@
Stream<LogRecord> _getStream() {
if (hierarchicalLoggingEnabled || parent == null) {
if (_controller == null) {
- _controller = new StreamController<LogRecord>();
+ _controller = new StreamController<LogRecord>(sync: true);
_stream = _controller.stream.asBroadcastStream();
}
return _stream;
diff --git a/pkg/oauth2/lib/oauth2.dart b/pkg/oauth2/lib/oauth2.dart
index 96bffcf..cca66ab 100644
--- a/pkg/oauth2/lib/oauth2.dart
+++ b/pkg/oauth2/lib/oauth2.dart
@@ -96,7 +96,7 @@
/// // Once the user is redirected to `redirectUrl`, pass the query
/// // parameters to the AuthorizationCodeGrant. It will validate them
/// // and extract the authorization code to create a new Client.
-/// return grant.handleAuthorizationResponse(request.queryParameters);
+/// return grant.handleAuthorizationResponse(request.uri.queryParameters);
/// })
/// }).then((client) {
/// // Once you have a Client, you can use it just like any other HTTP
diff --git a/pkg/pkg.status b/pkg/pkg.status
index 161a54b..06ccb56 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -143,6 +143,9 @@
[ $compiler == none && $runtime == drt ]
dartdoc/test/dartdoc_test: Skip # See dartbug.com/4541.
+[ $arch == arm ]
+*: Skip
+
[ $arch == simarm ]
*: Skip
diff --git a/pkg/scheduled_test/lib/src/mock_clock.dart b/pkg/scheduled_test/lib/src/mock_clock.dart
index 0d77e5a..ba353fa 100644
--- a/pkg/scheduled_test/lib/src/mock_clock.dart
+++ b/pkg/scheduled_test/lib/src/mock_clock.dart
@@ -45,13 +45,13 @@
int _time = 0;
/// Controller providing streams for listening.
- StreamController<int> _multiplexController =
- new StreamController<int>.broadcast();
+ StreamController<int> _broadcastController =
+ new StreamController<int>.broadcast(sync: true);
Clock._();
/// The stream of millisecond ticks of the clock.
- Stream<int> get onTick => _multiplexController.stream;
+ Stream<int> get onTick => _broadcastController.stream;
/// Advances the clock forward by [milliseconds]. This works like synchronous
/// code that takes [milliseconds] to execute; any [Timer]s that are scheduled
@@ -61,7 +61,7 @@
for (var i = 0; i < milliseconds; i++) {
var tickTime = ++_time;
runAsync(() {
- _multiplexController.add(tickTime);
+ _broadcastController.add(tickTime);
});
}
}
@@ -72,7 +72,7 @@
/// code runs before the next tick.
void run() {
pumpEventQueue().then((_) {
- if (!_multiplexController.hasListener) return;
+ if (!_broadcastController.hasListener) return;
tick();
return run();
});
diff --git a/pkg/scheduled_test/lib/src/scheduled_server/safe_http_server.dart b/pkg/scheduled_test/lib/src/scheduled_server/safe_http_server.dart
index c9885f1..a580770b 100644
--- a/pkg/scheduled_test/lib/src/scheduled_server/safe_http_server.dart
+++ b/pkg/scheduled_test/lib/src/scheduled_server/safe_http_server.dart
@@ -76,7 +76,6 @@
int get contentLength => _inner.contentLength;
String get method => _inner.method;
Uri get uri => _inner.uri;
- Map<String, String> get queryParameters => _inner.queryParameters;
HttpHeaders get headers => _inner.headers;
List<Cookie> get cookies => _inner.cookies;
bool get persistentConnection => _inner.persistentConnection;
diff --git a/pkg/scheduled_test/lib/src/utils.dart b/pkg/scheduled_test/lib/src/utils.dart
index 62461a6..31abe95 100644
--- a/pkg/scheduled_test/lib/src/utils.dart
+++ b/pkg/scheduled_test/lib/src/utils.dart
@@ -81,7 +81,7 @@
/// returned by [future] once [future] completes. If [future] completes to an
/// error, the return value will emit that error and then close.
Stream futureStream(Future<Stream> future) {
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
future.then((stream) {
stream.listen(
controller.add,
@@ -137,7 +137,7 @@
/// the wrapped stream. Unlike [StreamSubscription], this canceller will send a
/// "done" message to the wrapped stream.
Pair<Stream, StreamCanceller> streamWithCanceller(Stream stream) {
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
var controllerStream = stream.isBroadcast ?
controller.stream.asBroadcastStream() :
controller.stream;
@@ -154,8 +154,8 @@
/// errors from [stream]. This is useful if [stream] is single-subscription but
/// multiple subscribers are necessary.
Pair<Stream, Stream> tee(Stream stream) {
- var controller1 = new StreamController();
- var controller2 = new StreamController();
+ var controller1 = new StreamController(sync: true);
+ var controller2 = new StreamController(sync: true);
stream.listen((value) {
controller1.add(value);
controller2.add(value);
diff --git a/pkg/unittest/lib/test_controller.js b/pkg/unittest/lib/test_controller.js
index d8ef908..f3932d3 100644
--- a/pkg/unittest/lib/test_controller.js
+++ b/pkg/unittest/lib/test_controller.js
@@ -33,9 +33,22 @@
var waitForDone = false;
+// Returns the driving window object if available
+function getDriverWindow() {
+ if (window != window.parent) {
+ // We're running in an iframe.
+ return window.parent;
+ } else if (window.opener) {
+ // We were opened by another window.
+ return window.opener;
+ }
+ return null;
+}
+
function notifyStart() {
- if (window.opener) {
- window.opener.postMessage("STARTING", "*");
+ var driver = getDriverWindow();
+ if (driver) {
+ driver.postMessage("STARTING", "*");
}
}
@@ -43,8 +56,9 @@
if (testRunner) testRunner.notifyDone();
// To support in browser launching of tests we post back start and result
// messages to the window.opener.
- if (window.opener) {
- window.opener.postMessage(window.document.body.innerHTML, "*");
+ var driver = getDriverWindow();
+ if (driver) {
+ driver.postMessage(window.document.body.innerHTML, "*");
}
}
diff --git a/runtime/bin/bin.gypi b/runtime/bin/bin.gypi
index 033539e..8b0db92 100644
--- a/runtime/bin/bin.gypi
+++ b/runtime/bin/bin.gypi
@@ -251,6 +251,7 @@
'dependencies': [
'libdart_withcore',
'libdart_builtin',
+ 'libdart_io',
],
'include_dirs': [
'..',
diff --git a/runtime/bin/builtin.dart b/runtime/bin/builtin.dart
index 808124a..bae6952 100644
--- a/runtime/bin/builtin.dart
+++ b/runtime/bin/builtin.dart
@@ -106,6 +106,9 @@
case 'package':
path = _filePathFromPackageUri(uri);
break;
+ case 'http':
+ path = _filePathFromHttpUri(uri);
+ break;
default:
// Only handling file and package URIs in standalone binary.
_logResolution("# Unknown scheme (${uri.scheme}) in $uri.");
@@ -162,3 +165,23 @@
_logResolution("# Package: $path");
return path;
}
+
+String _filePathFromHttpUri(Uri uri) {
+ _logResolution('# Path: $uri');
+ return uri.toString();
+}
+
+String _pathFromHttpUri(String userUri) {
+ var uri = Uri.parse(userUri);
+ return uri.path;
+}
+
+String _domainFromHttpUri(String userUri) {
+ var uri = Uri.parse(userUri);
+ return uri.domain;
+}
+
+int _portFromHttpUri(String userUri) {
+ var uri = Uri.parse(userUri);
+ return uri.port == 0 ? 80 : uri.port;
+}
diff --git a/runtime/bin/builtin_natives.cc b/runtime/bin/builtin_natives.cc
index 9a6bafe..fa7a79c 100644
--- a/runtime/bin/builtin_natives.cc
+++ b/runtime/bin/builtin_natives.cc
@@ -52,7 +52,6 @@
V(File_LinkTarget, 1) \
V(File_Delete, 1) \
V(File_DeleteLink, 1) \
- V(File_Directory, 1) \
V(File_FullPath, 1) \
V(File_OpenStdio, 1) \
V(File_GetStdioHandleType, 1) \
diff --git a/runtime/bin/common.cc b/runtime/bin/common.cc
index 030fcfa..ce9a9ef 100644
--- a/runtime/bin/common.cc
+++ b/runtime/bin/common.cc
@@ -18,38 +18,38 @@
// Fetch the cached builtin array types for this isolate.
IsolateData* isolate_data =
reinterpret_cast<IsolateData*>(Dart_CurrentIsolateData());
- Dart_Handle object_array_class = isolate_data->object_array_class;
- Dart_Handle growable_object_array_class =
- isolate_data->growable_object_array_class;
- Dart_Handle immutable_array_class = isolate_data->immutable_array_class;
// If we have not cached the class pointers in the isolate data,
// look them up and cache them now.
- if (object_array_class == NULL) {
+ if (isolate_data->object_array_class == NULL) {
Dart_Handle core_lib =
Dart_LookupLibrary(Dart_NewStringFromCString("dart:core"));
ASSERT(!Dart_IsError(core_lib));
- object_array_class =
+
+ Dart_Handle cls =
Dart_GetClass(core_lib, Dart_NewStringFromCString("_ObjectArray"));
- ASSERT(!Dart_IsError(object_array_class));
- immutable_array_class =
- Dart_GetClass(core_lib, Dart_NewStringFromCString("_ImmutableArray"));
- ASSERT(!Dart_IsError(immutable_array_class));
- growable_object_array_class = Dart_GetClass(
+ ASSERT(!Dart_IsError(cls));
+ isolate_data->object_array_class = Dart_NewPersistentHandle(cls);
+ ASSERT(isolate_data->object_array_class != NULL);
+
+ cls = Dart_GetClass(core_lib, Dart_NewStringFromCString("_ImmutableArray"));
+ ASSERT(!Dart_IsError(cls));
+ isolate_data->immutable_array_class = Dart_NewPersistentHandle(cls);
+ ASSERT(isolate_data->immutable_array_class != NULL);
+
+ cls = Dart_GetClass(
core_lib, Dart_NewStringFromCString("_GrowableObjectArray"));
- ASSERT(!Dart_IsError(growable_object_array_class));
- // Update the cache.
- isolate_data->object_array_class =
- Dart_NewPersistentHandle(object_array_class);
- ASSERT(!Dart_IsError(isolate_data->object_array_class));
- isolate_data->growable_object_array_class =
- Dart_NewPersistentHandle(growable_object_array_class);
- ASSERT(!Dart_IsError(isolate_data->growable_object_array_class));
- isolate_data->immutable_array_class =
- Dart_NewPersistentHandle(immutable_array_class);
- ASSERT(!Dart_IsError(isolate_data->immutable_array_class));
+ ASSERT(!Dart_IsError(cls));
+ isolate_data->growable_object_array_class = Dart_NewPersistentHandle(cls);
+ ASSERT(isolate_data->growable_object_array_class != NULL);
}
+ Dart_Handle object_array_class =
+ Dart_HandleFromPersistent(isolate_data->object_array_class);
+ Dart_Handle growable_object_array_class =
+ Dart_HandleFromPersistent(isolate_data->growable_object_array_class);
+ Dart_Handle immutable_array_class =
+ Dart_HandleFromPersistent(isolate_data->immutable_array_class);
bool builtin_array =
(Dart_IdentityEquals(list_class, growable_object_array_class) ||
Dart_IdentityEquals(list_class, object_array_class) ||
diff --git a/runtime/bin/dartutils.cc b/runtime/bin/dartutils.cc
index 89a84c4..9e26305 100644
--- a/runtime/bin/dartutils.cc
+++ b/runtime/bin/dartutils.cc
@@ -14,6 +14,7 @@
#include "bin/file.h"
#include "bin/io_buffer.h"
#include "bin/utils.h"
+#include "bin/socket.h"
namespace dart {
namespace bin {
@@ -26,6 +27,8 @@
const char* DartUtils::kCoreLibURL = "dart:core";
const char* DartUtils::kIOLibURL = "dart:io";
const char* DartUtils::kIOLibPatchURL = "dart:io-patch";
+const char* DartUtils::kUriLibURL = "dart:uri";
+const char* DartUtils::kHttpScheme = "http:";
const char* DartUtils::kIdFieldName = "_id";
@@ -141,6 +144,12 @@
}
+bool DartUtils::IsHttpSchemeURL(const char* url_name) {
+ static const intptr_t kHttpSchemeLen = strlen(kHttpScheme);
+ return (strncmp(url_name, kHttpScheme, kHttpSchemeLen) == 0);
+}
+
+
bool DartUtils::IsDartExtensionSchemeURL(const char* url_name) {
static const intptr_t kDartExtensionSchemeLen = strlen(kDartExtensionScheme);
// If the URL starts with "dartext:" then it is considered as a special
@@ -233,18 +242,223 @@
}
+// Writes string into socket.
+// Return < 0 indicates an error.
+// Return >= 0 number of bytes written.
+static intptr_t SocketWriteString(intptr_t socket, const char* str,
+ intptr_t len) {
+ int r;
+ intptr_t cursor = 0;
+ do {
+ r = Socket::Write(socket, &str[cursor], len);
+ if (r < 0) {
+ return r;
+ }
+ cursor += r;
+ len -= r;
+ } while (len > 0);
+ ASSERT(len == 0);
+ return cursor;
+}
+
+
+static uint8_t* SocketReadUntilEOF(intptr_t socket, intptr_t* response_len) {
+ const intptr_t kInitialBufferSize = 16 * KB;
+ intptr_t buffer_size = kInitialBufferSize;
+ uint8_t* buffer = reinterpret_cast<uint8_t*>(malloc(buffer_size));
+ ASSERT(buffer != NULL);
+ intptr_t buffer_cursor = 0;
+ do {
+ int bytes_read = Socket::Read(socket, &buffer[buffer_cursor],
+ buffer_size - buffer_cursor - 1);
+ if (bytes_read < 0) {
+ free(buffer);
+ return NULL;
+ }
+
+ buffer_cursor += bytes_read;
+
+ if (bytes_read == 0) {
+ *response_len = buffer_cursor;
+ buffer[buffer_cursor] = '\0';
+ break;
+ }
+
+ // There is still more data to be read, check that we have room in the
+ // buffer for more data.
+ if (buffer_cursor == buffer_size - 1) {
+ // Buffer is full. Increase buffer size.
+ buffer_size *= 2;
+ buffer = reinterpret_cast<uint8_t*>(realloc(buffer, buffer_size));
+ ASSERT(buffer != NULL);
+ }
+ } while (true);
+ return buffer;
+}
+
+
+static bool HttpGetRequestOkay(const char* response) {
+ static const char* kOkayReply = "HTTP/1.0 200 OK";
+ static const intptr_t kOkayReplyLen = strlen(kOkayReply);
+ return (strncmp(response, kOkayReply, kOkayReplyLen) == 0);
+}
+
+
+static const uint8_t* HttpRequestGetPayload(const char* response) {
+ const char* split = strstr(response, "\r\n\r\n");
+ if (split != NULL) {
+ return reinterpret_cast<const uint8_t*>(split+4);
+ }
+ return NULL;
+}
+
+
+// TODO(iposva): Allocate from the zone instead of leaking error string
+// here. On the other hand the binary is about the exit anyway.
+#define SET_ERROR_MSG(error_msg, format, ...) \
+ intptr_t len = snprintf(NULL, 0, format, __VA_ARGS__); \
+ char *msg = reinterpret_cast<char*>(malloc(len + 1)); \
+ snprintf(msg, len + 1, format, __VA_ARGS__); \
+ *error_msg = msg
+
+
+static const uint8_t* HttpGetRequest(const char* host, const char* path,
+ int port, intptr_t* response_len,
+ const char** error_msg) {
+ OSError* error = NULL;
+ SocketAddresses* addresses = Socket::LookupAddress(host, -1, &error);
+ if (addresses == NULL || addresses->count() == 0) {
+ SET_ERROR_MSG(error_msg, "Unable to resolve %s", host);
+ return NULL;
+ }
+
+ int preferred_address = 0;
+ for (int i = 0; i < addresses->count(); i++) {
+ SocketAddress* address = addresses->GetAt(i);
+ if (address->GetType() == SocketAddress::ADDRESS_LOOPBACK_IP_V4) {
+ // Prefer the IP_V4 loop back.
+ preferred_address = i;
+ break;
+ }
+ }
+
+ RawAddr addr = addresses->GetAt(preferred_address)->addr();
+ intptr_t tcp_client = Socket::Create(addr);
+ if (tcp_client < 0) {
+ SET_ERROR_MSG(error_msg, "Unable to create socket to %s:%d", host, port);
+ return NULL;
+ }
+ Socket::Connect(tcp_client, addr, port);
+ if (tcp_client < 0) {
+ SET_ERROR_MSG(error_msg, "Unable to connect to %s:%d", host, port);
+ return NULL;
+ }
+ // Send get request.
+ {
+ const char* format =
+ "GET %s HTTP/1.0\r\nUser-Agent: Dart VM\r\nHost: %s\r\n\r\n";
+ intptr_t len = snprintf(NULL, 0, format, path, host);
+ char* get_request = reinterpret_cast<char*>(malloc(len + 1));
+ snprintf(get_request, len + 1, format, path, host);
+ intptr_t r = SocketWriteString(tcp_client, get_request, len);
+ free(get_request);
+ if (r < len) {
+ SET_ERROR_MSG(error_msg, "Unable to write to %s:%d - %d", host, port,
+ static_cast<int>(r));
+ Socket::Close(tcp_client);
+ return NULL;
+ }
+ ASSERT(r == len);
+ }
+ // Consume response.
+ uint8_t* response = SocketReadUntilEOF(tcp_client, response_len);
+ // Close socket.
+ Socket::Close(tcp_client);
+ if (response == NULL) {
+ SET_ERROR_MSG(error_msg, "Unable to read from %s:%d", host, port);
+ return NULL;
+ }
+ if (HttpGetRequestOkay(reinterpret_cast<const char*>(response)) == false) {
+ SET_ERROR_MSG(error_msg, "Invalid HTTP response from %s:%d", host, port);
+ free(response);
+ return NULL;
+ }
+ return response;
+}
+
+
+static Dart_Handle ParseHttpUri(const char* script_uri, const char** host_str,
+ int64_t* port_int, const char** path_str) {
+ ASSERT(script_uri != NULL);
+ ASSERT(host_str != NULL);
+ ASSERT(port_int != NULL);
+ ASSERT(path_str != NULL);
+ Dart_Handle result;
+ Dart_Handle uri = DartUtils::NewString(script_uri);
+ Dart_Handle builtin_lib =
+ Builtin::LoadAndCheckLibrary(Builtin::kBuiltinLibrary);
+ Dart_Handle path = DartUtils::PathFromUri(uri, builtin_lib);
+ if (Dart_IsError(path)) {
+ return path;
+ }
+ Dart_Handle host = DartUtils::DomainFromUri(uri, builtin_lib);
+ if (Dart_IsError(host)) {
+ return host;
+ }
+ Dart_Handle port = DartUtils::PortFromUri(uri, builtin_lib);
+ if (Dart_IsError(port)) {
+ return port;
+ }
+ result = Dart_StringToCString(path, path_str);
+ if (Dart_IsError(result)) {
+ return result;
+ }
+ result = Dart_StringToCString(host, host_str);
+ if (Dart_IsError(result)) {
+ return result;
+ }
+ if (DartUtils::GetInt64Value(port, port_int) == false) {
+ return Dart_Error("Invalid port");
+ }
+ return result;
+}
+
+
+Dart_Handle DartUtils::ReadStringFromHttp(const char* script_uri) {
+ const char* host_str = NULL;
+ int64_t port_int = 0;
+ const char* path_str = NULL;
+ Dart_Handle result = ParseHttpUri(script_uri, &host_str, &port_int,
+ &path_str);
+ if (Dart_IsError(result)) {
+ return result;
+ }
+ const char* error_msg = NULL;
+ intptr_t len;
+ const uint8_t* text_buffer = HttpGetRequest(host_str, path_str, port_int,
+ &len, &error_msg);
+ if (text_buffer == NULL) {
+ return Dart_Error(error_msg);
+ }
+ const uint8_t* payload = HttpRequestGetPayload(
+ reinterpret_cast<const char*>(text_buffer));
+ if (payload == NULL) {
+ return Dart_Error("Invalid HTTP response.");
+ }
+ // Subtract HTTP response from length.
+ len -= (payload-text_buffer);
+ ASSERT(len >= 0);
+ Dart_Handle str = Dart_NewStringFromUTF8(payload, len);
+ return str;
+}
+
+
static const uint8_t* ReadFileFully(const char* filename,
intptr_t* file_len,
const char** error_msg) {
void* stream = DartUtils::OpenFile(filename, false);
if (stream == NULL) {
- const char* format = "Unable to open file: %s";
- intptr_t len = snprintf(NULL, 0, format, filename);
- // TODO(iposva): Allocate from the zone instead of leaking error string
- // here. On the other hand the binary is about the exit anyway.
- char* msg = reinterpret_cast<char*>(malloc(len + 1));
- snprintf(msg, len + 1, format, filename);
- *error_msg = msg;
+ SET_ERROR_MSG(error_msg, "Unable to open file: %s", filename);
return NULL;
}
*file_len = -1;
@@ -298,6 +512,32 @@
}
+static Dart_Handle SingleArgDart_Invoke(Dart_Handle arg, Dart_Handle lib,
+ const char* method) {
+ const int kNumArgs = 1;
+ Dart_Handle dart_args[kNumArgs];
+ dart_args[0] = arg;
+ return Dart_Invoke(lib, DartUtils::NewString(method), kNumArgs, dart_args);
+}
+
+Dart_Handle DartUtils::PathFromUri(Dart_Handle script_uri,
+ Dart_Handle builtin_lib) {
+ return SingleArgDart_Invoke(script_uri, builtin_lib, "_pathFromHttpUri");
+}
+
+
+Dart_Handle DartUtils::DomainFromUri(Dart_Handle script_uri,
+ Dart_Handle builtin_lib) {
+ return SingleArgDart_Invoke(script_uri, builtin_lib, "_domainFromHttpUri");
+}
+
+
+Dart_Handle DartUtils::PortFromUri(Dart_Handle script_uri,
+ Dart_Handle builtin_lib) {
+ return SingleArgDart_Invoke(script_uri, builtin_lib, "_portFromHttpUri");
+}
+
+
Dart_Handle DartUtils::ResolveUri(Dart_Handle library_url,
Dart_Handle url,
Dart_Handle builtin_lib) {
@@ -425,8 +665,57 @@
}
+Dart_Handle DartUtils::LoadScriptHttp(const char* script_uri,
+ Dart_Handle builtin_lib) {
+ Dart_Handle uri = NewString(script_uri);
+ if (Dart_IsError(uri)) {
+ return uri;
+ }
+ const char* host_str = NULL;
+ int64_t port_int = 0;
+ const char* path_str = NULL;
+ Dart_Handle result = ParseHttpUri(script_uri, &host_str, &port_int,
+ &path_str);
+ if (Dart_IsError(result)) {
+ return result;
+ }
+ const char* error_msg = NULL;
+ intptr_t len;
+ const uint8_t* text_buffer;
+ text_buffer = HttpGetRequest(host_str, path_str, port_int, &len,
+ &error_msg);
+ if (text_buffer == NULL) {
+ return Dart_Error(error_msg);
+ }
+ const uint8_t* payload = HttpRequestGetPayload(
+ reinterpret_cast<const char*>(text_buffer));
+ if (payload == NULL) {
+ return Dart_Error("Invalid HTTP response.");
+ }
+ // Subtract HTTP response from length.
+ len -= (payload-text_buffer);
+ ASSERT(len >= 0);
+ // At this point we have received a valid HTTP 200 reply and
+ // payload points at the beginning of the script or snapshot.
+ bool is_snapshot = false;
+ payload = SniffForMagicNumber(payload, &len, &is_snapshot);
+ if (is_snapshot) {
+ return Dart_LoadScriptFromSnapshot(payload, len);
+ } else {
+ Dart_Handle source = Dart_NewStringFromUTF8(payload, len);
+ if (Dart_IsError(source)) {
+ return source;
+ }
+ return Dart_LoadScript(uri, source, 0, 0);
+ }
+}
+
+
Dart_Handle DartUtils::LoadScript(const char* script_uri,
Dart_Handle builtin_lib) {
+ if (DartUtils::IsHttpSchemeURL(script_uri)) {
+ return LoadScriptHttp(script_uri, builtin_lib);
+ }
Dart_Handle resolved_script_uri;
resolved_script_uri = ResolveScriptUri(NewString(script_uri), builtin_lib);
if (Dart_IsError(resolved_script_uri)) {
@@ -466,6 +755,7 @@
Dart_Handle url,
Dart_LibraryTag tag,
const char* url_string) {
+ bool is_http_scheme_url = DartUtils::IsHttpSchemeURL(url_string);
if (url_mapping != NULL && IsDartSchemeURL(url_string)) {
const char* mapped_url_string = MapLibraryUrl(url_mapping, url_string);
if (mapped_url_string == NULL) {
@@ -475,12 +765,19 @@
// URL mapping specifies and load it.
url_string = mapped_url_string;
}
- // The tag is either an import or a source tag.
- // Read the file and load it according to the specified tag.
- Dart_Handle source = DartUtils::ReadStringFromFile(url_string);
+ Dart_Handle source;
+ if (is_http_scheme_url) {
+ // Read the file over http.
+ source = DartUtils::ReadStringFromHttp(url_string);
+ } else {
+ // Read the file.
+ source = DartUtils::ReadStringFromFile(url_string);
+ }
if (Dart_IsError(source)) {
return source; // source contains the error string.
}
+ // The tag is either an import or a source tag.
+ // Load it according to the specified tag.
if (tag == kImportTag) {
// Return library object or an error string.
return Dart_LoadLibrary(url, source);
diff --git a/runtime/bin/dartutils.h b/runtime/bin/dartutils.h
index 437570d..dcc67d1 100644
--- a/runtime/bin/dartutils.h
+++ b/runtime/bin/dartutils.h
@@ -106,6 +106,7 @@
static bool IsDartExtensionSchemeURL(const char* url_name);
static bool IsDartIOLibURL(const char* url_name);
static bool IsDartBuiltinLibURL(const char* url_name);
+ static bool IsHttpSchemeURL(const char* url_name);
static Dart_Handle CanonicalizeURL(CommandLineOptions* url_mapping,
Dart_Handle library,
const char* url_str);
@@ -114,11 +115,14 @@
static void WriteFile(const void* buffer, intptr_t num_bytes, void* stream);
static void CloseFile(void* stream);
static Dart_Handle ReadStringFromFile(const char* filename);
+ static Dart_Handle ReadStringFromHttp(const char* filename);
static Dart_Handle LibraryTagHandler(Dart_LibraryTag tag,
Dart_Handle library,
Dart_Handle url);
static Dart_Handle LoadScript(const char* script_uri,
Dart_Handle builtin_lib);
+ static Dart_Handle LoadScriptHttp(const char* script_uri,
+ Dart_Handle builtin_lib);
static Dart_Handle LoadSource(CommandLineOptions* url_mapping,
Dart_Handle library,
Dart_Handle url,
@@ -164,6 +168,15 @@
static Dart_Handle FilePathFromUri(Dart_Handle script_uri,
Dart_Handle builtin_lib);
+ static Dart_Handle PathFromUri(Dart_Handle script_uri,
+ Dart_Handle builtin_lib);
+
+ static Dart_Handle DomainFromUri(Dart_Handle script_uri,
+ Dart_Handle builtin_lib);
+
+ static Dart_Handle PortFromUri(Dart_Handle script_uri,
+ Dart_Handle builtin_lib);
+
static Dart_Handle ResolveUri(Dart_Handle library_url,
Dart_Handle url,
Dart_Handle builtin_lib);
@@ -191,6 +204,7 @@
static const char* kIOLibURL;
static const char* kIOLibPatchURL;
static const char* kUriLibURL;
+ static const char* kHttpScheme;
static const char* kIdFieldName;
diff --git a/runtime/bin/file.cc b/runtime/bin/file.cc
index b885f54..67d67e3 100644
--- a/runtime/bin/file.cc
+++ b/runtime/bin/file.cc
@@ -506,25 +506,6 @@
}
-void FUNCTION_NAME(File_Directory)(Dart_NativeArguments args) {
- Dart_EnterScope();
- const char* str =
- DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0));
- char* str_copy = strdup(str);
- char* path = File::GetContainingDirectory(str_copy);
- free(str_copy);
- if (path != NULL) {
- Dart_SetReturnValue(args, DartUtils::NewString(path));
- free(path);
- } else {
- Dart_Handle err = DartUtils::NewDartOSError();
- if (Dart_IsError(err)) Dart_PropagateError(err);
- Dart_SetReturnValue(args, err);
- }
- Dart_ExitScope();
-}
-
-
void FUNCTION_NAME(File_FullPath)(Dart_NativeArguments args) {
Dart_EnterScope();
const char* str =
@@ -735,24 +716,6 @@
}
-static CObject* FileDirectoryRequest(const CObjectArray& request) {
- if (request.Length() == 2 && request[1]->IsString()) {
- CObjectString filename(request[1]);
- char* str_copy = strdup(filename.CString());
- char* path = File::GetContainingDirectory(str_copy);
- free(str_copy);
- if (path != NULL) {
- CObject* result = new CObjectString(CObject::NewString(path));
- free(path);
- return result;
- } else {
- return CObject::NewOSError();
- }
- }
- return CObject::Null();
-}
-
-
static CObject* FileCloseRequest(const CObjectArray& request) {
intptr_t return_value = -1;
if (request.Length() == 2 && request[1]->IsIntptr()) {
@@ -1198,9 +1161,6 @@
case File::kFullPathRequest:
response = FileFullPathRequest(request);
break;
- case File::kDirectoryRequest:
- response = FileDirectoryRequest(request);
- break;
case File::kCloseRequest:
response = FileCloseRequest(request);
break;
diff --git a/runtime/bin/file.h b/runtime/bin/file.h
index cfc48c1..839c557 100644
--- a/runtime/bin/file.h
+++ b/runtime/bin/file.h
@@ -67,26 +67,25 @@
kDeleteRequest = 2,
kOpenRequest = 3,
kFullPathRequest = 4,
- kDirectoryRequest = 5,
- kCloseRequest = 6,
- kPositionRequest = 7,
- kSetPositionRequest = 8,
- kTruncateRequest = 9,
- kLengthRequest = 10,
- kLengthFromPathRequest = 11,
- kLastModifiedRequest = 12,
- kFlushRequest = 13,
- kReadByteRequest = 14,
- kWriteByteRequest = 15,
- kReadRequest = 16,
- kReadIntoRequest = 17,
- kWriteFromRequest = 18,
- kCreateLinkRequest = 19,
- kDeleteLinkRequest = 20,
- kLinkTargetRequest = 21,
- kTypeRequest = 22,
- kIdenticalRequest = 23,
- kStatRequest = 24
+ kCloseRequest = 5,
+ kPositionRequest = 6,
+ kSetPositionRequest = 7,
+ kTruncateRequest = 8,
+ kLengthRequest = 9,
+ kLengthFromPathRequest = 10,
+ kLastModifiedRequest = 11,
+ kFlushRequest = 12,
+ kReadByteRequest = 13,
+ kWriteByteRequest = 14,
+ kReadRequest = 15,
+ kReadIntoRequest = 16,
+ kWriteFromRequest = 17,
+ kCreateLinkRequest = 18,
+ kDeleteLinkRequest = 19,
+ kLinkTargetRequest = 20,
+ kTypeRequest = 21,
+ kIdenticalRequest = 22,
+ kStatRequest = 23
};
enum FileStat {
@@ -159,7 +158,6 @@
static char* LinkTarget(const char* pathname);
static bool IsAbsolutePath(const char* path);
static char* GetCanonicalPath(const char* path);
- static char* GetContainingDirectory(char* path);
static const char* PathSeparator();
static const char* StringEscapedPathSeparator();
static Type GetType(const char* path, bool follow_links);
diff --git a/runtime/bin/file_android.cc b/runtime/bin/file_android.cc
index b166aad..ba7ac88 100644
--- a/runtime/bin/file_android.cc
+++ b/runtime/bin/file_android.cc
@@ -281,25 +281,6 @@
}
-char* File::GetContainingDirectory(char* pathname) {
- // Report errors for non-regular files.
- struct stat st;
- if (TEMP_FAILURE_RETRY(stat(pathname, &st)) == 0) {
- if (!S_ISREG(st.st_mode)) {
- errno = (S_ISDIR(st.st_mode)) ? EISDIR : ENOENT;
- return NULL;
- }
- } else {
- return NULL;
- }
- char* path = NULL;
- do {
- path = dirname(pathname);
- } while (path == NULL && errno == EINTR);
- return GetCanonicalPath(path);
-}
-
-
const char* File::PathSeparator() {
return "/";
}
diff --git a/runtime/bin/file_linux.cc b/runtime/bin/file_linux.cc
index 7c4ddda..7d974a4 100644
--- a/runtime/bin/file_linux.cc
+++ b/runtime/bin/file_linux.cc
@@ -275,25 +275,6 @@
}
-char* File::GetContainingDirectory(char* pathname) {
- // Report errors for non-regular files.
- struct stat st;
- if (TEMP_FAILURE_RETRY(stat(pathname, &st)) == 0) {
- if (!S_ISREG(st.st_mode)) {
- errno = (S_ISDIR(st.st_mode)) ? EISDIR : ENOENT;
- return NULL;
- }
- } else {
- return NULL;
- }
- char* path = NULL;
- do {
- path = dirname(pathname);
- } while (path == NULL && errno == EINTR);
- return GetCanonicalPath(path);
-}
-
-
const char* File::PathSeparator() {
return "/";
}
diff --git a/runtime/bin/file_macos.cc b/runtime/bin/file_macos.cc
index c693f94..27f7177 100644
--- a/runtime/bin/file_macos.cc
+++ b/runtime/bin/file_macos.cc
@@ -283,25 +283,6 @@
}
-char* File::GetContainingDirectory(char* pathname) {
- // Report errors for non-regular files.
- struct stat st;
- if (TEMP_FAILURE_RETRY(stat(pathname, &st)) == 0) {
- if (!S_ISREG(st.st_mode)) {
- errno = (S_ISDIR(st.st_mode)) ? EISDIR : ENOENT;
- return NULL;
- }
- } else {
- return NULL;
- }
- char* path = NULL;
- do {
- path = dirname(pathname);
- } while (path == NULL && errno == EINTR);
- return GetCanonicalPath(path);
-}
-
-
const char* File::PathSeparator() {
return "/";
}
diff --git a/runtime/bin/file_patch.dart b/runtime/bin/file_patch.dart
index 65ac0a4..218c729 100644
--- a/runtime/bin/file_patch.dart
+++ b/runtime/bin/file_patch.dart
@@ -14,7 +14,6 @@
/* patch */ static _linkTarget(String path) native "File_LinkTarget";
/* patch */ static _delete(String path) native "File_Delete";
/* patch */ static _deleteLink(String path) native "File_DeleteLink";
- /* patch */ static _directory(String path) native "File_Directory";
/* 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 3162003..d0f4c82 100644
--- a/runtime/bin/file_win.cc
+++ b/runtime/bin/file_win.cc
@@ -458,39 +458,6 @@
}
-char* File::GetContainingDirectory(char* pathname) {
- struct _stat st;
- wchar_t* system_name = StringUtils::Utf8ToWide(pathname);
- int stat_status = _wstat(system_name, &st);
- if (stat_status == 0) {
- if ((st.st_mode & S_IFMT) != S_IFREG) {
- SetLastError(ERROR_FILE_NOT_FOUND);
- free(system_name);
- return NULL;
- }
- } else {
- SetLastError(ERROR_FILE_NOT_FOUND);
- free(system_name);
- return NULL;
- }
- int required_size = GetFullPathNameW(system_name, 0, NULL, NULL);
- wchar_t* path =
- static_cast<wchar_t*>(malloc(required_size * sizeof(wchar_t)));
- wchar_t* file_part = NULL;
- int written =
- GetFullPathNameW(system_name, required_size, path, &file_part);
- free(system_name);
- ASSERT(written == (required_size - 1));
- ASSERT(file_part != NULL);
- ASSERT(file_part > path);
- ASSERT(file_part[-1] == L'\\');
- file_part[-1] = '\0';
- char* result = StringUtils::WideToUtf8(path);
- free(path);
- return result;
-}
-
-
const char* File::PathSeparator() {
// This is already UTF-8 encoded.
return "\\";
diff --git a/runtime/bin/io_buffer.cc b/runtime/bin/io_buffer.cc
index 65fe234..cbef566 100644
--- a/runtime/bin/io_buffer.cc
+++ b/runtime/bin/io_buffer.cc
@@ -10,9 +10,9 @@
Dart_Handle IOBuffer::Allocate(intptr_t size, uint8_t **buffer) {
uint8_t* data = Allocate(size);
- Dart_Handle result = Dart_NewExternalTypedData(kUint8,
- data, size,
- data, IOBuffer::Finalizer);
+ Dart_Handle result = Dart_NewExternalTypedData(kUint8, data, size);
+ Dart_NewWeakPersistentHandle(result, data, IOBuffer::Finalizer);
+
if (Dart_IsError(result)) {
Free(data);
Dart_PropagateError(result);
diff --git a/runtime/bin/io_buffer.h b/runtime/bin/io_buffer.h
index 06ce0a6..1dfcc00 100644
--- a/runtime/bin/io_buffer.h
+++ b/runtime/bin/io_buffer.h
@@ -29,10 +29,10 @@
}
// Function for finalizing external byte arrays used as IO buffers.
- static void Finalizer(Dart_Handle handle, void* buffer) {
+ static void Finalizer(Dart_WeakPersistentHandle handle, void* buffer) {
Free(buffer);
if (handle != NULL) {
- Dart_DeletePersistentHandle(handle);
+ Dart_DeleteWeakPersistentHandle(handle);
}
}
diff --git a/runtime/bin/isolate_data.h b/runtime/bin/isolate_data.h
index 9b0806e..2992a08 100644
--- a/runtime/bin/isolate_data.h
+++ b/runtime/bin/isolate_data.h
@@ -26,9 +26,9 @@
}
EventHandler* event_handler;
- Dart_Handle object_array_class;
- Dart_Handle growable_object_array_class;
- Dart_Handle immutable_array_class;
+ Dart_PersistentHandle object_array_class;
+ Dart_PersistentHandle growable_object_array_class;
+ Dart_PersistentHandle immutable_array_class;
private:
DISALLOW_COPY_AND_ASSIGN(IsolateData);
diff --git a/runtime/bin/secure_socket.cc b/runtime/bin/secure_socket.cc
index 4f7bd6b..e785620 100644
--- a/runtime/bin/secure_socket.cc
+++ b/runtime/bin/secure_socket.cc
@@ -272,10 +272,15 @@
if (!library_initialized_) {
InitializeLibrary(NULL, "", true, false);
}
- string_start_ = ThrowIfError(
- Dart_NewPersistentHandle(DartUtils::NewString("start")));
- string_length_ = ThrowIfError(
- Dart_NewPersistentHandle(DartUtils::NewString("length")));
+ ASSERT(string_start_ == NULL);
+ string_start_ = Dart_NewPersistentHandle(DartUtils::NewString("start"));
+ ASSERT(string_start_ != NULL);
+ ASSERT(string_length_ == NULL);
+ string_length_ = Dart_NewPersistentHandle(DartUtils::NewString("length"));
+ ASSERT(string_length_ != NULL);
+ ASSERT(bad_certificate_callback_ == NULL);
+ bad_certificate_callback_ = Dart_NewPersistentHandle(Dart_Null());
+ ASSERT(bad_certificate_callback_ != NULL);
InitializeBuffers(dart_this);
filter_ = memio_CreateIOLayer(kMemioBufferSize);
@@ -313,29 +318,32 @@
Dart_Handle data_identifier = DartUtils::NewString("data");
for (int i = 0; i < kNumBuffers; ++i) {
int size = isEncrypted(i) ? encrypted_buffer_size_ : buffer_size_;
- dart_buffer_objects_[i] = ThrowIfError(
- Dart_NewPersistentHandle(Dart_ListGetAt(dart_buffers_object, i)));
+ dart_buffer_objects_[i] =
+ Dart_NewPersistentHandle(Dart_ListGetAt(dart_buffers_object, i));
+ ASSERT(dart_buffer_objects_[i] != NULL);
buffers_[i] = new uint8_t[size];
Dart_Handle data = ThrowIfError(
- Dart_NewExternalTypedData(kUint8, buffers_[i], size, NULL, NULL));
- ThrowIfError(Dart_SetField(dart_buffer_objects_[i],
- data_identifier,
- data));
+ Dart_NewExternalTypedData(kUint8, buffers_[i], size));
+ ThrowIfError(
+ Dart_SetField(Dart_HandleFromPersistent(dart_buffer_objects_[i]),
+ data_identifier,
+ data));
}
}
void SSLFilter::RegisterHandshakeCompleteCallback(Dart_Handle complete) {
ASSERT(NULL == handshake_complete_);
- handshake_complete_ = ThrowIfError(Dart_NewPersistentHandle(complete));
+ handshake_complete_ = Dart_NewPersistentHandle(complete);
+ ASSERT(handshake_complete_ != NULL);
}
void SSLFilter::RegisterBadCertificateCallback(Dart_Handle callback) {
- if (NULL != bad_certificate_callback_) {
- Dart_DeletePersistentHandle(bad_certificate_callback_);
- }
- bad_certificate_callback_ = ThrowIfError(Dart_NewPersistentHandle(callback));
+ ASSERT(bad_certificate_callback_ != NULL);
+ Dart_DeletePersistentHandle(bad_certificate_callback_);
+ bad_certificate_callback_ = Dart_NewPersistentHandle(callback);
+ ASSERT(bad_certificate_callback_ != NULL);
}
static const char* builtin_roots_module =
@@ -427,7 +435,7 @@
SECStatus BadCertificateCallback(void* filter, PRFileDesc* fd) {
SSLFilter* ssl_filter = static_cast<SSLFilter*>(filter);
Dart_Handle callback = ssl_filter->bad_certificate_callback();
- if (callback == NULL || Dart_IsNull(callback)) return SECFailure;
+ if (Dart_IsNull(callback)) return SECFailure;
Dart_EnterScope();
Dart_Handle x509_object = ssl_filter->PeerCertificate();
@@ -582,7 +590,8 @@
SECStatus status = SSL_ForceHandshake(filter_);
if (status == SECSuccess) {
if (in_handshake_) {
- ThrowIfError(Dart_InvokeClosure(handshake_complete_, 0, NULL));
+ ThrowIfError(Dart_InvokeClosure(
+ Dart_HandleFromPersistent(handshake_complete_), 0, NULL));
in_handshake_ = false;
}
} else {
@@ -610,9 +619,7 @@
Dart_DeletePersistentHandle(string_start_);
Dart_DeletePersistentHandle(string_length_);
Dart_DeletePersistentHandle(handshake_complete_);
- if (bad_certificate_callback_ != NULL) {
- Dart_DeletePersistentHandle(bad_certificate_callback_);
- }
+ Dart_DeletePersistentHandle(bad_certificate_callback_);
free(client_certificate_name_);
PR_Close(filter_);
@@ -621,11 +628,12 @@
intptr_t SSLFilter::ProcessBuffer(int buffer_index) {
int size = isEncrypted(buffer_index) ? encrypted_buffer_size_ : buffer_size_;
- Dart_Handle buffer_object = dart_buffer_objects_[buffer_index];
+ Dart_Handle buffer_object =
+ Dart_HandleFromPersistent(dart_buffer_objects_[buffer_index]);
Dart_Handle start_object = ThrowIfError(
- Dart_GetField(buffer_object, string_start_));
+ Dart_GetField(buffer_object, Dart_HandleFromPersistent(string_start_)));
Dart_Handle length_object = ThrowIfError(
- Dart_GetField(buffer_object, string_length_));
+ Dart_GetField(buffer_object, Dart_HandleFromPersistent(string_length_)));
int64_t unsafe_start = DartUtils::GetIntegerValue(start_object);
int64_t unsafe_length = DartUtils::GetIntegerValue(length_object);
ASSERT(unsafe_start >= 0);
diff --git a/runtime/bin/secure_socket.h b/runtime/bin/secure_socket.h
index 88b4c73..0eecd3c 100644
--- a/runtime/bin/secure_socket.h
+++ b/runtime/bin/secure_socket.h
@@ -89,7 +89,9 @@
void Handshake();
void RegisterHandshakeCompleteCallback(Dart_Handle handshake_complete);
void RegisterBadCertificateCallback(Dart_Handle callback);
- Dart_Handle bad_certificate_callback() { return bad_certificate_callback_; }
+ Dart_Handle bad_certificate_callback() {
+ return Dart_HandleFromPersistent(bad_certificate_callback_);
+ }
static void InitializeLibrary(const char* certificate_database,
const char* password,
bool use_builtin_root_certificates,
@@ -106,11 +108,11 @@
uint8_t* buffers_[kNumBuffers];
int buffer_size_;
int encrypted_buffer_size_;
- Dart_Handle string_start_;
- Dart_Handle string_length_;
- Dart_Handle dart_buffer_objects_[kNumBuffers];
- Dart_Handle handshake_complete_;
- Dart_Handle bad_certificate_callback_;
+ Dart_PersistentHandle string_start_;
+ Dart_PersistentHandle string_length_;
+ Dart_PersistentHandle dart_buffer_objects_[kNumBuffers];
+ Dart_PersistentHandle handshake_complete_;
+ Dart_PersistentHandle bad_certificate_callback_;
bool in_handshake_;
bool is_server_;
char* client_certificate_name_;
diff --git a/runtime/bin/socket.h b/runtime/bin/socket.h
index 5c191a0..46780fc 100644
--- a/runtime/bin/socket.h
+++ b/runtime/bin/socket.h
@@ -130,6 +130,8 @@
static intptr_t Available(intptr_t fd);
static int Read(intptr_t fd, void* buffer, intptr_t num_bytes);
static int Write(intptr_t fd, const void* buffer, intptr_t num_bytes);
+ static intptr_t Create(RawAddr addr);
+ static intptr_t Connect(intptr_t fd, RawAddr addr, const intptr_t port);
static intptr_t CreateConnect(RawAddr addr,
const intptr_t port);
static intptr_t GetPort(intptr_t fd);
diff --git a/runtime/bin/socket_android.cc b/runtime/bin/socket_android.cc
index 20715a3..c0fbacd 100644
--- a/runtime/bin/socket_android.cc
+++ b/runtime/bin/socket_android.cc
@@ -42,18 +42,21 @@
}
-intptr_t Socket::CreateConnect(RawAddr addr, const intptr_t port) {
+intptr_t Socket::Create(RawAddr addr) {
intptr_t fd;
fd = TEMP_FAILURE_RETRY(socket(addr.ss.ss_family, SOCK_STREAM, 0));
if (fd < 0) {
- Log::PrintErr("Error CreateConnect: %s\n", strerror(errno));
+ Log::PrintErr("Error Create: %s\n", strerror(errno));
return -1;
}
FDUtils::SetCloseOnExec(fd);
- Socket::SetNonBlocking(fd);
+ return fd;
+}
+
+intptr_t Socket::Connect(intptr_t fd, RawAddr addr, const intptr_t port) {
SocketAddress::SetAddrPort(&addr, port);
intptr_t result = TEMP_FAILURE_RETRY(
connect(fd,
@@ -62,11 +65,23 @@
if (result == 0 || errno == EINPROGRESS) {
return fd;
}
- TEMP_FAILURE_RETRY(close(fd));
+ VOID_TEMP_FAILURE_RETRY(close(fd));
return -1;
}
+intptr_t Socket::CreateConnect(RawAddr addr, const intptr_t port) {
+ intptr_t fd = Socket::Create(addr);
+ if (fd < 0) {
+ return fd;
+ }
+
+ Socket::SetNonBlocking(fd);
+
+ return Socket::Connect(fd, addr, port);
+}
+
+
intptr_t Socket::Available(intptr_t fd) {
return FDUtils::AvailableBytes(fd);
}
diff --git a/runtime/bin/socket_linux.cc b/runtime/bin/socket_linux.cc
index cfc9b12..04ecbe7 100644
--- a/runtime/bin/socket_linux.cc
+++ b/runtime/bin/socket_linux.cc
@@ -42,18 +42,21 @@
}
-intptr_t Socket::CreateConnect(RawAddr addr, const intptr_t port) {
+intptr_t Socket::Create(RawAddr addr) {
intptr_t fd;
fd = TEMP_FAILURE_RETRY(socket(addr.ss.ss_family, SOCK_STREAM, 0));
if (fd < 0) {
- Log::PrintErr("Error CreateConnect: %s\n", strerror(errno));
+ Log::PrintErr("Error Create: %s\n", strerror(errno));
return -1;
}
FDUtils::SetCloseOnExec(fd);
- Socket::SetNonBlocking(fd);
+ return fd;
+}
+
+intptr_t Socket::Connect(intptr_t fd, RawAddr addr, const intptr_t port) {
SocketAddress::SetAddrPort(&addr, port);
intptr_t result = TEMP_FAILURE_RETRY(
connect(fd,
@@ -62,11 +65,23 @@
if (result == 0 || errno == EINPROGRESS) {
return fd;
}
- TEMP_FAILURE_RETRY(close(fd));
+ VOID_TEMP_FAILURE_RETRY(close(fd));
return -1;
}
+intptr_t Socket::CreateConnect(RawAddr addr, const intptr_t port) {
+ intptr_t fd = Socket::Create(addr);
+ if (fd < 0) {
+ return fd;
+ }
+
+ Socket::SetNonBlocking(fd);
+
+ return Socket::Connect(fd, addr, port);
+}
+
+
intptr_t Socket::Available(intptr_t fd) {
return FDUtils::AvailableBytes(fd);
}
diff --git a/runtime/bin/socket_macos.cc b/runtime/bin/socket_macos.cc
index 94363fb..40b92cf 100644
--- a/runtime/bin/socket_macos.cc
+++ b/runtime/bin/socket_macos.cc
@@ -42,18 +42,21 @@
}
-intptr_t Socket::CreateConnect(RawAddr addr, const intptr_t port) {
+intptr_t Socket::Create(RawAddr addr) {
intptr_t fd;
fd = TEMP_FAILURE_RETRY(socket(addr.ss.ss_family, SOCK_STREAM, 0));
if (fd < 0) {
- Log::PrintErr("Error CreateConnect: %s\n", strerror(errno));
+ Log::PrintErr("Error Create: %s\n", strerror(errno));
return -1;
}
FDUtils::SetCloseOnExec(fd);
- Socket::SetNonBlocking(fd);
+ return fd;
+}
+
+intptr_t Socket::Connect(intptr_t fd, RawAddr addr, const intptr_t port) {
SocketAddress::SetAddrPort(&addr, port);
intptr_t result = TEMP_FAILURE_RETRY(
connect(fd,
@@ -67,6 +70,18 @@
}
+intptr_t Socket::CreateConnect(RawAddr addr, const intptr_t port) {
+ intptr_t fd = Socket::Create(addr);
+ if (fd < 0) {
+ return fd;
+ }
+
+ Socket::SetNonBlocking(fd);
+
+ return Socket::Connect(fd, addr, port);
+}
+
+
intptr_t Socket::Available(intptr_t fd) {
return FDUtils::AvailableBytes(fd);
}
diff --git a/runtime/bin/socket_patch.dart b/runtime/bin/socket_patch.dart
index d86a17c..d603532 100644
--- a/runtime/bin/socket_patch.dart
+++ b/runtime/bin/socket_patch.dart
@@ -558,7 +558,7 @@
}
_RawServerSocket(this._socket) {
- _controller = new StreamController(
+ _controller = new StreamController(sync: true,
onListen: _onSubscriptionStateChange,
onCancel: _onSubscriptionStateChange,
onPause: _onPauseStateChange,
@@ -630,7 +630,7 @@
}
_RawSocket(this._socket) {
- _controller = new StreamController(
+ _controller = new StreamController(sync: true,
onListen: _onSubscriptionStateChange,
onCancel: _onSubscriptionStateChange,
onPause: _onPauseStateChange,
@@ -886,7 +886,7 @@
var _detachReady;
_Socket(RawSocket this._raw) {
- _controller = new StreamController<List<int>>(
+ _controller = new StreamController<List<int>>(sync: true,
onListen: _onSubscriptionStateChange,
onCancel: _onSubscriptionStateChange,
onPause: _onPauseStateChange,
diff --git a/runtime/bin/socket_win.cc b/runtime/bin/socket_win.cc
index 60a6163..ec54765 100644
--- a/runtime/bin/socket_win.cc
+++ b/runtime/bin/socket_win.cc
@@ -113,7 +113,8 @@
return true;
}
-intptr_t Socket::CreateConnect(RawAddr addr, const intptr_t port) {
+
+intptr_t Socket::Create(RawAddr addr) {
SOCKET s = socket(addr.ss.ss_family, SOCK_STREAM, 0);
if (s == INVALID_SOCKET) {
return -1;
@@ -131,20 +132,35 @@
FATAL("Failed setting SO_LINGER on socket");
}
+ ClientSocket* client_socket = new ClientSocket(s);
+ return reinterpret_cast<intptr_t>(client_socket);
+}
+
+
+intptr_t Socket::Connect(intptr_t fd, RawAddr addr, const intptr_t port) {
+ ASSERT(reinterpret_cast<Handle*>(fd)->is_socket());
+ SocketHandle* handle = reinterpret_cast<SocketHandle*>(fd);
+ SOCKET s = handle->socket();
SocketAddress::SetAddrPort(&addr, port);
- status = connect(
- s,
- &addr.addr,
- SocketAddress::GetAddrLength(addr));
+ int status = connect(s, &addr.addr, SocketAddress::GetAddrLength(addr));
if (status == SOCKET_ERROR) {
DWORD rc = WSAGetLastError();
- closesocket(s);
+ ClientSocket* client_socket = reinterpret_cast<ClientSocket*>(fd);
+ client_socket->Close();
SetLastError(rc);
return -1;
}
+ return fd;
+}
- ClientSocket* client_socket = new ClientSocket(s);
- return reinterpret_cast<intptr_t>(client_socket);
+
+intptr_t Socket::CreateConnect(RawAddr addr, const intptr_t port) {
+ intptr_t fd = Socket::Create(addr);
+ if (fd < 0) {
+ return fd;
+ }
+
+ return Socket::Connect(fd, addr, port);
}
diff --git a/runtime/include/dart_api.h b/runtime/include/dart_api.h
index bbaed07..abb5a6c 100755
--- a/runtime/include/dart_api.h
+++ b/runtime/include/dart_api.h
@@ -176,9 +176,12 @@
* deallocated (see Dart_DeletePersistentHandle).
*/
typedef struct _Dart_Handle* Dart_Handle;
+typedef struct _Dart_PersistentHandle* Dart_PersistentHandle;
+typedef struct _Dart_WeakPersistentHandle* Dart_WeakPersistentHandle;
-typedef void (*Dart_WeakPersistentHandleFinalizer)(Dart_Handle handle,
- void* peer);
+typedef void (*Dart_WeakPersistentHandleFinalizer)(
+ Dart_WeakPersistentHandle handle,
+ void* peer);
typedef void (*Dart_PeerFinalizer)(void* peer);
/**
@@ -361,6 +364,17 @@
DART_EXPORT bool Dart_IdentityEquals(Dart_Handle obj1, Dart_Handle obj2);
/**
+ * Allocates a handle in the current scope from a persistent handle.
+ */
+DART_EXPORT Dart_Handle Dart_HandleFromPersistent(Dart_PersistentHandle object);
+
+/**
+ * Allocates a handle in the current scope from a weak persistent handle.
+ */
+DART_EXPORT Dart_Handle Dart_HandleFromWeakPersistent(
+ Dart_WeakPersistentHandle object);
+
+/**
* Allocates a persistent handle for an object.
*
* This handle has the lifetime of the current isolate unless it is
@@ -368,14 +382,14 @@
*
* Requires there to be a current isolate.
*/
-DART_EXPORT Dart_Handle Dart_NewPersistentHandle(Dart_Handle object);
+DART_EXPORT Dart_PersistentHandle Dart_NewPersistentHandle(Dart_Handle object);
/**
* Deallocates a persistent handle.
*
* Requires there to be a current isolate.
*/
-DART_EXPORT void Dart_DeletePersistentHandle(Dart_Handle object);
+DART_EXPORT void Dart_DeletePersistentHandle(Dart_PersistentHandle object);
/**
* Allocates a weak persistent handle for an object.
@@ -394,17 +408,13 @@
* \return Success if the weak persistent handle was
* created. Otherwise, returns an error.
*/
-DART_EXPORT Dart_Handle Dart_NewWeakPersistentHandle(
+DART_EXPORT Dart_WeakPersistentHandle Dart_NewWeakPersistentHandle(
Dart_Handle object,
void* peer,
Dart_WeakPersistentHandleFinalizer callback);
-/**
- * Is this object a weak persistent handle?
- *
- * Requires there to be a current isolate.
- */
-DART_EXPORT bool Dart_IsWeakPersistentHandle(Dart_Handle object);
+DART_EXPORT void Dart_DeleteWeakPersistentHandle(
+ Dart_WeakPersistentHandle object);
/**
* Allocates a prologue weak persistent handle for an object.
@@ -432,7 +442,7 @@
* \return Success if the prologue weak persistent handle was created.
* Otherwise, returns an error.
*/
-DART_EXPORT Dart_Handle Dart_NewPrologueWeakPersistentHandle(
+DART_EXPORT Dart_WeakPersistentHandle Dart_NewPrologueWeakPersistentHandle(
Dart_Handle object,
void* peer,
Dart_WeakPersistentHandleFinalizer callback);
@@ -442,7 +452,8 @@
*
* Requires there to be a current isolate.
*/
-DART_EXPORT bool Dart_IsPrologueWeakPersistentHandle(Dart_Handle object);
+DART_EXPORT bool Dart_IsPrologueWeakPersistentHandle(
+ Dart_WeakPersistentHandle object);
/**
* Constructs a set of weak references from the Cartesian product of
@@ -459,10 +470,11 @@
* \return Success if the weak reference set could be created.
* Otherwise, returns an error handle.
*/
-DART_EXPORT Dart_Handle Dart_NewWeakReferenceSet(Dart_Handle* keys,
- intptr_t num_keys,
- Dart_Handle* values,
- intptr_t num_values);
+DART_EXPORT Dart_Handle Dart_NewWeakReferenceSet(
+ Dart_WeakPersistentHandle* keys,
+ intptr_t num_keys,
+ Dart_WeakPersistentHandle* values,
+ intptr_t num_values);
// --- Garbage Collection Callbacks ---
@@ -1766,18 +1778,9 @@
* WeakPersistentHandle which needs to be deleted in the specified callback
* using Dart_DeletePersistentHandle.
*/
-DART_EXPORT Dart_Handle Dart_NewExternalTypedData(
- Dart_TypedData_Type type,
- void* data,
- intptr_t length,
- void* peer,
- Dart_WeakPersistentHandleFinalizer callback);
-
-/**
- * Retrieves the peer pointer associated with an external TypedData object.
- */
-DART_EXPORT Dart_Handle Dart_ExternalTypedDataGetPeer(Dart_Handle object,
- void** peer);
+DART_EXPORT Dart_Handle Dart_NewExternalTypedData(Dart_TypedData_Type type,
+ void* data,
+ intptr_t length);
/**
* Acquires access to the internal data address of a TypedData object.
diff --git a/runtime/lib/mirrors.cc b/runtime/lib/mirrors.cc
index 62c22e0..790f6f6 100644
--- a/runtime/lib/mirrors.cc
+++ b/runtime/lib/mirrors.cc
@@ -88,10 +88,11 @@
}
-static void FreeVMReference(Dart_Handle weak_ref, void* data) {
- Dart_Handle perm_handle = reinterpret_cast<Dart_Handle>(data);
+static void FreeVMReference(Dart_WeakPersistentHandle weak_ref, void* data) {
+ Dart_PersistentHandle perm_handle =
+ reinterpret_cast<Dart_PersistentHandle>(data);
Dart_DeletePersistentHandle(perm_handle);
- Dart_DeletePersistentHandle(weak_ref);
+ Dart_DeleteWeakPersistentHandle(weak_ref);
}
@@ -108,10 +109,8 @@
}
// Allocate a persistent handle.
- Dart_Handle perm_handle = Dart_NewPersistentHandle(handle);
- if (Dart_IsError(perm_handle)) {
- return perm_handle;
- }
+ Dart_PersistentHandle perm_handle = Dart_NewPersistentHandle(handle);
+ ASSERT(perm_handle != NULL);
// Store the persistent handle in the VMReference.
intptr_t perm_handle_value = reinterpret_cast<intptr_t>(perm_handle);
@@ -126,12 +125,9 @@
// the VMReference is collected, so we can release the persistent
// handle.
void* perm_handle_data = reinterpret_cast<void*>(perm_handle);
- Dart_Handle weak_ref =
+ Dart_WeakPersistentHandle weak_ref =
Dart_NewWeakPersistentHandle(vm_ref, perm_handle_data, FreeVMReference);
- if (Dart_IsError(weak_ref)) {
- Dart_DeletePersistentHandle(perm_handle);
- return weak_ref;
- }
+ ASSERT(weak_ref != NULL);
// Success.
return vm_ref;
@@ -146,9 +142,13 @@
if (Dart_IsError(result)) {
return result;
}
- Dart_Handle perm_handle = reinterpret_cast<Dart_Handle>(perm_handle_value);
- ASSERT(!Dart_IsError(perm_handle));
- return perm_handle;
+ Dart_PersistentHandle perm_handle =
+ reinterpret_cast<Dart_PersistentHandle>(perm_handle_value);
+ ASSERT(perm_handle != NULL);
+ Dart_Handle handle = Dart_HandleFromPersistent(perm_handle);
+ ASSERT(handle != NULL);
+ ASSERT(!Dart_IsError(handle));
+ return handle;
}
diff --git a/runtime/lib/typed_data.cc b/runtime/lib/typed_data.cc
index a4f37b3..b1b2632 100644
--- a/runtime/lib/typed_data.cc
+++ b/runtime/lib/typed_data.cc
@@ -59,8 +59,8 @@
}
-static void PeerFinalizer(Dart_Handle handle, void* peer) {
- Dart_DeletePersistentHandle(handle);
+ static void PeerFinalizer(Dart_WeakPersistentHandle handle, void* peer) {
+ Dart_DeleteWeakPersistentHandle(handle);
OS::AlignedFree(peer);
}
diff --git a/runtime/lib/typed_data.dart b/runtime/lib/typed_data.dart
index 8cf462f..04f6fa9 100644
--- a/runtime/lib/typed_data.dart
+++ b/runtime/lib/typed_data.dart
@@ -282,14 +282,14 @@
// Method(s) implementing the Collection interface.
bool contains(element) => IterableMixinWorkaround.contains(this, element);
- void forEach(void f(element)) {
+ void forEach(void f(num element)) {
var len = this.length;
for (var i = 0; i < len; i++) {
f(this[i]);
}
}
- Iterable map(f(int element)) {
+ Iterable map(f(num element)) {
return IterableMixinWorkaround.mapList(this, f);
}
@@ -297,20 +297,20 @@
return IterableMixinWorkaround.join(this, separator);
}
- dynamic reduce(dynamic combine(value, element)) {
+ num reduce(dynamic combine(num value, num element)) {
return IterableMixinWorkaround.reduce(this, combine);
}
dynamic fold(dynamic initialValue,
- dynamic combine(dynamic initialValue, element)) {
+ dynamic combine(dynamic initialValue, num element)) {
return IterableMixinWorkaround.fold(this, initialValue, combine);
}
- Iterable where(bool f(int element)) {
+ Iterable where(bool f(num element)) {
return IterableMixinWorkaround.where(this, f);
}
- Iterable expand(Iterable f(int element)) {
+ Iterable expand(Iterable f(num element)) {
return IterableMixinWorkaround.expand(this, f);
}
@@ -318,7 +318,7 @@
return IterableMixinWorkaround.takeList(this, n);
}
- Iterable takeWhile(bool test(int value)) {
+ Iterable takeWhile(bool test(num element)) {
return IterableMixinWorkaround.takeWhile(this, test);
}
@@ -326,31 +326,31 @@
return IterableMixinWorkaround.skipList(this, n);
}
- Iterable skipWhile(bool test(int value)) {
+ Iterable skipWhile(bool test(num element)) {
return IterableMixinWorkaround.skipWhile(this, test);
}
- bool every(bool f(element)) {
+ bool every(bool f(num element)) {
return IterableMixinWorkaround.every(this, f);
}
- bool any(bool f(element)) {
+ bool any(bool f(num element)) {
return IterableMixinWorkaround.any(this, f);
}
- int firstWhere(bool test(int value), {int orElse()}) {
+ num firstWhere(bool test(num element), {orElse()}) {
return IterableMixinWorkaround.firstWhere(this, test, orElse);
}
- int lastWhere(bool test(int value), {int orElse()}) {
+ num lastWhere(bool test(num element), {orElse()}) {
return IterableMixinWorkaround.lastWhereList(this, test, orElse);
}
- int singleWhere(bool test(int value)) {
+ num singleWhere(bool test(num element)) {
return IterableMixinWorkaround.singleWhere(this, test);
}
- int elementAt(int index) {
+ num elementAt(int index) {
return this[index];
}
@@ -387,7 +387,7 @@
"Cannot insert into a non-extendable array");
}
- void sort([int compare(var a, var b)]) {
+ void sort([int compare(num a, num b)]) {
return IterableMixinWorkaround.sortList(this, compare);
}
@@ -429,27 +429,27 @@
"Cannot remove from a non-extendable array");
}
- void removeWhere(bool test(int element)) {
+ void removeWhere(bool test(element)) {
throw new UnsupportedError(
"Cannot remove from a non-extendable array");
}
- void retainWhere(bool test(int element)) {
+ void retainWhere(bool test(element)) {
throw new UnsupportedError(
"Cannot remove from a non-extendable array");
}
- int get first {
+ num get first {
if (length > 0) return this[0];
throw new StateError("No elements");
}
- int get last {
+ num get last {
if (length > 0) return this[length - 1];
throw new StateError("No elements");
}
- int get single {
+ num get single {
if (length == 1) return this[0];
if (length == 0) throw new StateError("No elements");
throw new StateError("More than one element");
@@ -497,7 +497,7 @@
IterableMixinWorkaround.setAllList(this, index, iterable);
}
- void fillRange(int start, int end, [fillValue]) {
+ void fillRange(int start, int end, [num fillValue]) {
IterableMixinWorkaround.fillRangeList(this, start, end, fillValue);
}
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index 4fe49fc..b849809 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -54,13 +54,13 @@
# Skip until we stabilize language tests.
*: Skip
+[ $arch == arm ]
+*: Skip
+
[ $arch == simarm ]
-# Tests missing code generation support.
-cc/Dart2JSCompileAll: Skip
-cc/CorelibCompileAll: Skip
-cc/ParsePatchLibrary: Skip
-dart/byte_array_test: Skip
-dart/byte_array_optimized_test: Skip
+# Bug in optimized code generation.
+dart/byte_array_test: Fail
+dart/byte_array_optimized_test: Fail
[ $arch == mips ]
*: Skip
diff --git a/runtime/vm/assembler_arm.cc b/runtime/vm/assembler_arm.cc
index b84ff57..c1803e2 100644
--- a/runtime/vm/assembler_arm.cc
+++ b/runtime/vm/assembler_arm.cc
@@ -1243,29 +1243,6 @@
}
-void Assembler::mrc(Register rd, int32_t coproc, int32_t opc1,
- int32_t crn, int32_t crm, int32_t opc2, Condition cond) {
- ASSERT(rd != kNoRegister);
- ASSERT(cond != kNoCondition);
-
- // This is all the simulator and disassembler know about.
- ASSERT(coproc == 15);
- ASSERT(opc1 == 0);
- ASSERT(crn == 0);
- ASSERT(crm == 2);
- ASSERT(opc2 == 0);
- int32_t encoding = (static_cast<int32_t>(cond) << kConditionShift) |
- B27 | B26 | B25 | B20 | B4 |
- ((opc1 & 0x7) << kOpc1Shift) |
- ((crn & 0xf) << kCRnShift) |
- ((coproc & 0xf) << kCoprocShift) |
- ((opc2 & 0x7) << kOpc2Shift) |
- ((crm & 0xf) << kCRmShift) |
- (static_cast<int32_t>(rd) << kRdShift);
- Emit(encoding);
-}
-
-
void Assembler::MarkExceptionHandler(Label* label) {
EmitType01(AL, 1, TST, 1, PC, R0, ShifterOperand(0));
Label l;
@@ -1504,8 +1481,9 @@
}
case kLoadSWord:
case kLoadDWord: {
- *offset_mask = 0x3ff;
- return Utils::IsAbsoluteUint(10, offset); // VFP addressing mode.
+ *offset_mask = 0x3fc; // Multiple of 4.
+ // VFP addressing mode.
+ return (Utils::IsAbsoluteUint(10, offset) && Utils::IsAligned(offset, 4));
}
default: {
UNREACHABLE();
@@ -1531,8 +1509,9 @@
}
case kStoreSWord:
case kStoreDWord: {
- *offset_mask = 0x3ff;
- return Utils::IsAbsoluteUint(10, offset); // VFP addressing mode.
+ *offset_mask = 0x3fc; // Multiple of 4.
+ // VFP addressing mode.
+ return (Utils::IsAbsoluteUint(10, offset) && Utils::IsAligned(offset, 4));
}
default: {
UNREACHABLE();
@@ -1562,7 +1541,7 @@
}
-void Assembler::Mov(Register rd, Register rm, Condition cond) {
+void Assembler::MoveRegister(Register rd, Register rm, Condition cond) {
if (rd != rm) {
mov(rd, ShifterOperand(rm), cond);
}
@@ -1576,6 +1555,11 @@
}
+void Assembler::Lsl(Register rd, Register rm, Register rs, Condition cond) {
+ mov(rd, ShifterOperand(rm, LSL, rs), cond);
+}
+
+
void Assembler::Lsr(Register rd, Register rm, uint32_t shift_imm,
Condition cond) {
ASSERT(shift_imm != 0); // Do not use Lsr if no shift is wanted.
@@ -1584,6 +1568,11 @@
}
+void Assembler::Lsr(Register rd, Register rm, Register rs, Condition cond) {
+ mov(rd, ShifterOperand(rm, LSR, rs), cond);
+}
+
+
void Assembler::Asr(Register rd, Register rm, uint32_t shift_imm,
Condition cond) {
ASSERT(shift_imm != 0); // Do not use Asr if no shift is wanted.
@@ -1592,6 +1581,11 @@
}
+void Assembler::Asr(Register rd, Register rm, Register rs, Condition cond) {
+ mov(rd, ShifterOperand(rm, ASR, rs), cond);
+}
+
+
void Assembler::Ror(Register rd, Register rm, uint32_t shift_imm,
Condition cond) {
ASSERT(shift_imm != 0); // Use Rrx instruction.
@@ -1599,6 +1593,11 @@
}
+void Assembler::Ror(Register rd, Register rm, Register rs, Condition cond) {
+ mov(rd, ShifterOperand(rm, ROR, rs), cond);
+}
+
+
void Assembler::Rrx(Register rd, Register rm, Condition cond) {
mov(rd, ShifterOperand(rm, ROR, 0), cond);
}
diff --git a/runtime/vm/assembler_arm.h b/runtime/vm/assembler_arm.h
index 4ee373b..5cddcab 100644
--- a/runtime/vm/assembler_arm.h
+++ b/runtime/vm/assembler_arm.h
@@ -514,10 +514,6 @@
void bx(Register rm, Condition cond = AL);
void blx(Register rm, Condition cond = AL);
- // Move to ARM core register from Coprocessor.
- void mrc(Register rd, int32_t coproc, int32_t opc1,
- int32_t crn, int32_t crm, int32_t opc2, Condition cond = AL);
-
// Macros.
// Branch to an entry address. Call sequence is never patched.
void Branch(const ExternalLabel* label, Condition cond = AL);
@@ -617,14 +613,18 @@
void PushList(RegList regs, Condition cond = AL);
void PopList(RegList regs, Condition cond = AL);
- void Mov(Register rd, Register rm, Condition cond = AL);
+ void MoveRegister(Register rd, Register rm, Condition cond = AL);
// Convenience shift instructions. Use mov instruction with shifter operand
- // for variants setting the status flags or using a register shift count.
+ // for variants setting the status flags.
void Lsl(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL);
+ void Lsl(Register rd, Register rm, Register rs, Condition cond = AL);
void Lsr(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL);
+ void Lsr(Register rd, Register rm, Register rs, Condition cond = AL);
void Asr(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL);
+ void Asr(Register rd, Register rm, Register rs, Condition cond = AL);
void Ror(Register rd, Register rm, uint32_t shift_imm, Condition cond = AL);
+ void Ror(Register rd, Register rm, Register rs, Condition cond = AL);
void Rrx(Register rd, Register rm, Condition cond = AL);
void SmiTag(Register reg, Condition cond = AL) {
diff --git a/runtime/vm/assembler_arm_test.cc b/runtime/vm/assembler_arm_test.cc
index 838bb69..0c0296d 100644
--- a/runtime/vm/assembler_arm_test.cc
+++ b/runtime/vm/assembler_arm_test.cc
@@ -637,7 +637,7 @@
ASSEMBLER_TEST_GENERATE(Multiply64To64, assembler) {
__ Push(R4);
- __ Mov(IP, R0);
+ __ mov(IP, ShifterOperand(R0));
__ mul(R4, R2, R1);
__ umull(R0, R1, R2, IP);
__ mla(R2, IP, R3, R4);
@@ -936,7 +936,7 @@
ASSEMBLER_TEST_GENERATE(Ldrd, assembler) {
- __ Mov(IP, SP);
+ __ mov(IP, ShifterOperand(SP));
__ strd(R2, Address(SP, (-kWordSize * 30), Address::PreIndex));
__ strd(R0, Address(IP, (-kWordSize * 28)));
__ ldrd(R2, Address(IP, (-kWordSize * 28)));
@@ -1418,76 +1418,12 @@
}
-// Check that assembler mrc instruction encoding, and simulator decoding
-// are in agreement.
-#if defined(USING_SIMULATOR)
-ASSEMBLER_TEST_GENERATE(MrcHaveDiv, assembler) {
- __ mrc(R0, 15, 0, 0, 2, 0); // Accesses ID_ISAR0.
- // Bits 24 - 27 describe the presence of integer division. Bit 24 is set if
- // it is available in the Thumb instruction set. Bit 25 is set if it is
- // available both in Thumb and in the ARM instruction set.
- __ Lsr(R0, R0, 24);
- __ and_(R0, R0, ShifterOperand(0xf));
- __ bx(LR);
-}
-
-
-ASSEMBLER_TEST_RUN(MrcHaveDiv, test) {
- EXPECT(test != NULL);
- typedef int (*Tst)();
- bool b = CPUFeatures::integer_division_supported();
- CPUFeatures::set_integer_division_supported(true);
- EXPECT_EQ(2, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
- CPUFeatures::set_integer_division_supported(b);
-}
-
-
-ASSEMBLER_TEST_GENERATE(MrcNoDiv, assembler) {
- __ mrc(R0, 15, 0, 0, 2, 0);
- __ Lsr(R0, R0, 24);
- __ and_(R0, R0, ShifterOperand(0xf));
- __ bx(LR);
-}
-
-
-ASSEMBLER_TEST_RUN(MrcNoDiv, test) {
- EXPECT(test != NULL);
- typedef int (*Tst)();
- bool b = CPUFeatures::integer_division_supported();
- CPUFeatures::set_integer_division_supported(false);
- EXPECT_EQ(0, EXECUTE_TEST_CODE_INT32(Tst, test->entry()));
- CPUFeatures::set_integer_division_supported(b);
-}
-
-
-ASSEMBLER_TEST_GENERATE(MrcReal, assembler) {
- __ mrc(R0, 15, 0, 0, 2, 0);
- __ Lsr(R0, R0, 24);
- __ and_(R0, R0, ShifterOperand(0xf));
- __ bx(LR);
-}
-
-
-ASSEMBLER_TEST_RUN(MrcReal, test) {
- EXPECT(test != NULL);
- typedef int (*Tst)();
- bool have_div = CPUFeatures::integer_division_supported();
- int32_t r = EXECUTE_TEST_CODE_INT32(Tst, test->entry());
- if (have_div) {
- EXPECT_EQ(2, r);
- } else {
- EXPECT_EQ(0, r);
- }
-}
-#endif // defined(USING_SIMULATOR)
-
-
ASSEMBLER_TEST_GENERATE(Udiv, assembler) {
if (CPUFeatures::integer_division_supported()) {
__ mov(R0, ShifterOperand(27));
__ mov(R1, ShifterOperand(9));
__ udiv(R2, R0, R1);
- __ Mov(R0, R2);
+ __ mov(R0, ShifterOperand(R2));
} else {
__ mov(R0, ShifterOperand(3));
}
@@ -1507,7 +1443,7 @@
__ mov(R0, ShifterOperand(27));
__ LoadImmediate(R1, -9);
__ sdiv(R2, R0, R1);
- __ Mov(R0, R2);
+ __ mov(R0, ShifterOperand(R2));
} else {
__ LoadImmediate(R0, -3);
}
@@ -1527,7 +1463,7 @@
__ mov(R0, ShifterOperand(27));
__ mov(R1, ShifterOperand(0));
__ udiv(R2, R0, R1);
- __ Mov(R0, R2);
+ __ mov(R0, ShifterOperand(R2));
} else {
__ LoadImmediate(R0, 0);
}
@@ -1547,7 +1483,7 @@
__ mov(R0, ShifterOperand(27));
__ mov(R1, ShifterOperand(0));
__ udiv(R2, R0, R1);
- __ Mov(R0, R2);
+ __ mov(R0, ShifterOperand(R2));
} else {
__ LoadImmediate(R0, 0);
}
@@ -1567,7 +1503,7 @@
__ LoadImmediate(R0, 0x80000000);
__ LoadImmediate(R1, 0xffffffff);
__ udiv(R2, R0, R1);
- __ Mov(R0, R2);
+ __ mov(R0, ShifterOperand(R2));
} else {
__ LoadImmediate(R0, 0);
}
@@ -1587,7 +1523,7 @@
__ LoadImmediate(R0, 0x80000000);
__ LoadImmediate(R1, 0xffffffff);
__ sdiv(R2, R0, R1);
- __ Mov(R0, R2);
+ __ mov(R0, ShifterOperand(R2));
} else {
__ LoadImmediate(R0, 0x80000000);
}
diff --git a/runtime/vm/ast.cc b/runtime/vm/ast.cc
index 7f88189..77f14fd 100644
--- a/runtime/vm/ast.cc
+++ b/runtime/vm/ast.cc
@@ -73,6 +73,34 @@
}
+LetNode::LetNode(intptr_t token_pos)
+ : AstNode(token_pos),
+ vars_(1),
+ initializers_(1),
+ body_(NULL) { }
+
+
+LocalVariable* LetNode::AddInitializer(AstNode* node) {
+ initializers_.Add(node);
+ char name[64];
+ OS::SNPrint(name, sizeof(name), ":lt%"Pd"_%d", token_pos(), vars_.length());
+ LocalVariable* temp_var =
+ new LocalVariable(token_pos(),
+ String::ZoneHandle(Symbols::New(name)),
+ Type::ZoneHandle(Type::DynamicType()));
+ vars_.Add(temp_var);
+ return temp_var;
+}
+
+
+void LetNode::VisitChildren(AstNodeVisitor* visitor) const {
+ for (intptr_t i = 0; i < num_temps(); ++i) {
+ initializers_[i]->Visit(visitor);
+ }
+ body_->Visit(visitor);
+}
+
+
void ArrayNode::VisitChildren(AstNodeVisitor* visitor) const {
for (intptr_t i = 0; i < this->length(); i++) {
ElementAt(i)->Visit(visitor);
diff --git a/runtime/vm/ast.h b/runtime/vm/ast.h
index c65f991..43fe8b2 100644
--- a/runtime/vm/ast.h
+++ b/runtime/vm/ast.h
@@ -55,6 +55,7 @@
V(LoadIndexedNode, "load indexed") \
V(StoreIndexedNode, "store indexed") \
V(SequenceNode, "seq") \
+ V(LetNode, "let") \
V(CommaNode, "comma") \
V(CatchClauseNode, "catch clause block") \
V(TryCatchNode, "try catch block") \
@@ -293,24 +294,48 @@
};
+class LetNode : public AstNode {
+ public:
+ explicit LetNode(intptr_t token_pos);
+
+ LocalVariable* TempAt(intptr_t i) const { return vars_[i]; }
+ AstNode* InitializerAt(intptr_t i) const { return initializers_[i]; }
+
+ LocalVariable* AddInitializer(AstNode* node);
+
+ intptr_t num_temps() const {
+ return vars_.length();
+ }
+
+ AstNode* body() const { return body_; }
+ void set_body(AstNode* node) { body_ = node; }
+
+ void VisitChildren(AstNodeVisitor* visitor) const;
+
+ DECLARE_COMMON_NODE_FUNCTIONS(LetNode);
+
+ private:
+ GrowableArray<LocalVariable*> vars_;
+ GrowableArray<AstNode*> initializers_;
+ AstNode* body_;
+
+ DISALLOW_COPY_AND_ASSIGN(LetNode);
+};
+
+
class ArrayNode : public AstNode {
public:
- ArrayNode(intptr_t token_pos,
- const AbstractType& type,
- const LocalVariable& temp)
+ ArrayNode(intptr_t token_pos, const AbstractType& type)
: AstNode(token_pos),
type_(type),
- temp_local_(temp),
elements_() {
CheckFields();
}
ArrayNode(intptr_t token_pos,
const AbstractType& type,
- const LocalVariable& temp,
const GrowableArray<AstNode*>& elements)
: AstNode(token_pos),
type_(type),
- temp_local_(temp),
elements_(elements.length()) {
CheckFields();
for (intptr_t i = 0; i < elements.length(); i++) {
@@ -330,13 +355,10 @@
const AbstractType& type() const { return type_; }
- const LocalVariable& temp_local() const { return temp_local_; }
-
DECLARE_COMMON_NODE_FUNCTIONS(ArrayNode);
private:
const AbstractType& type_;
- const LocalVariable& temp_local_; // Store allocated array while filling it.
GrowableArray<AstNode*> elements_;
void CheckFields() {
@@ -1507,25 +1529,19 @@
// instantiator is the first parameter of this factory, which is already a
// type argument vector. This case is identified by a null and unneeded
// instantiator_class.
-//
-// A temporary local is needed to hold the allocated value while the
-// constructor is being called.
class ConstructorCallNode : public AstNode {
public:
ConstructorCallNode(intptr_t token_pos,
const AbstractTypeArguments& type_arguments,
const Function& constructor,
- ArgumentListNode* arguments,
- const LocalVariable* allocated_object_var)
+ ArgumentListNode* arguments)
: AstNode(token_pos),
type_arguments_(type_arguments),
constructor_(constructor),
- arguments_(arguments),
- allocated_object_var_(*allocated_object_var) {
+ arguments_(arguments) {
ASSERT(type_arguments_.IsZoneHandle());
ASSERT(constructor_.IsZoneHandle());
ASSERT(arguments_ != NULL);
- ASSERT(allocated_object_var != NULL);
}
const AbstractTypeArguments& type_arguments() const {
@@ -1533,9 +1549,6 @@
}
const Function& constructor() const { return constructor_; }
ArgumentListNode* arguments() const { return arguments_; }
- const LocalVariable& allocated_object_var() const {
- return allocated_object_var_;
- }
virtual void VisitChildren(AstNodeVisitor* visitor) const {
arguments()->Visit(visitor);
@@ -1547,7 +1560,6 @@
const AbstractTypeArguments& type_arguments_;
const Function& constructor_;
ArgumentListNode* arguments_;
- const LocalVariable& allocated_object_var_;
DISALLOW_IMPLICIT_CONSTRUCTORS(ConstructorCallNode);
};
diff --git a/runtime/vm/ast_printer.cc b/runtime/vm/ast_printer.cc
index 32bd0af8..9bf4816 100644
--- a/runtime/vm/ast_printer.cc
+++ b/runtime/vm/ast_printer.cc
@@ -127,6 +127,11 @@
}
+void AstPrinter::VisitLetNode(LetNode* node) {
+ VisitGenericAstNode(node);
+}
+
+
void AstPrinter::VisitArrayNode(ArrayNode* node) {
VisitGenericAstNode(node);
}
diff --git a/runtime/vm/bit_vector.h b/runtime/vm/bit_vector.h
index 76f6450..09a0489 100644
--- a/runtime/vm/bit_vector.h
+++ b/runtime/vm/bit_vector.h
@@ -48,7 +48,6 @@
: length_(length),
data_length_(SizeFor(length)),
data_(Isolate::Current()->current_zone()->Alloc<uword>(data_length_)) {
- ASSERT(length > 0);
Clear();
}
diff --git a/runtime/vm/code_generator_test.cc b/runtime/vm/code_generator_test.cc
index c0d1172..bcd6bf7 100644
--- a/runtime/vm/code_generator_test.cc
+++ b/runtime/vm/code_generator_test.cc
@@ -350,11 +350,10 @@
String& function_bar_name = String::ZoneHandle(Symbols::New("bar"));
ArgumentListNode* no_arguments = new ArgumentListNode(kPos);
const TypeArguments& no_type_arguments = TypeArguments::ZoneHandle();
- const LocalVariable* allocated = test->CreateTempConstVariable("alloc");
InstanceCallNode* call_bar = new InstanceCallNode(
kPos,
new ConstructorCallNode(
- kPos, no_type_arguments, constructor, no_arguments, allocated),
+ kPos, no_type_arguments, constructor, no_arguments),
function_bar_name,
no_arguments);
@@ -535,9 +534,8 @@
const TypeArguments& no_type_arguments = TypeArguments::ZoneHandle();
ArgumentListNode* no_arguments = new ArgumentListNode(kPos);
- const LocalVariable* allocated = test->CreateTempConstVariable("alloc");
test->node_sequence()->Add(new ReturnNode(kPos, new ConstructorCallNode(
- kPos, no_type_arguments, constructor, no_arguments, allocated)));
+ kPos, no_type_arguments, constructor, no_arguments)));
}
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index c9b16a7..53bc843 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -242,6 +242,9 @@
// Return false if bailed out.
static bool CompileParsedFunctionHelper(const ParsedFunction& parsed_function,
bool optimized) {
+ if (optimized && !parsed_function.function().is_optimizable()) {
+ return false;
+ }
TimerScope timer(FLAG_compiler_stats, &CompilerStats::codegen_timer);
bool is_compiled = false;
Isolate* isolate = Isolate::Current();
@@ -281,6 +284,11 @@
flow_graph = builder.BuildGraph();
}
+ if (FLAG_print_flow_graph ||
+ (optimized && FLAG_print_flow_graph_optimized)) {
+ FlowGraphPrinter::PrintGraph("Before Optimizations", flow_graph);
+ }
+
if (optimized) {
TimerScope timer(FLAG_compiler_stats,
&CompilerStats::ssa_timer,
@@ -288,12 +296,11 @@
// Transform to SSA (virtual register 0 and no inlining arguments).
flow_graph->ComputeSSA(0, NULL);
DEBUG_ASSERT(flow_graph->VerifyUseLists());
+ if (FLAG_print_flow_graph || FLAG_print_flow_graph_optimized) {
+ FlowGraphPrinter::PrintGraph("After SSA", flow_graph);
+ }
}
- if (FLAG_print_flow_graph ||
- (optimized && FLAG_print_flow_graph_optimized)) {
- FlowGraphPrinter::PrintGraph("Before Optimizations", flow_graph);
- }
// Collect all instance fields that are loaded in the graph and
// have non-generic type feedback attached to them that can
@@ -847,9 +854,6 @@
parsed_function->set_expression_temp_var(
ParsedFunction::CreateExpressionTempVar(0));
fragment->scope()->AddVariable(parsed_function->expression_temp_var());
- parsed_function->set_array_literal_var(
- ParsedFunction::CreateArrayLiteralVar(0));
- fragment->scope()->AddVariable(parsed_function->array_literal_var());
parsed_function->AllocateVariables();
// Non-optimized code generator.
diff --git a/runtime/vm/constants_arm.h b/runtime/vm/constants_arm.h
index 8caf86d..0d69e3c 100644
--- a/runtime/vm/constants_arm.h
+++ b/runtime/vm/constants_arm.h
@@ -554,15 +554,6 @@
return ((Bits(20, 5) & 0x12) == 0x10) && (Bits(9, 3) == 5);
}
- // Only handle mrc of the id_isar0 register.
- inline bool IsMrcIdIsar0() const {
- ASSERT(ConditionField() != kSpecialCondition);
- ASSERT(TypeField() == 7);
- return (Bits(21, 3) == 0) && (Bits(16, 4) == 0) &&
- (Bits(8, 4) == 0xf) && (Bits(5, 3) == 0) &&
- (Bits(0, 4) == 2);
- }
-
// Test for VFP multiple load and store instructions of type 6.
inline bool IsVFPMultipleLoadStore() const {
ASSERT(ConditionField() != kSpecialCondition);
diff --git a/runtime/vm/dart.cc b/runtime/vm/dart.cc
index 446aace..b68c88a 100644
--- a/runtime/vm/dart.cc
+++ b/runtime/vm/dart.cc
@@ -128,6 +128,12 @@
vm_isolate_->heap()->IterateOldObjects(&premarker);
vm_isolate_->heap()->WriteProtect(true);
}
+ // There is a planned and known asymmetry here: We enter one scope for the VM
+ // isolate so that we can allocate the "persistent" scoped handles for the
+ // predefined API values (such as Dart_True, Dart_False and Dart_Null).
+ Dart_EnterScope();
+ Api::InitHandles();
+
Isolate::SetCurrent(NULL); // Unregister the VM isolate from this thread.
Isolate::SetCreateCallback(create);
Isolate::SetInterruptCallback(interrupt);
diff --git a/runtime/vm/dart_api_impl.cc b/runtime/vm/dart_api_impl.cc
index d493d4e..fd7f2da 100644
--- a/runtime/vm/dart_api_impl.cc
+++ b/runtime/vm/dart_api_impl.cc
@@ -36,6 +36,9 @@
DECLARE_FLAG(bool, print_class_table);
ThreadLocalKey Api::api_native_key_ = Thread::kUnsetThreadLocalKey;
+Dart_Handle Api::true_handle_ = NULL;
+Dart_Handle Api::false_handle_ = NULL;
+Dart_Handle Api::null_handle_ = NULL;
const char* CanonicalFunction(const char* func) {
@@ -95,9 +98,7 @@
ApiState* state = isolate->api_state();
ASSERT(state != NULL);
ASSERT(state->IsValidLocalHandle(object) ||
- state->IsValidPersistentHandle(object) ||
- state->IsValidWeakPersistentHandle(object) ||
- state->IsValidPrologueWeakPersistentHandle(object));
+ Dart::vm_isolate()->api_state()->IsValidLocalHandle(object));
ASSERT(FinalizablePersistentHandle::raw_offset() == 0 &&
PersistentHandle::raw_offset() == 0 &&
LocalHandle::raw_offset() == 0);
@@ -118,32 +119,23 @@
#undef DEFINE_UNWRAP
-LocalHandle* Api::UnwrapAsLocalHandle(const ApiState& state,
- Dart_Handle object) {
- ASSERT(state.IsValidLocalHandle(object));
- return reinterpret_cast<LocalHandle*>(object);
-}
-
-
-PersistentHandle* Api::UnwrapAsPersistentHandle(const ApiState& state,
- Dart_Handle object) {
- ASSERT(state.IsValidPersistentHandle(object));
+PersistentHandle* Api::UnwrapAsPersistentHandle(Dart_PersistentHandle object) {
+ ASSERT(Isolate::Current()->api_state()->IsValidPersistentHandle(object));
return reinterpret_cast<PersistentHandle*>(object);
}
FinalizablePersistentHandle* Api::UnwrapAsWeakPersistentHandle(
- const ApiState& state,
- Dart_Handle object) {
- ASSERT(state.IsValidWeakPersistentHandle(object));
+ Dart_WeakPersistentHandle object) {
+ ASSERT(Isolate::Current()->api_state()->IsValidWeakPersistentHandle(object));
return reinterpret_cast<FinalizablePersistentHandle*>(object);
}
FinalizablePersistentHandle* Api::UnwrapAsPrologueWeakPersistentHandle(
- const ApiState& state,
- Dart_Handle object) {
- ASSERT(state.IsValidPrologueWeakPersistentHandle(object));
+ Dart_WeakPersistentHandle object) {
+ ASSERT(Isolate::Current()->api_state()->IsValidPrologueWeakPersistentHandle(
+ object));
return reinterpret_cast<FinalizablePersistentHandle*>(object);
}
@@ -151,7 +143,7 @@
Dart_Handle Api::CheckIsolateState(Isolate* isolate) {
if (ClassFinalizer::FinalizePendingClasses() &&
isolate->object_store()->PreallocateObjects()) {
- return Api::Success(isolate);
+ return Api::Success();
}
ASSERT(isolate->object_store()->sticky_error() != Object::null());
return Api::NewHandle(isolate, isolate->object_store()->sticky_error());
@@ -163,15 +155,6 @@
}
-Dart_Handle Api::Success(Isolate* isolate) {
- ASSERT(isolate != NULL);
- ApiState* state = isolate->api_state();
- ASSERT(state != NULL);
- PersistentHandle* true_handle = state->True();
- return reinterpret_cast<Dart_Handle>(true_handle);
-}
-
-
Dart_Handle Api::NewError(const char* format, ...) {
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
@@ -210,30 +193,18 @@
}
-Dart_Handle Api::Null(Isolate* isolate) {
- ASSERT(isolate != NULL);
- ApiState* state = isolate->api_state();
- ASSERT(state != NULL);
- PersistentHandle* null_handle = state->Null();
- return reinterpret_cast<Dart_Handle>(null_handle);
+Dart_Handle Api::Null() {
+ return null_handle_;
}
-Dart_Handle Api::True(Isolate* isolate) {
- ASSERT(isolate != NULL);
- ApiState* state = isolate->api_state();
- ASSERT(state != NULL);
- PersistentHandle* true_handle = state->True();
- return reinterpret_cast<Dart_Handle>(true_handle);
+Dart_Handle Api::True() {
+ return true_handle_;
}
-Dart_Handle Api::False(Isolate* isolate) {
- ASSERT(isolate != NULL);
- ApiState* state = isolate->api_state();
- ASSERT(state != NULL);
- PersistentHandle* false_handle = state->False();
- return reinterpret_cast<Dart_Handle>(false_handle);
+Dart_Handle Api::False() {
+ return false_handle_;
}
@@ -254,6 +225,23 @@
}
+void Api::InitHandles() {
+ Isolate* isolate = Isolate::Current();
+ ASSERT(isolate != NULL);
+ ASSERT(isolate == Dart::vm_isolate());
+ ApiState* state = isolate->api_state();
+ ASSERT(state != NULL);
+ ASSERT(true_handle_ == NULL);
+ true_handle_ = Api::NewHandle(isolate, Bool::True().raw());
+
+ ASSERT(false_handle_ == NULL);
+ false_handle_ = Api::NewHandle(isolate, Bool::False().raw());
+
+ ASSERT(null_handle_ == NULL);
+ null_handle_ = Api::NewHandle(isolate, Object::null());
+}
+
+
bool Api::ExternalStringGetPeerHelper(Dart_Handle object, void** peer) {
NoGCScope no_gc_scope;
RawObject* raw_obj = Api::UnwrapHandle(object);
@@ -524,7 +512,32 @@
}
-DART_EXPORT Dart_Handle Dart_NewPersistentHandle(Dart_Handle object) {
+DART_EXPORT Dart_Handle Dart_HandleFromPersistent(
+ Dart_PersistentHandle object) {
+ Isolate* isolate = Isolate::Current();
+ DARTSCOPE(isolate);
+ ApiState* state = isolate->api_state();
+ ASSERT(state != NULL);
+ ASSERT(state->IsValidPersistentHandle(object));
+ return Api::NewHandle(isolate,
+ reinterpret_cast<PersistentHandle*>(object)->raw());
+}
+
+
+DART_EXPORT Dart_Handle Dart_HandleFromWeakPersistent(
+ Dart_WeakPersistentHandle object) {
+ Isolate* isolate = Isolate::Current();
+ DARTSCOPE(isolate);
+ ApiState* state = isolate->api_state();
+ ASSERT(state != NULL);
+ ASSERT(state->IsValidWeakPersistentHandle(object) ||
+ state->IsValidPrologueWeakPersistentHandle(object));
+ return Api::NewHandle(
+ isolate, reinterpret_cast<FinalizablePersistentHandle*>(object)->raw());
+}
+
+
+DART_EXPORT Dart_PersistentHandle Dart_NewPersistentHandle(Dart_Handle object) {
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
ApiState* state = isolate->api_state();
@@ -532,10 +545,10 @@
const Object& old_ref = Object::Handle(isolate, Api::UnwrapHandle(object));
PersistentHandle* new_ref = state->persistent_handles().AllocateHandle();
new_ref->set_raw(old_ref);
- return reinterpret_cast<Dart_Handle>(new_ref);
+ return reinterpret_cast<Dart_PersistentHandle>(new_ref);
}
-static Dart_Handle AllocateFinalizableHandle(
+static Dart_WeakPersistentHandle AllocateFinalizableHandle(
Isolate* isolate,
FinalizablePersistentHandles* handles,
Dart_Handle object,
@@ -546,11 +559,11 @@
finalizable_ref->set_raw(ref);
finalizable_ref->set_peer(peer);
finalizable_ref->set_callback(callback);
- return reinterpret_cast<Dart_Handle>(finalizable_ref);
+ return reinterpret_cast<Dart_WeakPersistentHandle>(finalizable_ref);
}
-DART_EXPORT Dart_Handle Dart_NewWeakPersistentHandle(
+DART_EXPORT Dart_WeakPersistentHandle Dart_NewWeakPersistentHandle(
Dart_Handle object,
void* peer,
Dart_WeakPersistentHandleFinalizer callback) {
@@ -566,7 +579,7 @@
}
-DART_EXPORT Dart_Handle Dart_NewPrologueWeakPersistentHandle(
+DART_EXPORT Dart_WeakPersistentHandle Dart_NewPrologueWeakPersistentHandle(
Dart_Handle object,
void* peer,
Dart_WeakPersistentHandleFinalizer callback) {
@@ -582,24 +595,12 @@
}
-DART_EXPORT void Dart_DeletePersistentHandle(Dart_Handle object) {
+DART_EXPORT void Dart_DeletePersistentHandle(Dart_PersistentHandle object) {
Isolate* isolate = Isolate::Current();
CHECK_ISOLATE(isolate);
ApiState* state = isolate->api_state();
ASSERT(state != NULL);
- if (state->IsValidPrologueWeakPersistentHandle(object)) {
- FinalizablePersistentHandle* prologue_weak_ref =
- Api::UnwrapAsPrologueWeakPersistentHandle(*state, object);
- state->prologue_weak_persistent_handles().FreeHandle(prologue_weak_ref);
- return;
- }
- if (state->IsValidWeakPersistentHandle(object)) {
- FinalizablePersistentHandle* weak_ref =
- Api::UnwrapAsWeakPersistentHandle(*state, object);
- state->weak_persistent_handles().FreeHandle(weak_ref);
- return;
- }
- PersistentHandle* ref = Api::UnwrapAsPersistentHandle(*state, object);
+ PersistentHandle* ref = Api::UnwrapAsPersistentHandle(object);
ASSERT(!state->IsProtectedHandle(ref));
if (!state->IsProtectedHandle(ref)) {
state->persistent_handles().FreeHandle(ref);
@@ -607,16 +608,27 @@
}
-DART_EXPORT bool Dart_IsWeakPersistentHandle(Dart_Handle object) {
+DART_EXPORT void Dart_DeleteWeakPersistentHandle(
+ Dart_WeakPersistentHandle object) {
Isolate* isolate = Isolate::Current();
CHECK_ISOLATE(isolate);
ApiState* state = isolate->api_state();
ASSERT(state != NULL);
- return state->IsValidWeakPersistentHandle(object);
+ if (state->IsValidPrologueWeakPersistentHandle(object)) {
+ FinalizablePersistentHandle* prologue_weak_ref =
+ Api::UnwrapAsPrologueWeakPersistentHandle(object);
+ state->prologue_weak_persistent_handles().FreeHandle(prologue_weak_ref);
+ return;
+ }
+ FinalizablePersistentHandle* weak_ref =
+ Api::UnwrapAsWeakPersistentHandle(object);
+ state->weak_persistent_handles().FreeHandle(weak_ref);
+ return;
}
-DART_EXPORT bool Dart_IsPrologueWeakPersistentHandle(Dart_Handle object) {
+DART_EXPORT bool Dart_IsPrologueWeakPersistentHandle(
+ Dart_WeakPersistentHandle object) {
Isolate* isolate = Isolate::Current();
CHECK_ISOLATE(isolate);
ApiState* state = isolate->api_state();
@@ -625,10 +637,11 @@
}
-DART_EXPORT Dart_Handle Dart_NewWeakReferenceSet(Dart_Handle* keys,
- intptr_t num_keys,
- Dart_Handle* values,
- intptr_t num_values) {
+DART_EXPORT Dart_Handle Dart_NewWeakReferenceSet(
+ Dart_WeakPersistentHandle* keys,
+ intptr_t num_keys,
+ Dart_WeakPersistentHandle* values,
+ intptr_t num_values) {
Isolate* isolate = Isolate::Current();
CHECK_ISOLATE(isolate);
ApiState* state = isolate->api_state();
@@ -653,7 +666,7 @@
WeakReferenceSet* reference_set = new WeakReferenceSet(keys, num_keys,
values, num_values);
state->DelayWeakReferenceSet(reference_set);
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -672,7 +685,7 @@
CURRENT_FUNC);
}
callbacks.Add(callback);
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -687,7 +700,7 @@
CURRENT_FUNC);
}
callbacks.Remove(callback);
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -703,7 +716,7 @@
CURRENT_FUNC);
}
callbacks.Add(callback);
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -718,7 +731,7 @@
CURRENT_FUNC);
}
callbacks.Remove(callback);
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -730,7 +743,7 @@
RETURN_NULL_ERROR(callback);
}
isolate->heap()->Profile(callback, stream);
- return Api::Success(isolate);
+ return Api::Success();
}
// --- Initialization and Globals ---
@@ -898,7 +911,7 @@
FullSnapshotWriter writer(buffer, ApiReallocate);
writer.WriteFullSnapshot();
*size = writer.BytesWritten();
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -927,7 +940,7 @@
ScriptSnapshotWriter writer(buffer, ApiReallocate);
writer.WriteScriptSnapshot(library);
*size = writer.BytesWritten();
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -1003,7 +1016,7 @@
if (FLAG_print_class_table) {
isolate->class_table()->Print();
}
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -1017,7 +1030,7 @@
isolate->object_store()->clear_sticky_error();
return error;
}
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -1198,7 +1211,7 @@
DART_EXPORT Dart_Handle Dart_Null() {
Isolate* isolate = Isolate::Current();
CHECK_ISOLATE_SCOPE(isolate);
- return Api::Null(isolate);
+ return Api::Null();
}
@@ -1220,7 +1233,7 @@
Object::Handle(isolate, DartLibraryCalls::Equals(expected, actual));
if (result.IsBool()) {
*value = Bool::Cast(result).value();
- return Api::Success(isolate);
+ return Api::Success();
} else if (result.IsError()) {
return Api::NewHandle(isolate, result.raw());
} else {
@@ -1267,7 +1280,7 @@
} else {
*value = false;
}
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -1318,7 +1331,7 @@
intptr_t class_id = Api::ClassId(integer);
if (class_id == kSmiCid || class_id == kMintCid) {
*fits = true;
- return Api::Success(isolate);
+ return Api::Success();
}
// Slow path for Mints and Bigints.
DARTSCOPE(isolate);
@@ -1328,7 +1341,7 @@
}
ASSERT(!BigintOperations::FitsIntoInt64(Bigint::Cast(int_obj)));
*fits = false;
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -1339,7 +1352,7 @@
CHECK_ISOLATE(isolate);
if (Api::IsSmi(integer)) {
*fits = (Api::SmiValue(integer) >= 0);
- return Api::Success(isolate);
+ return Api::Success();
}
// Slow path for Mints and Bigints.
DARTSCOPE(isolate);
@@ -1353,7 +1366,7 @@
} else {
*fits = BigintOperations::FitsIntoUint64(Bigint::Cast(int_obj));
}
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -1388,7 +1401,7 @@
CHECK_ISOLATE(isolate);
if (Api::IsSmi(integer)) {
*value = Api::SmiValue(integer);
- return Api::Success(isolate);
+ return Api::Success();
}
// Slow path for Mints and Bigints.
DARTSCOPE(isolate);
@@ -1399,12 +1412,12 @@
ASSERT(!int_obj.IsSmi());
if (int_obj.IsMint()) {
*value = int_obj.AsInt64Value();
- return Api::Success(isolate);
+ return Api::Success();
} else {
const Bigint& bigint = Bigint::Cast(int_obj);
if (BigintOperations::FitsIntoInt64(bigint)) {
*value = BigintOperations::ToInt64(bigint);
- return Api::Success(isolate);
+ return Api::Success();
}
}
return Api::NewError("%s: Integer %s cannot be represented as an int64_t.",
@@ -1421,7 +1434,7 @@
intptr_t smi_value = Api::SmiValue(integer);
if (smi_value >= 0) {
*value = smi_value;
- return Api::Success(isolate);
+ return Api::Success();
}
}
// Slow path for Mints and Bigints.
@@ -1433,12 +1446,12 @@
ASSERT(!int_obj.IsSmi());
if (int_obj.IsMint() && !int_obj.IsNegative()) {
*value = int_obj.AsInt64Value();
- return Api::Success(isolate);
+ return Api::Success();
} else {
const Bigint& bigint = Bigint::Cast(int_obj);
if (BigintOperations::FitsIntoUint64(bigint)) {
*value = BigintOperations::ToUint64(bigint);
- return Api::Success(isolate);
+ return Api::Success();
}
}
return Api::NewError("%s: Integer %s cannot be represented as a uint64_t.",
@@ -1467,7 +1480,7 @@
*value = BigintOperations::ToHexCString(Bigint::Cast(int_obj),
BigintAllocate);
}
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -1477,14 +1490,14 @@
DART_EXPORT Dart_Handle Dart_True() {
Isolate* isolate = Isolate::Current();
CHECK_ISOLATE_SCOPE(isolate);
- return Api::True(isolate);
+ return Api::True();
}
DART_EXPORT Dart_Handle Dart_False() {
Isolate* isolate = Isolate::Current();
CHECK_ISOLATE_SCOPE(isolate);
- return Api::False(isolate);
+ return Api::False();
}
@@ -1496,7 +1509,7 @@
DART_EXPORT Dart_Handle Dart_NewBoolean(bool value) {
Isolate* isolate = Isolate::Current();
CHECK_ISOLATE_SCOPE(isolate);
- return value ? Api::True(isolate) : Api::False(isolate);
+ return value ? Api::True() : Api::False();
}
@@ -1509,7 +1522,7 @@
RETURN_TYPE_ERROR(isolate, boolean_obj, Bool);
}
*value = obj.value();
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -1538,7 +1551,7 @@
RETURN_TYPE_ERROR(isolate, double_obj, Double);
}
*value = obj.value();
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -1563,7 +1576,7 @@
RETURN_TYPE_ERROR(isolate, str, String);
}
*len = str_obj.Length();
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -1633,7 +1646,7 @@
}
if (Api::ExternalStringGetPeerHelper(object, peer)) {
- return Api::Success(Isolate::Current());
+ return Api::Success();
}
// It's not an external string, return appropriate error.
@@ -1701,7 +1714,7 @@
memmove(res, string_value, string_length + 1);
ASSERT(res[string_length] == '\0');
*cstr = res;
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -1727,7 +1740,7 @@
}
str_obj.ToUTF8(*utf8_array, str_len);
*length = str_len;
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -1755,7 +1768,7 @@
latin1_array[i] = str_obj.CharAt(i);
}
*length = copy_len;
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -1774,7 +1787,7 @@
utf16_array[i] = static_cast<uint16_t>(str_obj.CharAt(i));
}
*length = copy_len;
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -1790,7 +1803,7 @@
RETURN_NULL_ERROR(size);
}
*size = (str_obj.Length() * str_obj.CharSize());
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -1839,7 +1852,7 @@
utf16_array[i] = static_cast<uint16_t>(str_obj.CharAt(i));
}
}
- return Api::Null(isolate);
+ return Api::Null();
}
return Api::NewHandle(isolate,
str_obj.MakeExternal(array, length, peer, cback));
@@ -1893,7 +1906,7 @@
type& array = type::Handle(isolate); \
array ^= obj.raw(); \
*len = array.Length(); \
- return Api::Success(isolate); \
+ return Api::Success(); \
DART_EXPORT Dart_Handle Dart_ListLength(Dart_Handle list, intptr_t* len) {
@@ -1938,7 +1951,7 @@
Object::Handle(isolate, DartEntry::InvokeFunction(function, args));
if (retval.IsSmi()) {
*len = Smi::Cast(retval).Value();
- return Api::Success(isolate);
+ return Api::Success();
} else if (retval.IsMint() || retval.IsBigint()) {
if (retval.IsMint()) {
int64_t mint_value = Mint::Cast(retval).value();
@@ -2017,7 +2030,7 @@
} \
if ((index >= 0) && (index < array.Length())) { \
array.SetAt(index, value_obj); \
- return Api::Success(isolate); \
+ return Api::Success(); \
} \
return Api::NewError("Invalid index passed in to set list element"); \
@@ -2166,7 +2179,7 @@
native_array[i] = static_cast<uint8_t>(integer.AsInt64Value() & 0xff); \
ASSERT(integer.AsInt64Value() <= 0xff); \
} \
- return Api::Success(isolate); \
+ return Api::Success(); \
} \
return Api::NewError("Invalid length passed in to access array elements"); \
@@ -2186,7 +2199,7 @@
memmove(native_array,
reinterpret_cast<uint8_t*>(array.DataAddr(offset)),
length);
- return Api::Success(isolate);
+ return Api::Success();
}
return Api::NewError("Invalid length passed in to access list elements");
}
@@ -2243,7 +2256,7 @@
native_array[i] =
static_cast<uint8_t>(integer_result.AsInt64Value() & 0xff);
}
- return Api::Success(isolate);
+ return Api::Success();
}
}
return Api::NewError("Object does not implement the 'List' interface");
@@ -2259,7 +2272,7 @@
integer = Integer::New(native_array[i]); \
array.SetAt(offset + i, integer); \
} \
- return Api::Success(isolate); \
+ return Api::Success(); \
} \
return Api::NewError("Invalid length passed in to set array elements"); \
@@ -2279,7 +2292,7 @@
memmove(reinterpret_cast<uint8_t*>(array.DataAddr(offset)),
native_array,
length);
- return Api::Success(isolate);
+ return Api::Success();
}
return Api::NewError("Invalid length passed in to access list elements");
}
@@ -2334,7 +2347,7 @@
return Api::NewHandle(isolate, result.raw());
}
}
- return Api::Success(isolate);
+ return Api::Success();
}
}
return Api::NewError("Object does not implement the 'List' interface");
@@ -2488,32 +2501,19 @@
static Dart_Handle NewExternalTypedData(
- Isolate* isolate,
- intptr_t cid,
- void* data,
- intptr_t length,
- void* peer,
- Dart_WeakPersistentHandleFinalizer callback) {
+ Isolate* isolate, intptr_t cid, void* data, intptr_t length) {
CHECK_LENGTH(length, ExternalTypedData::MaxElements(cid));
const ExternalTypedData& result = ExternalTypedData::Handle(
isolate,
ExternalTypedData::New(cid, reinterpret_cast<uint8_t*>(data), length));
- result.AddFinalizer(peer, callback);
return Api::NewHandle(isolate, result.raw());
}
-static Dart_Handle NewExternalByteData(Isolate* isolate,
- void* data,
- intptr_t length,
- void* peer,
- Dart_WeakPersistentHandleFinalizer cb) {
- Dart_Handle ext_data = NewExternalTypedData(isolate,
- kExternalTypedDataUint8ArrayCid,
- data,
- length,
- peer,
- cb);
+static Dart_Handle NewExternalByteData(
+ Isolate* isolate, void* data, intptr_t length) {
+ Dart_Handle ext_data = NewExternalTypedData(
+ isolate, kExternalTypedDataUint8ArrayCid, data, length);
if (::Dart_IsError(ext_data)) {
return ext_data;
}
@@ -2582,16 +2582,14 @@
CURRENT_FUNC);
}
UNREACHABLE();
- return Api::Null(isolate);
+ return Api::Null();
}
DART_EXPORT Dart_Handle Dart_NewExternalTypedData(
Dart_TypedData_Type type,
void* data,
- intptr_t length,
- void* peer,
- Dart_WeakPersistentHandleFinalizer callback) {
+ intptr_t length) {
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
if (data == NULL && length != 0) {
@@ -2600,114 +2598,73 @@
CHECK_CALLBACK_STATE(isolate);
switch (type) {
case kByteData:
- return NewExternalByteData(isolate, data, length, peer, callback);
+ return NewExternalByteData(isolate, data, length);
case kInt8:
return NewExternalTypedData(isolate,
kExternalTypedDataInt8ArrayCid,
data,
- length,
- peer,
- callback);
+ length);
case kUint8:
return NewExternalTypedData(isolate,
kExternalTypedDataUint8ArrayCid,
data,
- length,
- peer,
- callback);
+ length);
case kUint8Clamped:
return NewExternalTypedData(isolate,
kExternalTypedDataUint8ClampedArrayCid,
data,
- length,
- peer,
- callback);
+ length);
case kInt16:
return NewExternalTypedData(isolate,
kExternalTypedDataInt16ArrayCid,
data,
- length,
- peer,
- callback);
+ length);
case kUint16:
return NewExternalTypedData(isolate,
kExternalTypedDataUint16ArrayCid,
data,
- length,
- peer,
- callback);
+ length);
case kInt32:
return NewExternalTypedData(isolate,
kExternalTypedDataInt32ArrayCid,
data,
- length,
- peer,
- callback);
+ length);
case kUint32:
return NewExternalTypedData(isolate,
kExternalTypedDataUint32ArrayCid,
data,
- length,
- peer,
- callback);
+ length);
case kInt64:
return NewExternalTypedData(isolate,
kExternalTypedDataInt64ArrayCid,
data,
- length,
- peer,
- callback);
+ length);
case kUint64:
return NewExternalTypedData(isolate,
kExternalTypedDataUint64ArrayCid,
data,
- length,
- peer,
- callback);
+ length);
case kFloat32:
return NewExternalTypedData(isolate,
kExternalTypedDataFloat32ArrayCid,
data,
- length,
- peer,
- callback);
+ length);
case kFloat64:
return NewExternalTypedData(isolate,
kExternalTypedDataFloat64ArrayCid,
data,
- length,
- peer,
- callback);
+ length);
case kFloat32x4:
return NewExternalTypedData(isolate,
kExternalTypedDataFloat32x4ArrayCid,
data,
- length,
- peer,
- callback);
+ length);
default:
return Api::NewError("%s expects argument 'type' to be of"
" 'external TypedData'", CURRENT_FUNC);
}
UNREACHABLE();
- return Api::Null(isolate);
-}
-
-
-DART_EXPORT Dart_Handle Dart_ExternalTypedDataGetPeer(Dart_Handle object,
- void** peer) {
- Isolate* isolate = Isolate::Current();
- DARTSCOPE(isolate);
- const ExternalTypedData& array =
- Api::UnwrapExternalTypedDataHandle(isolate, object);
- if (array.IsNull()) {
- RETURN_TYPE_ERROR(isolate, object, ExternalTypedData);
- }
- if (peer == NULL) {
- RETURN_NULL_ERROR(peer);
- }
- *peer = array.GetPeer();
- return Api::Success(isolate);
+ return Api::Null();
}
@@ -2770,7 +2727,7 @@
*data = data_obj.DataAddr(offset_in_bytes);
}
}
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -2787,7 +2744,7 @@
isolate->DecrementNoGCScopeDepth();
END_NO_CALLBACK_SCOPE(isolate);
}
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -2923,7 +2880,7 @@
} else {
*count = interface_types.Length();
}
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -3234,7 +3191,7 @@
RETURN_TYPE_ERROR(isolate, function, Function);
}
*is_abstract = func.is_abstract();
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -3250,7 +3207,7 @@
RETURN_TYPE_ERROR(isolate, function, Function);
}
*is_static = func.is_static();
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -3266,7 +3223,7 @@
RETURN_TYPE_ERROR(isolate, function, Function);
}
*is_constructor = func.kind() == RawFunction::kConstructor;
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -3282,7 +3239,7 @@
RETURN_TYPE_ERROR(isolate, function, Function);
}
*is_getter = func.IsGetterFunction();
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -3298,7 +3255,7 @@
RETURN_TYPE_ERROR(isolate, function, Function);
}
*is_setter = (func.kind() == RawFunction::kSetterFunction);
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -3352,7 +3309,7 @@
ASSERT(*fixed_param_count >= 0);
ASSERT(*opt_param_count >= 0);
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -3488,7 +3445,7 @@
RETURN_TYPE_ERROR(isolate, variable, Field);
}
*is_static = var.is_static();
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -3504,7 +3461,7 @@
RETURN_TYPE_ERROR(isolate, variable, Field);
}
*is_final = var.is_final();
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -4135,7 +4092,7 @@
if (result.IsError()) {
return Api::NewHandle(isolate, result.raw());
} else {
- return Api::Success(isolate);
+ return Api::Success();
}
} else if (!field.IsNull()) {
if (field.is_final()) {
@@ -4143,7 +4100,7 @@
CURRENT_FUNC, field_name.ToCString());
} else {
field.set_value(value_instance);
- return Api::Success(isolate);
+ return Api::Success();
}
} else {
return Api::NewError("%s: did not find static field '%s'.",
@@ -4172,7 +4129,7 @@
if (result.IsError()) {
return Api::NewHandle(isolate, result.raw());
} else {
- return Api::Success(isolate);
+ return Api::Success();
}
} else if (!field.IsNull()) {
if (field.is_final()) {
@@ -4180,7 +4137,7 @@
CURRENT_FUNC, field_name.ToCString());
} else {
field.set_value(value_instance);
- return Api::Success(isolate);
+ return Api::Success();
}
} else {
return Api::NewError("%s: did not find top-level variable '%s'.",
@@ -4237,7 +4194,7 @@
}
const Class& cls = Class::Handle(isolate, instance.clazz());
*count = cls.num_native_fields();
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -4256,7 +4213,7 @@
CURRENT_FUNC, index);
}
*value = instance.GetNativeField(isolate, index);
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -4275,7 +4232,7 @@
CURRENT_FUNC, index);
}
instance.SetNativeField(index, value);
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -4399,7 +4356,7 @@
Isolate* isolate = Isolate::Current();
CHECK_ISOLATE(isolate);
isolate->set_library_tag_handler(handler);
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -4535,7 +4492,7 @@
ASSERT(isolate != NULL);
const Error& error = Error::Handle(isolate, Library::CompileAll());
if (error.IsNull()) {
- *result = Api::Success(isolate);
+ *result = Api::Success();
} else {
*result = Api::NewHandle(isolate, error.raw());
}
@@ -4758,7 +4715,7 @@
library_vm.AddObject(library_prefix, prefix_symbol);
}
}
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -4828,7 +4785,7 @@
RETURN_TYPE_ERROR(isolate, library, Library);
}
lib.set_native_entry_resolver(resolver);
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -4865,7 +4822,7 @@
RawObject* raw_obj = obj.raw();
*peer = isolate->heap()->GetPeer(raw_obj);
}
- return Api::Success(isolate);
+ return Api::Success();
}
@@ -4883,7 +4840,7 @@
RawObject* raw_obj = obj.raw();
isolate->heap()->SetPeer(raw_obj, peer);
}
- return Api::Success(isolate);
+ return Api::Success();
}
} // namespace dart
diff --git a/runtime/vm/dart_api_impl.h b/runtime/vm/dart_api_impl.h
index b913df8..3959611 100644
--- a/runtime/vm/dart_api_impl.h
+++ b/runtime/vm/dart_api_impl.h
@@ -74,24 +74,18 @@
CLASS_LIST_FOR_HANDLES(DECLARE_UNWRAP)
#undef DECLARE_UNWRAP
- // Validates and converts the passed in handle as a local handle.
- static LocalHandle* UnwrapAsLocalHandle(const ApiState& state,
- Dart_Handle object);
-
// Validates and converts the passed in handle as a persistent handle.
- static PersistentHandle* UnwrapAsPersistentHandle(const ApiState& state,
- Dart_Handle object);
+ static PersistentHandle* UnwrapAsPersistentHandle(
+ Dart_PersistentHandle object);
// Validates and converts the passed in handle as a weak persistent handle.
static FinalizablePersistentHandle* UnwrapAsWeakPersistentHandle(
- const ApiState& state,
- Dart_Handle object);
+ Dart_WeakPersistentHandle object);
// Validates and converts the passed in handle as a prologue weak
// persistent handle.
static FinalizablePersistentHandle* UnwrapAsPrologueWeakPersistentHandle(
- const ApiState& state,
- Dart_Handle object);
+ Dart_WeakPersistentHandle object);
// Returns an Error handle if isolate is in an inconsistent state.
// Returns a Success handle when no error condition exists.
@@ -101,7 +95,7 @@
static Dart_Isolate CastIsolate(Isolate* isolate);
// Gets the handle used to designate successful return.
- static Dart_Handle Success(Isolate* isolate);
+ static Dart_Handle Success() { return Api::True(); }
// Sets up the acquired error object after initializing an Isolate. This
// object is pre-created because we will not be able to allocate this
@@ -140,13 +134,13 @@
static Dart_Handle NewError(const char* format, ...) PRINTF_ATTRIBUTE(1, 2);
// Gets a handle to Null.
- static Dart_Handle Null(Isolate* isolate);
+ static Dart_Handle Null();
// Gets a handle to True.
- static Dart_Handle True(Isolate* isolate);
+ static Dart_Handle True();
// Gets a handle to False
- static Dart_Handle False(Isolate* isolate);
+ static Dart_Handle False();
// Retrieves the top ApiLocalScope.
static ApiLocalScope* TopScope(Isolate* isolate);
@@ -154,6 +148,9 @@
// Performs one-time initialization needed by the API.
static void InitOnce();
+ // Allocates handles for objects in the VM isolate.
+ static void InitHandles();
+
// Helper function to get the peer value of an external string object.
static bool ExternalStringGetPeerHelper(Dart_Handle object, void** peer);
@@ -161,6 +158,9 @@
// Thread local key used by the API. Currently holds the current
// ApiNativeScope if any.
static ThreadLocalKey api_native_key_;
+ static Dart_Handle true_handle_;
+ static Dart_Handle false_handle_;
+ static Dart_Handle null_handle_;
friend class ApiNativeScope;
};
diff --git a/runtime/vm/dart_api_impl_test.cc b/runtime/vm/dart_api_impl_test.cc
index 76bdc4c..9368382 100644
--- a/runtime/vm/dart_api_impl_test.cc
+++ b/runtime/vm/dart_api_impl_test.cc
@@ -931,8 +931,7 @@
Dart_EnterScope();
Dart_Handle external_byte_data = Dart_NewExternalTypedData(kByteData,
data,
- 16,
- NULL, NULL);
+ 16);
EXPECT_VALID(external_byte_data);
EXPECT_EQ(kByteData, Dart_GetTypeOfTypedData(external_byte_data));
Dart_SetReturnValue(args, external_byte_data);
@@ -1106,9 +1105,7 @@
intptr_t data_length = ARRAY_SIZE(data);
Dart_Handle ext_list_access_test_obj;
ext_list_access_test_obj = Dart_NewExternalTypedData(kUint8,
- data,
- data_length,
- NULL, NULL);
+ data, data_length);
EXPECT_VALID(ext_list_access_test_obj);
TestDirectAccess(lib, ext_list_access_test_obj, kUint8);
}
@@ -1209,10 +1206,6 @@
EXPECT_EQ(expected_type, type);
EXPECT_VALID(Dart_TypedDataReleaseData(obj));
- void* peer = &data; // just a non-NULL value
- EXPECT_VALID(Dart_ExternalTypedDataGetPeer(obj, &peer));
- EXPECT(peer == NULL);
-
intptr_t list_length = 0;
EXPECT_VALID(Dart_ListLength(obj, &list_length));
EXPECT_EQ(data_length, list_length);
@@ -1257,9 +1250,7 @@
uint8_t data[] = { 0, 11, 22, 33, 44, 55, 66, 77 };
intptr_t data_length = ARRAY_SIZE(data);
- Dart_Handle obj = Dart_NewExternalTypedData(kUint8,
- data, data_length,
- NULL, NULL);
+ Dart_Handle obj = Dart_NewExternalTypedData(kUint8, data, data_length);
ExternalTypedDataAccessTests(obj, kUint8, data, data_length);
}
@@ -1268,9 +1259,7 @@
uint8_t data[] = { 0, 11, 22, 33, 44, 55, 66, 77 };
intptr_t data_length = ARRAY_SIZE(data);
- Dart_Handle obj = Dart_NewExternalTypedData(kUint8Clamped,
- data, data_length,
- NULL, NULL);
+ Dart_Handle obj = Dart_NewExternalTypedData(kUint8Clamped, data, data_length);
ExternalTypedDataAccessTests(obj, kUint8Clamped, data, data_length);
}
@@ -1291,8 +1280,7 @@
uint8_t data[] = { 0, 11, 22, 33, 44, 55, 66, 77 };
intptr_t data_length = ARRAY_SIZE(data);
Dart_Handle obj = Dart_NewExternalTypedData(kUint8Clamped,
- data, data_length,
- NULL, NULL);
+ data, data_length);
EXPECT_VALID(obj);
Dart_Handle result;
// Create a test library and Load up a test script in it.
@@ -1311,9 +1299,9 @@
}
-static void ExternalTypedDataCallbackFinalizer(Dart_Handle handle,
+static void ExternalTypedDataFinalizer(Dart_WeakPersistentHandle handle,
void* peer) {
- Dart_DeletePersistentHandle(handle);
+ Dart_DeleteWeakPersistentHandle(handle);
*static_cast<int*>(peer) = 42;
}
@@ -1326,13 +1314,9 @@
Dart_Handle obj = Dart_NewExternalTypedData(
kUint8,
data,
- ARRAY_SIZE(data),
- &peer,
- ExternalTypedDataCallbackFinalizer);
+ ARRAY_SIZE(data));
+ Dart_NewWeakPersistentHandle(obj, &peer, ExternalTypedDataFinalizer);
EXPECT_VALID(obj);
- void* api_peer = NULL;
- EXPECT_VALID(Dart_ExternalTypedDataGetPeer(obj, &api_peer));
- EXPECT_EQ(api_peer, &peer);
Dart_ExitScope();
}
EXPECT(peer == 0);
@@ -1384,8 +1368,8 @@
// Dart_NewExternalTypedData.
Dart_EnterScope();
{
- Dart_Handle lcl = Dart_NewExternalTypedData(
- kFloat32x4, data, 10, &peer, ExternalTypedDataCallbackFinalizer);
+ Dart_Handle lcl = Dart_NewExternalTypedData(kFloat32x4, data, 10);
+ Dart_NewWeakPersistentHandle(lcl, &peer, ExternalTypedDataFinalizer);
CheckFloat32x4Data(lcl);
}
Dart_ExitScope();
@@ -1429,7 +1413,7 @@
ApiState* state = isolate->api_state();
EXPECT(state != NULL);
ApiLocalScope* scope = state->top_scope();
- Dart_Handle handles[2000];
+ Dart_PersistentHandle handles[2000];
Dart_EnterScope();
{
DARTSCOPE(isolate);
@@ -1460,22 +1444,22 @@
HANDLESCOPE(isolate);
for (int i = 0; i < 500; i++) {
String& str = String::Handle();
- str ^= Api::UnwrapHandle(handles[i]);
+ str ^= Api::UnwrapAsPersistentHandle(handles[i])->raw();
EXPECT(str.Equals(kTestString1));
}
for (int i = 500; i < 1000; i++) {
String& str = String::Handle();
- str ^= Api::UnwrapHandle(handles[i]);
+ str ^= Api::UnwrapAsPersistentHandle(handles[i])->raw();
EXPECT(str.Equals(kTestString2));
}
for (int i = 1000; i < 1500; i++) {
String& str = String::Handle();
- str ^= Api::UnwrapHandle(handles[i]);
+ str ^= Api::UnwrapAsPersistentHandle(handles[i])->raw();
EXPECT(str.Equals(kTestString1));
}
for (int i = 1500; i < 2000; i++) {
String& str = String::Handle();
- str ^= Api::UnwrapHandle(handles[i]);
+ str ^= Api::UnwrapAsPersistentHandle(handles[i])->raw();
EXPECT(str.Equals(kTestString2));
}
}
@@ -1497,17 +1481,19 @@
DARTSCOPE(isolate);
// Start with a known persistent handle.
- Dart_Handle obj1 = Dart_True();
+ Dart_PersistentHandle obj1 = Dart_NewPersistentHandle(Dart_True());
EXPECT(state->IsValidPersistentHandle(obj1));
// And use it to allocate a second persistent handle.
- Dart_Handle obj2 = Dart_NewPersistentHandle(obj1);
- EXPECT(state->IsValidPersistentHandle(obj2));
+ Dart_Handle obj2 = Dart_HandleFromPersistent(obj1);
+ Dart_PersistentHandle obj3 = Dart_NewPersistentHandle(obj2);
+ EXPECT(state->IsValidPersistentHandle(obj3));
// Make sure that the value transferred.
- EXPECT(Dart_IsBoolean(obj2));
+ Dart_Handle obj4 = Dart_HandleFromPersistent(obj3);
+ EXPECT(Dart_IsBoolean(obj4));
bool value = false;
- Dart_Handle result = Dart_BooleanValue(obj2, &value);
+ Dart_Handle result = Dart_BooleanValue(obj4, &value);
EXPECT_VALID(result);
EXPECT(value);
}
@@ -1526,12 +1512,24 @@
};
-TEST_CASE(WeakPersistentHandle) {
- Dart_Handle weak_new_ref = Dart_Null();
- EXPECT(Dart_IsNull(weak_new_ref));
+static Dart_Handle AsHandle(Dart_PersistentHandle weak) {
+ return Dart_HandleFromPersistent(weak);
+}
- Dart_Handle weak_old_ref = Dart_Null();
- EXPECT(Dart_IsNull(weak_old_ref));
+
+static Dart_Handle AsHandle(Dart_WeakPersistentHandle weak) {
+ return Dart_HandleFromWeakPersistent(weak);
+}
+
+
+TEST_CASE(WeakPersistentHandle) {
+ Dart_Handle local_new_ref = Dart_Null();
+ Dart_WeakPersistentHandle weak_new_ref = Dart_NewWeakPersistentHandle(
+ local_new_ref, NULL, NULL);
+
+ Dart_Handle local_old_ref = Dart_Null();
+ Dart_WeakPersistentHandle weak_old_ref = Dart_NewWeakPersistentHandle(
+ local_old_ref, NULL, NULL);
{
Dart_EnterScope();
@@ -1551,13 +1549,13 @@
// Create a weak ref to the new space object.
weak_new_ref = Dart_NewWeakPersistentHandle(new_ref, NULL, NULL);
- EXPECT_VALID(weak_new_ref);
- EXPECT(!Dart_IsNull(weak_new_ref));
+ EXPECT_VALID(AsHandle(weak_new_ref));
+ EXPECT(!Dart_IsNull(AsHandle(weak_new_ref)));
// Create a weak ref to the old space object.
weak_old_ref = Dart_NewWeakPersistentHandle(old_ref, NULL, NULL);
- EXPECT_VALID(weak_old_ref);
- EXPECT(!Dart_IsNull(weak_old_ref));
+ EXPECT_VALID(AsHandle(weak_old_ref));
+ EXPECT(!Dart_IsNull(AsHandle(weak_old_ref)));
// Garbage collect new space.
GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
@@ -1568,13 +1566,13 @@
EXPECT_VALID(old_ref);
EXPECT(!Dart_IsNull(old_ref));
- EXPECT_VALID(weak_new_ref);
- EXPECT(!Dart_IsNull(weak_new_ref));
- EXPECT(Dart_IdentityEquals(new_ref, weak_new_ref));
+ EXPECT_VALID(AsHandle(weak_new_ref));
+ EXPECT(!Dart_IsNull(AsHandle(weak_new_ref)));
+ EXPECT(Dart_IdentityEquals(new_ref, AsHandle(weak_new_ref)));
- EXPECT_VALID(weak_old_ref);
- EXPECT(!Dart_IsNull(weak_old_ref));
- EXPECT(Dart_IdentityEquals(old_ref, weak_old_ref));
+ EXPECT_VALID(AsHandle(weak_old_ref));
+ EXPECT(!Dart_IsNull(AsHandle(weak_old_ref)));
+ EXPECT(Dart_IdentityEquals(old_ref, AsHandle(weak_old_ref)));
// Garbage collect old space.
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
@@ -1585,13 +1583,13 @@
EXPECT_VALID(old_ref);
EXPECT(!Dart_IsNull(old_ref));
- EXPECT_VALID(weak_new_ref);
- EXPECT(!Dart_IsNull(weak_new_ref));
- EXPECT(Dart_IdentityEquals(new_ref, weak_new_ref));
+ EXPECT_VALID(AsHandle(weak_new_ref));
+ EXPECT(!Dart_IsNull(AsHandle(weak_new_ref)));
+ EXPECT(Dart_IdentityEquals(new_ref, AsHandle(weak_new_ref)));
- EXPECT_VALID(weak_old_ref);
- EXPECT(!Dart_IsNull(weak_old_ref));
- EXPECT(Dart_IdentityEquals(old_ref, weak_old_ref));
+ EXPECT_VALID(AsHandle(weak_old_ref));
+ EXPECT(!Dart_IsNull(AsHandle(weak_old_ref)));
+ EXPECT(Dart_IdentityEquals(old_ref, AsHandle(weak_old_ref)));
// Delete local (strong) references.
Dart_ExitScope();
@@ -1600,23 +1598,31 @@
// Garbage collect new space again.
GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
- // Weak ref to new space object should now be cleared.
- EXPECT_VALID(weak_new_ref);
- EXPECT(Dart_IsNull(weak_new_ref));
- EXPECT_VALID(weak_old_ref);
- EXPECT(!Dart_IsNull(weak_old_ref));
+ {
+ Dart_EnterScope();
+ // Weak ref to new space object should now be cleared.
+ EXPECT_VALID(AsHandle(weak_new_ref));
+ EXPECT(Dart_IsNull(AsHandle(weak_new_ref)));
+ EXPECT_VALID(AsHandle(weak_old_ref));
+ EXPECT(!Dart_IsNull(AsHandle(weak_old_ref)));
+ Dart_ExitScope();
+ }
// Garbage collect old space again.
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
- // Weak ref to old space object should now be cleared.
- EXPECT_VALID(weak_new_ref);
- EXPECT(Dart_IsNull(weak_new_ref));
- EXPECT_VALID(weak_old_ref);
- EXPECT(Dart_IsNull(weak_old_ref));
+ {
+ Dart_EnterScope();
+ // Weak ref to old space object should now be cleared.
+ EXPECT_VALID(AsHandle(weak_new_ref));
+ EXPECT(Dart_IsNull(AsHandle(weak_new_ref)));
+ EXPECT_VALID(AsHandle(weak_old_ref));
+ EXPECT(Dart_IsNull(AsHandle(weak_old_ref)));
+ Dart_ExitScope();
+ }
- Dart_DeletePersistentHandle(weak_new_ref);
- Dart_DeletePersistentHandle(weak_old_ref);
+ Dart_DeleteWeakPersistentHandle(weak_new_ref);
+ Dart_DeleteWeakPersistentHandle(weak_old_ref);
// Garbage collect one last time to revisit deleted handles.
Isolate::Current()->heap()->CollectGarbage(Heap::kNew);
@@ -1624,14 +1630,14 @@
}
-static void WeakPersistentHandlePeerFinalizer(Dart_Handle handle, void* peer) {
+static void WeakPersistentHandlePeerFinalizer(
+ Dart_WeakPersistentHandle handle, void* peer) {
*static_cast<int*>(peer) = 42;
}
TEST_CASE(WeakPersistentHandleCallback) {
- Dart_Handle weak_ref = Dart_Null();
- EXPECT(Dart_IsNull(weak_ref));
+ Dart_WeakPersistentHandle weak_ref = NULL;
int peer = 0;
{
Dart_EnterScope();
@@ -1639,21 +1645,20 @@
EXPECT_VALID(obj);
weak_ref = Dart_NewWeakPersistentHandle(obj, &peer,
WeakPersistentHandlePeerFinalizer);
+ EXPECT_VALID(AsHandle(weak_ref));
+ EXPECT(peer == 0);
Dart_ExitScope();
}
- EXPECT_VALID(weak_ref);
- EXPECT(peer == 0);
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
EXPECT(peer == 0);
GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
EXPECT(peer == 42);
- Dart_DeletePersistentHandle(weak_ref);
+ Dart_DeleteWeakPersistentHandle(weak_ref);
}
TEST_CASE(WeakPersistentHandleNoCallback) {
- Dart_Handle weak_ref = Dart_Null();
- EXPECT(Dart_IsNull(weak_ref));
+ Dart_WeakPersistentHandle weak_ref = NULL;
int peer = 0;
{
Dart_EnterScope();
@@ -1665,8 +1670,7 @@
}
// A finalizer is not invoked on a deleted handle. Therefore, the
// peer value should not change after the referent is collected.
- Dart_DeletePersistentHandle(weak_ref);
- EXPECT_VALID(weak_ref);
+ Dart_DeleteWeakPersistentHandle(weak_ref);
EXPECT(peer == 0);
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
EXPECT(peer == 0);
@@ -1689,116 +1693,125 @@
TEST_CASE(ObjectGroups) {
- Dart_Handle strong = Dart_Null();
- EXPECT(Dart_IsNull(strong));
+ Dart_PersistentHandle strong = NULL;
+ Dart_WeakPersistentHandle strong_weak = NULL;
- Dart_Handle weak1 = Dart_Null();
- EXPECT(Dart_IsNull(weak1));
-
- Dart_Handle weak2 = Dart_Null();
- EXPECT(Dart_IsNull(weak2));
-
- Dart_Handle weak3 = Dart_Null();
- EXPECT(Dart_IsNull(weak3));
-
- Dart_Handle weak4 = Dart_Null();
- EXPECT(Dart_IsNull(weak4));
+ Dart_WeakPersistentHandle weak1 = NULL;
+ Dart_WeakPersistentHandle weak2 = NULL;
+ Dart_WeakPersistentHandle weak3 = NULL;
+ Dart_WeakPersistentHandle weak4 = NULL;
Dart_EnterScope();
{
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
- strong = Dart_NewPersistentHandle(
- Api::NewHandle(isolate, String::New("strongly reachable", Heap::kOld)));
- EXPECT_VALID(strong);
- EXPECT(!Dart_IsNull(strong));
+ Dart_Handle local = Api::NewHandle(
+ isolate, String::New("strongly reachable", Heap::kOld));
+ strong = Dart_NewPersistentHandle(local);
+ strong_weak = Dart_NewWeakPersistentHandle(local, NULL, NULL);
+ EXPECT_VALID(AsHandle(strong));
+ EXPECT(!Dart_IsNull(AsHandle(strong)));
weak1 = Dart_NewWeakPersistentHandle(
Api::NewHandle(isolate, String::New("weakly reachable 1", Heap::kOld)),
NULL, NULL);
- EXPECT_VALID(weak1);
- EXPECT(!Dart_IsNull(weak1));
+ EXPECT_VALID(AsHandle(weak1));
+ EXPECT(!Dart_IsNull(AsHandle(weak1)));
weak2 = Dart_NewWeakPersistentHandle(
Api::NewHandle(isolate, String::New("weakly reachable 2", Heap::kOld)),
NULL, NULL);
- EXPECT_VALID(weak2);
- EXPECT(!Dart_IsNull(weak2));
+ EXPECT_VALID(AsHandle(weak2));
+ EXPECT(!Dart_IsNull(AsHandle(weak2)));
weak3 = Dart_NewWeakPersistentHandle(
Api::NewHandle(isolate, String::New("weakly reachable 3", Heap::kOld)),
NULL, NULL);
- EXPECT_VALID(weak3);
- EXPECT(!Dart_IsNull(weak3));
+ EXPECT_VALID(AsHandle(weak3));
+ EXPECT(!Dart_IsNull(AsHandle(weak3)));
weak4 = Dart_NewWeakPersistentHandle(
Api::NewHandle(isolate, String::New("weakly reachable 4", Heap::kOld)),
NULL, NULL);
- EXPECT_VALID(weak4);
- EXPECT(!Dart_IsNull(weak4));
+ EXPECT_VALID(AsHandle(weak4));
+ EXPECT(!Dart_IsNull(AsHandle(weak4)));
}
Dart_ExitScope();
- EXPECT_VALID(strong);
-
- EXPECT_VALID(weak1);
- EXPECT_VALID(weak2);
- EXPECT_VALID(weak3);
- EXPECT_VALID(weak4);
+ {
+ Dart_EnterScope();
+ EXPECT_VALID(AsHandle(strong));
+ EXPECT_VALID(AsHandle(weak1));
+ EXPECT_VALID(AsHandle(weak2));
+ EXPECT_VALID(AsHandle(weak3));
+ EXPECT_VALID(AsHandle(weak4));
+ Dart_ExitScope();
+ }
GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
- // New space collection should not affect old space objects
- EXPECT(!Dart_IsNull(weak1));
- EXPECT(!Dart_IsNull(weak2));
- EXPECT(!Dart_IsNull(weak3));
- EXPECT(!Dart_IsNull(weak4));
+ {
+ Dart_EnterScope();
+ // New space collection should not affect old space objects
+ EXPECT(!Dart_IsNull(AsHandle(weak1)));
+ EXPECT(!Dart_IsNull(AsHandle(weak2)));
+ EXPECT(!Dart_IsNull(AsHandle(weak3)));
+ EXPECT(!Dart_IsNull(AsHandle(weak4)));
+ Dart_ExitScope();
+ }
{
- Dart_Handle array1[] = { weak1, strong };
+ Dart_WeakPersistentHandle array1[] = { weak1, strong_weak };
EXPECT_VALID(Dart_NewWeakReferenceSet(array1, ARRAY_SIZE(array1),
array1, ARRAY_SIZE(array1)));
- Dart_Handle array2[] = { weak2, weak1 };
+ Dart_WeakPersistentHandle array2[] = { weak2, weak1 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array2, ARRAY_SIZE(array2),
array2, ARRAY_SIZE(array2)));
- Dart_Handle array3[] = { weak3, weak2 };
+ Dart_WeakPersistentHandle array3[] = { weak3, weak2 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array3, ARRAY_SIZE(array3),
array3, ARRAY_SIZE(array3)));
- Dart_Handle array4[] = { weak4, weak3 };
+ Dart_WeakPersistentHandle array4[] = { weak4, weak3 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array4, ARRAY_SIZE(array4),
array4, ARRAY_SIZE(array4)));
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
}
- // All weak references should be preserved.
- EXPECT(!Dart_IsNull(weak1));
- EXPECT(!Dart_IsNull(weak2));
- EXPECT(!Dart_IsNull(weak3));
- EXPECT(!Dart_IsNull(weak4));
+ {
+ Dart_EnterScope();
+ // All weak references should be preserved.
+ EXPECT(!Dart_IsNull(AsHandle(strong_weak)));
+ EXPECT(!Dart_IsNull(AsHandle(weak1)));
+ EXPECT(!Dart_IsNull(AsHandle(weak2)));
+ EXPECT(!Dart_IsNull(AsHandle(weak3)));
+ EXPECT(!Dart_IsNull(AsHandle(weak4)));
+ Dart_ExitScope();
+ }
{
- Dart_Handle array1[] = { weak1, strong };
+ Dart_EnterScope();
+ Dart_WeakPersistentHandle array1[] = { weak1, strong_weak };
EXPECT_VALID(Dart_NewWeakReferenceSet(array1, ARRAY_SIZE(array1),
array1, ARRAY_SIZE(array1)));
- Dart_Handle array2[] = { weak2, weak1 };
+ Dart_WeakPersistentHandle array2[] = { weak2, weak1 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array2, ARRAY_SIZE(array2),
array2, ARRAY_SIZE(array2)));
- Dart_Handle array3[] = { weak2 };
+ Dart_WeakPersistentHandle array3[] = { weak2 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array3, ARRAY_SIZE(array3),
array3, ARRAY_SIZE(array3)));
// Strong reference to weak3 to retain weak3 and weak4.
- Dart_Handle weak3_strong_ref = Dart_NewPersistentHandle(weak3);
- EXPECT_VALID(weak3_strong_ref);
+ Dart_PersistentHandle weak3_strong_ref =
+ Dart_NewPersistentHandle(AsHandle(weak3));
+ EXPECT_VALID(AsHandle(weak3_strong_ref));
- Dart_Handle array4[] = { weak4, weak3 };
+ Dart_WeakPersistentHandle array4[] = { weak4, weak3 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array4, ARRAY_SIZE(array4),
array4, ARRAY_SIZE(array4)));
@@ -1806,86 +1819,106 @@
// Delete strong reference to weak3.
Dart_DeletePersistentHandle(weak3_strong_ref);
+ Dart_ExitScope();
}
- // All weak references should be preserved.
- EXPECT(!Dart_IsNull(weak1));
- EXPECT(!Dart_IsNull(weak2));
- EXPECT(!Dart_IsNull(weak3));
- EXPECT(!Dart_IsNull(weak4));
+ {
+ Dart_EnterScope();
+ // All weak references should be preserved.
+ EXPECT(!Dart_IsNull(AsHandle(strong_weak)));
+ EXPECT(!Dart_IsNull(AsHandle(weak1)));
+ EXPECT(!Dart_IsNull(AsHandle(weak2)));
+ EXPECT(!Dart_IsNull(AsHandle(weak3)));
+ EXPECT(!Dart_IsNull(AsHandle(weak4)));
+ Dart_ExitScope();
+ }
{
- Dart_Handle array1[] = { weak1, strong };
+ Dart_WeakPersistentHandle array1[] = { weak1, strong_weak };
EXPECT_VALID(Dart_NewWeakReferenceSet(array1, ARRAY_SIZE(array1),
array1, ARRAY_SIZE(array1)));
- Dart_Handle array2[] = { weak2, weak1 };
+ Dart_WeakPersistentHandle array2[] = { weak2, weak1 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array2, ARRAY_SIZE(array2),
array2, ARRAY_SIZE(array2)));
- Dart_Handle array3[] = { weak2 };
+ Dart_WeakPersistentHandle array3[] = { weak2 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array3, ARRAY_SIZE(array3),
array3, ARRAY_SIZE(array3)));
- Dart_Handle array4[] = { weak4, weak3 };
+ Dart_WeakPersistentHandle array4[] = { weak4, weak3 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array4, ARRAY_SIZE(array4),
array4, ARRAY_SIZE(array4)));
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
}
- // Only weak1 and weak2 should be preserved.
- EXPECT(!Dart_IsNull(weak1));
- EXPECT(!Dart_IsNull(weak2));
- EXPECT(Dart_IsNull(weak3));
- EXPECT(Dart_IsNull(weak4));
+ {
+ Dart_EnterScope();
+ // Only weak1 and weak2 should be preserved.
+ EXPECT(!Dart_IsNull(AsHandle(strong_weak)));
+ EXPECT(!Dart_IsNull(AsHandle(weak1)));
+ EXPECT(!Dart_IsNull(AsHandle(weak2)));
+ EXPECT(Dart_IsNull(AsHandle(weak3)));
+ EXPECT(Dart_IsNull(AsHandle(weak4)));
+ Dart_ExitScope();
+ }
{
- Dart_Handle array1[] = { weak1, strong };
+ Dart_WeakPersistentHandle array1[] = { weak1, strong_weak };
EXPECT_VALID(Dart_NewWeakReferenceSet(array1, ARRAY_SIZE(array1),
array1, ARRAY_SIZE(array1)));
// weak3 is cleared so weak2 is unreferenced and should be cleared
- Dart_Handle array2[] = { weak2, weak3 };
+ Dart_WeakPersistentHandle array2[] = { weak2, weak3 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array2, ARRAY_SIZE(array2),
array2, ARRAY_SIZE(array2)));
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
}
- // Only weak1 should be preserved, weak3 should not preserve weak2.
- EXPECT(!Dart_IsNull(weak1));
- EXPECT(Dart_IsNull(weak2));
- EXPECT(Dart_IsNull(weak3)); // was cleared, should remain cleared
- EXPECT(Dart_IsNull(weak4)); // was cleared, should remain cleared
+ {
+ Dart_EnterScope();
+ // Only weak1 should be preserved, weak3 should not preserve weak2.
+ EXPECT(!Dart_IsNull(AsHandle(strong_weak)));
+ EXPECT(!Dart_IsNull(AsHandle(weak1)));
+ EXPECT(Dart_IsNull(AsHandle(weak2)));
+ EXPECT(Dart_IsNull(AsHandle(weak3))); // was cleared, should remain cleared
+ EXPECT(Dart_IsNull(AsHandle(weak4))); // was cleared, should remain cleared
+ Dart_ExitScope();
+ }
{
// weak{2,3,4} are cleared and should have no effect on weak1
- Dart_Handle array1[] = { strong, weak2, weak3, weak4 };
+ Dart_WeakPersistentHandle array1[] = { strong_weak, weak2, weak3, weak4 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array1, ARRAY_SIZE(array1),
array1, ARRAY_SIZE(array1)));
// weak1 is weakly reachable and should be cleared
- Dart_Handle array2[] = { weak1 };
+ Dart_WeakPersistentHandle array2[] = { weak1 };
EXPECT_VALID(Dart_NewWeakReferenceSet(array2, ARRAY_SIZE(array2),
array2, ARRAY_SIZE(array2)));
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
}
- // All weak references should now be cleared.
- EXPECT(Dart_IsNull(weak1));
- EXPECT(Dart_IsNull(weak2));
- EXPECT(Dart_IsNull(weak3));
- EXPECT(Dart_IsNull(weak4));
+ {
+ Dart_EnterScope();
+ // All weak references should now be cleared.
+ EXPECT(!Dart_IsNull(AsHandle(strong_weak)));
+ EXPECT(Dart_IsNull(AsHandle(weak1)));
+ EXPECT(Dart_IsNull(AsHandle(weak2)));
+ EXPECT(Dart_IsNull(AsHandle(weak3)));
+ EXPECT(Dart_IsNull(AsHandle(weak4)));
+ Dart_ExitScope();
+ }
}
TEST_CASE(PrologueWeakPersistentHandles) {
- Dart_Handle old_pwph = Dart_Null();
- EXPECT(Dart_IsNull(old_pwph));
- Dart_Handle new_pwph = Dart_Null();
- EXPECT(Dart_IsNull(new_pwph));
+ Dart_WeakPersistentHandle old_pwph = NULL;
+ Dart_WeakPersistentHandle new_pwph = NULL;
+
Dart_EnterScope();
{
Isolate* isolate = Isolate::Current();
@@ -1894,215 +1927,276 @@
Api::NewHandle(isolate,
String::New("new space prologue weak", Heap::kNew)),
NULL, NULL);
- EXPECT_VALID(new_pwph);
- EXPECT(!Dart_IsNull(new_pwph));
+ EXPECT_VALID(AsHandle(new_pwph));
+ EXPECT(!Dart_IsNull(AsHandle(new_pwph)));
old_pwph = Dart_NewPrologueWeakPersistentHandle(
Api::NewHandle(isolate,
String::New("old space prologue weak", Heap::kOld)),
NULL, NULL);
- EXPECT_VALID(old_pwph);
- EXPECT(!Dart_IsNull(old_pwph));
+ EXPECT_VALID(AsHandle(old_pwph));
+ EXPECT(!Dart_IsNull(AsHandle(old_pwph)));
}
Dart_ExitScope();
- EXPECT_VALID(new_pwph);
- EXPECT(!Dart_IsNull(new_pwph));
- EXPECT(Dart_IsPrologueWeakPersistentHandle(new_pwph));
- EXPECT_VALID(old_pwph);
- EXPECT(!Dart_IsNull(old_pwph));
- EXPECT(Dart_IsPrologueWeakPersistentHandle(old_pwph));
+
+ {
+ Dart_EnterScope();
+ EXPECT_VALID(AsHandle(new_pwph));
+ EXPECT(!Dart_IsNull(AsHandle(new_pwph)));
+ EXPECT(Dart_IsPrologueWeakPersistentHandle(new_pwph));
+ EXPECT_VALID(AsHandle(old_pwph));
+ EXPECT(!Dart_IsNull(AsHandle(old_pwph)));
+ EXPECT(Dart_IsPrologueWeakPersistentHandle(old_pwph));
+ Dart_ExitScope();
+ }
+
// Garbage collect new space without invoking API callbacks.
GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
- // Both prologue weak handles should be preserved.
- EXPECT(!Dart_IsNull(new_pwph));
- EXPECT(!Dart_IsNull(old_pwph));
+ {
+ Dart_EnterScope();
+ // Both prologue weak handles should be preserved.
+ EXPECT(!Dart_IsNull(AsHandle(new_pwph)));
+ EXPECT(!Dart_IsNull(AsHandle(old_pwph)));
+ Dart_ExitScope();
+ }
+
// Garbage collect old space without invoking API callbacks.
Isolate::Current()->heap()->CollectGarbage(Heap::kOld,
Heap::kIgnoreApiCallbacks);
- // Both prologue weak handles should be preserved.
- EXPECT(!Dart_IsNull(new_pwph));
- EXPECT(!Dart_IsNull(old_pwph));
+
+ {
+ Dart_EnterScope();
+ // Both prologue weak handles should be preserved.
+ EXPECT(!Dart_IsNull(AsHandle(new_pwph)));
+ EXPECT(!Dart_IsNull(AsHandle(old_pwph)));
+ Dart_ExitScope();
+ }
+
// Garbage collect new space invoking API callbacks.
GCTestHelper::CollectNewSpace(Heap::kInvokeApiCallbacks);
- // The prologue weak handle with a new space referent should now be
- // cleared. The old space referent should be preserved.
- EXPECT(Dart_IsNull(new_pwph));
- EXPECT(!Dart_IsNull(old_pwph));
+ {
+ Dart_EnterScope();
+ // The prologue weak handle with a new space referent should now be
+ // cleared. The old space referent should be preserved.
+ EXPECT(Dart_IsNull(AsHandle(new_pwph)));
+ EXPECT(!Dart_IsNull(AsHandle(old_pwph)));
+ Dart_ExitScope();
+ }
+
Isolate::Current()->heap()->CollectGarbage(Heap::kOld,
Heap::kInvokeApiCallbacks);
- // The prologue weak handle with an old space referent should now be
- // cleared. The new space referent should remain cleared.
- EXPECT(Dart_IsNull(new_pwph));
- EXPECT(Dart_IsNull(old_pwph));
+
+ {
+ Dart_EnterScope();
+ // The prologue weak handle with an old space referent should now be
+ // cleared. The new space referent should remain cleared.
+ EXPECT(Dart_IsNull(AsHandle(new_pwph)));
+ EXPECT(Dart_IsNull(AsHandle(old_pwph)));
+ Dart_ExitScope();
+ }
}
TEST_CASE(ImplicitReferencesOldSpace) {
- Dart_Handle strong = Dart_Null();
- EXPECT(Dart_IsNull(strong));
+ Dart_PersistentHandle strong = NULL;
+ Dart_WeakPersistentHandle strong_weak = NULL;
- Dart_Handle weak1 = Dart_Null();
- EXPECT(Dart_IsNull(weak1));
-
- Dart_Handle weak2 = Dart_Null();
- EXPECT(Dart_IsNull(weak2));
-
- Dart_Handle weak3 = Dart_Null();
- EXPECT(Dart_IsNull(weak3));
+ Dart_WeakPersistentHandle weak1 = NULL;
+ Dart_WeakPersistentHandle weak2 = NULL;
+ Dart_WeakPersistentHandle weak3 = NULL;
Dart_EnterScope();
{
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
- strong = Dart_NewPersistentHandle(
- Api::NewHandle(isolate, String::New("strongly reachable", Heap::kOld)));
- EXPECT(!Dart_IsNull(strong));
- EXPECT_VALID(strong);
+ Dart_Handle local = Api::NewHandle(
+ isolate, String::New("strongly reachable", Heap::kOld));
+ strong = Dart_NewPersistentHandle(local);
+ strong_weak = Dart_NewWeakPersistentHandle(local, NULL, NULL);
+
+ EXPECT(!Dart_IsNull(AsHandle(strong)));
+ EXPECT_VALID(AsHandle(strong));
+ EXPECT(!Dart_IsNull(AsHandle(strong_weak)));
+ EXPECT_VALID(AsHandle(strong_weak));
+ EXPECT(Dart_IdentityEquals(AsHandle(strong), AsHandle(strong_weak)))
weak1 = Dart_NewWeakPersistentHandle(
Api::NewHandle(isolate, String::New("weakly reachable 1", Heap::kOld)),
NULL, NULL);
- EXPECT(!Dart_IsNull(weak1));
- EXPECT_VALID(weak1);
+ EXPECT(!Dart_IsNull(AsHandle(weak1)));
+ EXPECT_VALID(AsHandle(weak1));
weak2 = Dart_NewWeakPersistentHandle(
Api::NewHandle(isolate, String::New("weakly reachable 2", Heap::kOld)),
NULL, NULL);
- EXPECT(!Dart_IsNull(weak2));
- EXPECT_VALID(weak2);
+ EXPECT(!Dart_IsNull(AsHandle(weak2)));
+ EXPECT_VALID(AsHandle(weak2));
weak3 = Dart_NewWeakPersistentHandle(
Api::NewHandle(isolate, String::New("weakly reachable 3", Heap::kOld)),
NULL, NULL);
- EXPECT(!Dart_IsNull(weak3));
- EXPECT_VALID(weak3);
+ EXPECT(!Dart_IsNull(AsHandle(weak3)));
+ EXPECT_VALID(AsHandle(weak3));
}
Dart_ExitScope();
- EXPECT_VALID(strong);
-
- EXPECT_VALID(weak1);
- EXPECT_VALID(weak2);
- EXPECT_VALID(weak3);
+ {
+ Dart_EnterScope();
+ EXPECT_VALID(AsHandle(strong_weak));
+ EXPECT_VALID(AsHandle(weak1));
+ EXPECT_VALID(AsHandle(weak2));
+ EXPECT_VALID(AsHandle(weak3));
+ Dart_ExitScope();
+ }
GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
- // New space collection should not affect old space objects
- EXPECT(!Dart_IsNull(weak1));
- EXPECT(!Dart_IsNull(weak2));
- EXPECT(!Dart_IsNull(weak3));
+ {
+ Dart_EnterScope();
+ // New space collection should not affect old space objects
+ EXPECT_VALID(AsHandle(strong_weak));
+ EXPECT(!Dart_IsNull(AsHandle(weak1)));
+ EXPECT(!Dart_IsNull(AsHandle(weak2)));
+ EXPECT(!Dart_IsNull(AsHandle(weak3)));
+ Dart_ExitScope();
+ }
// A strongly referenced key should preserve all the values.
{
- Dart_Handle keys[] = { strong };
- Dart_Handle values[] = { weak1, weak2, weak3 };
+ Dart_WeakPersistentHandle keys[] = { strong_weak };
+ Dart_WeakPersistentHandle values[] = { weak1, weak2, weak3 };
EXPECT_VALID(Dart_NewWeakReferenceSet(keys, ARRAY_SIZE(keys),
values, ARRAY_SIZE(values)));
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
}
- // All weak references should be preserved.
- EXPECT(!Dart_IsNull(weak1));
- EXPECT(!Dart_IsNull(weak2));
- EXPECT(!Dart_IsNull(weak3));
+ {
+ Dart_EnterScope();
+ // All weak references should be preserved.
+ EXPECT_VALID(AsHandle(strong_weak));
+ EXPECT(!Dart_IsNull(AsHandle(weak1)));
+ EXPECT(!Dart_IsNull(AsHandle(weak2)));
+ EXPECT(!Dart_IsNull(AsHandle(weak3)));
+ Dart_ExitScope();
+ }
// Key membership does not imply a strong reference.
{
- Dart_Handle keys[] = { strong, weak3 };
- Dart_Handle values[] = { weak1, weak2 };
+ Dart_WeakPersistentHandle keys[] = { strong_weak, weak3 };
+ Dart_WeakPersistentHandle values[] = { weak1, weak2 };
EXPECT_VALID(Dart_NewWeakReferenceSet(keys, ARRAY_SIZE(keys),
values, ARRAY_SIZE(values)));
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
}
- // All weak references except weak3 should be preserved.
- EXPECT(!Dart_IsNull(weak1));
- EXPECT(!Dart_IsNull(weak2));
- EXPECT(Dart_IsNull(weak3));
+ {
+ Dart_EnterScope();
+ // All weak references except weak3 should be preserved.
+ EXPECT(!Dart_IsNull(AsHandle(weak1)));
+ EXPECT(!Dart_IsNull(AsHandle(weak2)));
+ EXPECT(Dart_IsNull(AsHandle(weak3)));
+ Dart_ExitScope();
+ }
}
TEST_CASE(ImplicitReferencesNewSpace) {
- Dart_Handle strong = Dart_Null();
- EXPECT(Dart_IsNull(strong));
+ Dart_PersistentHandle strong = NULL;
+ Dart_WeakPersistentHandle strong_weak = NULL;
- Dart_Handle weak1 = Dart_Null();
- EXPECT(Dart_IsNull(weak1));
-
- Dart_Handle weak2 = Dart_Null();
- EXPECT(Dart_IsNull(weak2));
-
- Dart_Handle weak3 = Dart_Null();
- EXPECT(Dart_IsNull(weak3));
+ Dart_WeakPersistentHandle weak1 = NULL;
+ Dart_WeakPersistentHandle weak2 = NULL;
+ Dart_WeakPersistentHandle weak3 = NULL;
Dart_EnterScope();
{
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
- strong = Dart_NewPersistentHandle(
- Api::NewHandle(isolate, String::New("strongly reachable", Heap::kNew)));
- EXPECT(!Dart_IsNull(strong));
- EXPECT_VALID(strong);
+ Dart_Handle local = Api::NewHandle(
+ isolate, String::New("strongly reachable", Heap::kOld));
+ strong = Dart_NewPersistentHandle(local);
+ strong_weak = Dart_NewWeakPersistentHandle(local, NULL, NULL);
+
+ EXPECT(!Dart_IsNull(AsHandle(strong)));
+ EXPECT_VALID(AsHandle(strong));
+ EXPECT(!Dart_IsNull(AsHandle(strong_weak)));
+ EXPECT_VALID(AsHandle(strong_weak));
+ EXPECT(Dart_IdentityEquals(AsHandle(strong), AsHandle(strong_weak)))
weak1 = Dart_NewWeakPersistentHandle(
Api::NewHandle(isolate, String::New("weakly reachable 1", Heap::kNew)),
NULL, NULL);
- EXPECT(!Dart_IsNull(weak1));
- EXPECT_VALID(weak1);
+ EXPECT(!Dart_IsNull(AsHandle(weak1)));
+ EXPECT_VALID(AsHandle(weak1));
weak2 = Dart_NewWeakPersistentHandle(
Api::NewHandle(isolate, String::New("weakly reachable 2", Heap::kNew)),
NULL, NULL);
- EXPECT(!Dart_IsNull(weak2));
- EXPECT_VALID(weak2);
+ EXPECT(!Dart_IsNull(AsHandle(weak2)));
+ EXPECT_VALID(AsHandle(weak2));
weak3 = Dart_NewWeakPersistentHandle(
Api::NewHandle(isolate, String::New("weakly reachable 3", Heap::kNew)),
NULL, NULL);
- EXPECT(!Dart_IsNull(weak3));
- EXPECT_VALID(weak3);
+ EXPECT(!Dart_IsNull(AsHandle(weak3)));
+ EXPECT_VALID(AsHandle(weak3));
}
Dart_ExitScope();
- EXPECT_VALID(strong);
-
- EXPECT_VALID(weak1);
- EXPECT_VALID(weak2);
- EXPECT_VALID(weak3);
+ {
+ Dart_EnterScope();
+ EXPECT_VALID(AsHandle(strong_weak));
+ EXPECT_VALID(AsHandle(weak1));
+ EXPECT_VALID(AsHandle(weak2));
+ EXPECT_VALID(AsHandle(weak3));
+ Dart_ExitScope();
+ }
Isolate::Current()->heap()->CollectGarbage(Heap::kOld);
- // Old space collection should not affect old space objects.
- EXPECT(!Dart_IsNull(weak1));
- EXPECT(!Dart_IsNull(weak2));
- EXPECT(!Dart_IsNull(weak3));
+ {
+ Dart_EnterScope();
+ // Old space collection should not affect old space objects.
+ EXPECT(!Dart_IsNull(AsHandle(weak1)));
+ EXPECT(!Dart_IsNull(AsHandle(weak2)));
+ EXPECT(!Dart_IsNull(AsHandle(weak3)));
+ Dart_ExitScope();
+ }
// A strongly referenced key should preserve all the values.
{
- Dart_Handle keys[] = { strong };
- Dart_Handle values[] = { weak1, weak2, weak3 };
+ Dart_WeakPersistentHandle keys[] = { strong_weak };
+ Dart_WeakPersistentHandle values[] = { weak1, weak2, weak3 };
EXPECT_VALID(Dart_NewWeakReferenceSet(keys, ARRAY_SIZE(keys),
values, ARRAY_SIZE(values)));
GCTestHelper::CollectNewSpace(Heap::kInvokeApiCallbacks);
}
- // All weak references should be preserved.
- EXPECT(!Dart_IsNull(weak1));
- EXPECT(!Dart_IsNull(weak2));
- EXPECT(!Dart_IsNull(weak3));
+ {
+ Dart_EnterScope();
+ // All weak references should be preserved.
+ EXPECT(!Dart_IsNull(AsHandle(weak1)));
+ EXPECT(!Dart_IsNull(AsHandle(weak2)));
+ EXPECT(!Dart_IsNull(AsHandle(weak3)));
+ Dart_ExitScope();
+ }
GCTestHelper::CollectNewSpace(Heap::kIgnoreApiCallbacks);
- // No weak references should be preserved.
- EXPECT(Dart_IsNull(weak1));
- EXPECT(Dart_IsNull(weak2));
- EXPECT(Dart_IsNull(weak3));
+ {
+ Dart_EnterScope();
+ // No weak references should be preserved.
+ EXPECT(Dart_IsNull(AsHandle(weak1)));
+ EXPECT(Dart_IsNull(AsHandle(weak2)));
+ EXPECT(Dart_IsNull(AsHandle(weak3)));
+ Dart_ExitScope();
+ }
}
@@ -5177,7 +5271,7 @@
if (tag == kCanonicalizeUrl) {
return url;
}
- return Api::Success(Isolate::Current());
+ return Api::Success();
}
@@ -5301,7 +5395,7 @@
return Api::NewError("invalid callback");
}
index += 1;
- return Api::Success(Isolate::Current());
+ return Api::Success();
}
diff --git a/runtime/vm/dart_api_state.h b/runtime/vm/dart_api_state.h
index e1ac24e..4b58d4f 100644
--- a/runtime/vm/dart_api_state.h
+++ b/runtime/vm/dart_api_state.h
@@ -187,7 +187,7 @@
if (callback != NULL) {
void* peer = handle->peer();
handle->Clear();
- (*callback)(reinterpret_cast<Dart_Handle>(handle), peer);
+ (*callback)(reinterpret_cast<Dart_WeakPersistentHandle>(handle), peer);
} else {
handle->Clear();
}
@@ -351,7 +351,7 @@
}
// Validate if passed in handle is a Persistent Handle.
- bool IsValidHandle(Dart_Handle object) const {
+ bool IsValidHandle(Dart_PersistentHandle object) const {
return IsValidScopedHandle(reinterpret_cast<uword>(object));
}
@@ -425,7 +425,7 @@
}
// Validate if passed in handle is a Persistent Handle.
- bool IsValidHandle(Dart_Handle object) const {
+ bool IsValidHandle(Dart_WeakPersistentHandle object) const {
return IsValidScopedHandle(reinterpret_cast<uword>(object));
}
@@ -442,8 +442,8 @@
class WeakReferenceSet {
public:
- WeakReferenceSet(Dart_Handle* keys, intptr_t keys_length,
- Dart_Handle* values, intptr_t values_length)
+ WeakReferenceSet(Dart_WeakPersistentHandle* keys, intptr_t keys_length,
+ Dart_WeakPersistentHandle* values, intptr_t values_length)
: next_(NULL),
keys_(keys), num_keys_(keys_length),
values_(values), num_values_(values_length) {
@@ -456,14 +456,16 @@
RawObject** get_key(intptr_t i) {
ASSERT(i >= 0);
ASSERT(i < num_keys_);
- return (reinterpret_cast<PersistentHandle*>(keys_[i]))->raw_addr();
+ return (reinterpret_cast<FinalizablePersistentHandle*>(keys_[i]))->
+ raw_addr();
}
intptr_t num_values() const { return num_values_; }
RawObject** get_value(intptr_t i) {
ASSERT(i >= 0);
ASSERT(i < num_values_);
- return (reinterpret_cast<PersistentHandle*>(values_[i]))->raw_addr();
+ return (reinterpret_cast<FinalizablePersistentHandle*>(values_[i]))->
+ raw_addr();
}
static WeakReferenceSet* Pop(WeakReferenceSet** queue) {
@@ -485,9 +487,9 @@
private:
WeakReferenceSet* next_;
- Dart_Handle* keys_;
+ Dart_WeakPersistentHandle* keys_;
intptr_t num_keys_;
- Dart_Handle* values_;
+ Dart_WeakPersistentHandle* values_;
intptr_t num_values_;
DISALLOW_COPY_AND_ASSIGN(WeakReferenceSet);
};
@@ -617,15 +619,16 @@
return false;
}
- bool IsValidPersistentHandle(Dart_Handle object) const {
+ bool IsValidPersistentHandle(Dart_PersistentHandle object) const {
return persistent_handles_.IsValidHandle(object);
}
- bool IsValidWeakPersistentHandle(Dart_Handle object) const {
+ bool IsValidWeakPersistentHandle(Dart_WeakPersistentHandle object) const {
return weak_persistent_handles_.IsValidHandle(object);
}
- bool IsValidPrologueWeakPersistentHandle(Dart_Handle object) const {
+ bool IsValidPrologueWeakPersistentHandle(
+ Dart_WeakPersistentHandle object) const {
return prologue_weak_persistent_handles_.IsValidHandle(object);
}
@@ -655,27 +658,6 @@
}
return total;
}
- PersistentHandle* Null() {
- if (null_ == NULL) {
- null_ = persistent_handles().AllocateHandle();
- null_->set_raw(Object::null());
- }
- return null_;
- }
- PersistentHandle* True() {
- if (true_ == NULL) {
- true_ = persistent_handles().AllocateHandle();
- true_->set_raw(Bool::True());
- }
- return true_;
- }
- PersistentHandle* False() {
- if (false_ == NULL) {
- false_ = persistent_handles().AllocateHandle();
- false_->set_raw(Bool::False());
- }
- return false_;
- }
void SetupAcquiredError() {
ASSERT(acquired_error_ == NULL);
diff --git a/runtime/vm/debugger_api_impl.cc b/runtime/vm/debugger_api_impl.cc
index 123db7c..133df5b 100644
--- a/runtime/vm/debugger_api_impl.cc
+++ b/runtime/vm/debugger_api_impl.cc
@@ -78,7 +78,7 @@
CHECK_NOT_NULL(length);
CHECK_AND_CAST(DebuggerStackTrace, stack_trace, trace);
*length = stack_trace->Length();
- return Api::True(isolate);
+ return Api::Success();
}
@@ -96,7 +96,7 @@
}
*frame = reinterpret_cast<Dart_ActivationFrame>(
stack_trace->ActivationFrameAt(frame_index));
- return Api::True(isolate);
+ return Api::Success();
}
static Dart_PausedEventHandler* paused_event_handler = NULL;
@@ -204,7 +204,7 @@
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
isolate->debugger()->SetExceptionPauseInfo(pause_info);
- return Api::True(isolate);
+ return Api::Success();
}
@@ -220,7 +220,7 @@
DARTSCOPE(isolate);
CHECK_NOT_NULL(trace);
*trace = reinterpret_cast<Dart_StackTrace>(isolate->debugger()->StackTrace());
- return Api::True(isolate);
+ return Api::Success();
}
@@ -246,7 +246,7 @@
const Library& lib = Library::Handle(frame->Library());
*library_id = lib.index();
}
- return Api::True(isolate);
+ return Api::Success();
}
@@ -269,7 +269,7 @@
location->library_id = lib.index();
location->token_pos = frame->TokenPos();
}
- return Api::True(isolate);
+ return Api::Success();
}
@@ -397,7 +397,7 @@
}
debugger->OneTimeBreakAtEntry(bp_target);
- return Api::True(isolate);
+ return Api::Success();
}
@@ -408,7 +408,7 @@
ASSERT(debugger != NULL);
isolate->debugger()->RemoveBreakpoint(bp_id);
- return Api::True(isolate);
+ return Api::Success();
}
@@ -416,7 +416,7 @@
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
isolate->debugger()->SetStepOver();
- return Api::True(isolate);
+ return Api::Success();
}
@@ -424,7 +424,7 @@
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
isolate->debugger()->SetStepInto();
- return Api::True(isolate);
+ return Api::Success();
}
@@ -432,7 +432,7 @@
Isolate* isolate = Isolate::Current();
DARTSCOPE(isolate);
isolate->debugger()->SetStepOut();
- return Api::True(isolate);
+ return Api::Success();
}
@@ -493,7 +493,7 @@
UNWRAP_AND_CHECK_PARAM(Instance, obj, object_in);
CHECK_NOT_NULL(class_id);
*class_id = obj.GetClassId();
- return Api::True(isolate);
+ return Api::Success();
}
@@ -536,7 +536,7 @@
*static_fields =
Api::NewHandle(isolate, isolate->debugger()->GetStaticFields(cls));
}
- return Api::True(isolate);
+ return Api::Success();
}
@@ -747,7 +747,7 @@
CURRENT_FUNC, library_id);
}
*is_debuggable = lib.IsDebuggable();
- return Api::True(isolate);
+ return Api::Success();
}
@@ -762,7 +762,7 @@
CURRENT_FUNC, library_id);
}
lib.set_debuggable(is_debuggable);
- return Api::True(isolate);
+ return Api::Success();
}
diff --git a/runtime/vm/disassembler_arm.cc b/runtime/vm/disassembler_arm.cc
index dc1258e..ea92980 100644
--- a/runtime/vm/disassembler_arm.cc
+++ b/runtime/vm/disassembler_arm.cc
@@ -1212,8 +1212,6 @@
Unknown(instr);
}
}
- } else if (instr->IsMrcIdIsar0()) {
- Format(instr, "mrc'cond p15, 0, 'rd, c0, c2, 0");
} else {
Unknown(instr);
}
diff --git a/runtime/vm/flow_graph.cc b/runtime/vm/flow_graph.cc
index 8ebce64..d78ff5b 100644
--- a/runtime/vm/flow_graph.cc
+++ b/runtime/vm/flow_graph.cc
@@ -418,6 +418,7 @@
LoadLocalInstr* load = current->AsLoadLocal();
if (load != NULL) {
const intptr_t index = load->local().BitIndexIn(num_non_copied_params_);
+ if (index >= live_in->length()) continue; // Skip tmp_locals.
live_in->Add(index);
if (!last_loads->Contains(index)) {
last_loads->Add(index);
@@ -774,6 +775,8 @@
Definition* input_defn = v->definition();
if (input_defn->IsLoadLocal() ||
input_defn->IsStoreLocal() ||
+ input_defn->IsPushTemp() ||
+ input_defn->IsDropTemps() ||
input_defn->IsConstant()) {
// Remove the load/store from the graph.
input_defn->RemoveFromGraph();
@@ -795,8 +798,14 @@
if (definition != NULL) {
LoadLocalInstr* load = definition->AsLoadLocal();
StoreLocalInstr* store = definition->AsStoreLocal();
+ PushTempInstr* push = definition->AsPushTemp();
+ DropTempsInstr* drop = definition->AsDropTemps();
ConstantInstr* constant = definition->AsConstant();
- if ((load != NULL) || (store != NULL) || (constant != NULL)) {
+ if ((load != NULL) ||
+ (store != NULL) ||
+ (push != NULL) ||
+ (drop != NULL) ||
+ (constant != NULL)) {
intptr_t index;
Definition* result;
if (store != NULL) {
@@ -825,6 +834,17 @@
if (variable_liveness->IsLastLoad(block_entry, load)) {
(*env)[index] = constant_null();
}
+ } else if (push != NULL) {
+ result = push->value()->definition();
+ env->Add(result);
+ it.RemoveCurrentFromGraph();
+ continue;
+ } else if (drop != NULL) {
+ // Drop temps from the environment.
+ for (intptr_t j = 0; j < drop->num_temps(); j++) {
+ env->RemoveLast();
+ }
+ result = drop->value()->definition();
} else {
ASSERT(definition->is_used());
result = GetConstant(constant->value());
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index 0773a4f..42cd547 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -57,7 +57,8 @@
context_level_(0),
last_used_try_index_(CatchClauseNode::kInvalidTryIndex),
try_index_(CatchClauseNode::kInvalidTryIndex),
- graph_entry_(NULL) { }
+ graph_entry_(NULL),
+ args_pushed_(0) { }
void FlowGraphBuilder::AddCatchEntry(CatchBlockEntryInstr* entry) {
@@ -356,6 +357,7 @@
DeallocateTempIndex(definition->InputCount());
definition->set_use_kind(Definition::kValue);
definition->set_temp_index(AllocateTempIndex());
+ owner_->add_args_pushed(-definition->ArgumentCount());
if (is_empty()) {
entry_ = definition;
} else {
@@ -370,6 +372,7 @@
ASSERT(is_open());
DeallocateTempIndex(definition->InputCount());
definition->set_use_kind(Definition::kEffect);
+ owner_->add_args_pushed(-definition->ArgumentCount());
if (is_empty()) {
entry_ = definition;
} else {
@@ -384,6 +387,7 @@
ASSERT(instruction->IsPushArgument() || !instruction->IsDefinition());
ASSERT(!instruction->IsBlockEntry());
DeallocateTempIndex(instruction->InputCount());
+ owner_->add_args_pushed(-instruction->ArgumentCount());
if (is_empty()) {
entry_ = exit_ = instruction;
} else {
@@ -503,6 +507,7 @@
PushArgumentInstr* EffectGraphVisitor::PushArgument(Value* value) {
+ owner_->add_args_pushed(1);
PushArgumentInstr* result = new PushArgumentInstr(value);
AddInstruction(result);
return result;
@@ -1824,6 +1829,92 @@
}
+intptr_t EffectGraphVisitor::GetCurrentTempLocalIndex() const {
+ return kFirstLocalSlotFromFp
+ - owner()->num_stack_locals()
+ - owner()->num_copied_params()
+ - owner()->args_pushed()
+ - temp_index() + 1;
+}
+
+
+class TempLocalScope : public ValueObject {
+ public:
+ TempLocalScope(EffectGraphVisitor* visitor, Value* value)
+ : visitor_(visitor) {
+ ASSERT(value->definition()->temp_index() == visitor->temp_index() - 1);
+ intptr_t index = visitor->GetCurrentTempLocalIndex();
+ char name[64];
+ OS::SNPrint(name, 64, ":tmp_local%"Pd, index);
+ var_ = new LocalVariable(0, String::ZoneHandle(Symbols::New(name)),
+ Type::ZoneHandle(Type::DynamicType()));
+ var_->set_index(index);
+ visitor->Do(new PushTempInstr(value));
+ visitor->AllocateTempIndex();
+ }
+
+ LocalVariable* var() const { return var_; }
+
+ ~TempLocalScope() {
+ Value* result = visitor_->Bind(new LoadLocalInstr(*var_));
+ visitor_->DeallocateTempIndex(1);
+ visitor_->ReturnDefinition(new DropTempsInstr(1, result));
+ }
+
+ private:
+ EffectGraphVisitor* visitor_;
+ LocalVariable* var_;
+};
+
+
+void EffectGraphVisitor::BuildLetTempExpressions(LetNode* node) {
+ intptr_t num_temps = node->num_temps();
+ for (intptr_t i = 0; i < num_temps; ++i) {
+ ValueGraphVisitor for_value(owner(), temp_index());
+ node->InitializerAt(i)->Visit(&for_value);
+ Append(for_value);
+ Value* temp_val = for_value.value();
+ node->TempAt(i)->set_index(GetCurrentTempLocalIndex());
+ Do(new PushTempInstr(temp_val));
+ AllocateTempIndex();
+ }
+}
+
+
+void EffectGraphVisitor::VisitLetNode(LetNode* node) {
+ BuildLetTempExpressions(node);
+ intptr_t num_temps = node->num_temps();
+
+ // TODO(fschneider): Generate better code for effect context by visiting the
+ // body for effect. Currently, the value of the body expression is
+ // materialized and then dropped. This also requires changing DropTempsInstr
+ // to have zero or one inputs.
+ ValueGraphVisitor for_value(owner(), temp_index());
+ node->body()->Visit(&for_value);
+ Append(for_value);
+ Value* result_value = for_value.value();
+ DeallocateTempIndex(num_temps);
+ Do(new DropTempsInstr(num_temps, result_value));
+}
+
+
+void ValueGraphVisitor::VisitLetNode(LetNode* node) {
+ BuildLetTempExpressions(node);
+
+ ValueGraphVisitor for_value(owner(), temp_index());
+ node->body()->Visit(&for_value);
+ Append(for_value);
+ Value* result_value = for_value.value();
+ intptr_t num_temps = node->num_temps();
+ if (num_temps > 0) {
+ DeallocateTempIndex(num_temps);
+ ReturnDefinition(new DropTempsInstr(num_temps, result_value));
+ } else {
+ ReturnValue(result_value);
+ }
+}
+
+
void EffectGraphVisitor::VisitArrayNode(ArrayNode* node) {
const AbstractTypeArguments& type_args =
AbstractTypeArguments::ZoneHandle(node->type().arguments());
@@ -1834,31 +1925,28 @@
node->type(),
element_type);
Value* array_val = Bind(create);
- Definition* store = BuildStoreTemp(node->temp_local(), array_val);
- Do(store);
- const intptr_t class_id = create->Type()->ToCid();
- const intptr_t deopt_id = Isolate::kNoDeoptId;
- for (int i = 0; i < node->length(); ++i) {
- Value* array = Bind(
- new LoadLocalInstr(node->temp_local()));
- Value* index = Bind(new ConstantInstr(Smi::ZoneHandle(Smi::New(i))));
- ValueGraphVisitor for_value(owner(), temp_index());
- node->ElementAt(i)->Visit(&for_value);
- Append(for_value);
- // No store barrier needed for constants.
- const StoreBarrierType emit_store_barrier =
- for_value.value()->BindsToConstant()
- ? kNoStoreBarrier
- : kEmitStoreBarrier;
- intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(class_id);
- StoreIndexedInstr* store = new StoreIndexedInstr(
- array, index, for_value.value(),
- emit_store_barrier, index_scale, class_id, deopt_id);
- Do(store);
+ { TempLocalScope tmp(this, array_val);
+ const intptr_t class_id = create->Type()->ToCid();
+ const intptr_t deopt_id = Isolate::kNoDeoptId;
+ for (int i = 0; i < node->length(); ++i) {
+ Value* array = Bind(new LoadLocalInstr(*tmp.var()));
+ Value* index = Bind(new ConstantInstr(Smi::ZoneHandle(Smi::New(i))));
+ ValueGraphVisitor for_value(owner(), temp_index());
+ node->ElementAt(i)->Visit(&for_value);
+ Append(for_value);
+ // No store barrier needed for constants.
+ const StoreBarrierType emit_store_barrier =
+ for_value.value()->BindsToConstant()
+ ? kNoStoreBarrier
+ : kEmitStoreBarrier;
+ intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(class_id);
+ StoreIndexedInstr* store = new StoreIndexedInstr(
+ array, index, for_value.value(),
+ emit_store_barrier, index_scale, class_id, deopt_id);
+ Do(store);
+ }
}
-
- ReturnDefinition(new LoadLocalInstr(node->temp_local()));
}
@@ -2332,7 +2420,6 @@
// The type arguments are uninstantiated. We use expression_temp_var to save
// the instantiator type arguments because they have two uses.
ASSERT(owner()->parsed_function().expression_temp_var() != NULL);
- const LocalVariable& temp = *owner()->parsed_function().expression_temp_var();
const Class& instantiator_class = Class::Handle(
owner()->parsed_function().function().Owner());
Value* type_arguments_val = BuildInstantiatorTypeArguments(
@@ -2347,7 +2434,7 @@
const intptr_t len = node->type_arguments().Length();
if (node->type_arguments().IsRawInstantiatedRaw(len)) {
type_arguments_val =
- Bind(BuildStoreTemp(temp, type_arguments_val));
+ Bind(BuildStoreExprTemp(type_arguments_val));
type_arguments_val = Bind(
new ExtractConstructorTypeArgumentsInstr(
node->token_pos(),
@@ -2355,7 +2442,7 @@
instantiator_class,
type_arguments_val));
} else {
- Do(BuildStoreTemp(temp, type_arguments_val));
+ Do(BuildStoreExprTemp(type_arguments_val));
type_arguments_val = Bind(new ConstantInstr(node->type_arguments()));
}
}
@@ -2363,7 +2450,7 @@
Value* instantiator_val = NULL;
if (!use_instantiator_type_args) {
- instantiator_val = Bind(BuildLoadLocal(temp));
+ instantiator_val = Bind(BuildLoadExprTemp());
const intptr_t len = node->type_arguments().Length();
if (node->type_arguments().IsRawInstantiatedRaw(len)) {
instantiator_val =
@@ -2395,15 +2482,11 @@
// tn <- LoadLocal(temp)
Value* allocate = BuildObjectAllocation(node);
- Value* allocated_value = Bind(BuildStoreTemp(
- node->allocated_object_var(),
- allocate));
- PushArgumentInstr* push_allocated_value = PushArgument(allocated_value);
- BuildConstructorCall(node, push_allocated_value);
- Definition* load_allocated = BuildLoadLocal(
- node->allocated_object_var());
- allocated_value = Bind(load_allocated);
- ReturnValue(allocated_value);
+ { TempLocalScope tmp(this, allocate);
+ Value* allocated_tmp = Bind(new LoadLocalInstr(*tmp.var()));
+ PushArgumentInstr* push_allocated_value = PushArgument(allocated_tmp);
+ BuildConstructorCall(node, push_allocated_value);
+ }
}
@@ -3270,8 +3353,7 @@
// including the receiver.
ArrayNode* args_array = new ArrayNode(
args_pos,
- Type::ZoneHandle(Type::ArrayType()),
- *owner()->parsed_function().array_literal_var());
+ Type::ZoneHandle(Type::ArrayType()));
for (intptr_t i = 0; i < method_arguments->length(); i++) {
args_array->AddElement(method_arguments->NodeAt(i));
}
diff --git a/runtime/vm/flow_graph_builder.h b/runtime/vm/flow_graph_builder.h
index 9f613eb..a24a3d2 100644
--- a/runtime/vm/flow_graph_builder.h
+++ b/runtime/vm/flow_graph_builder.h
@@ -140,6 +140,9 @@
bool IsInlining() const { return (exit_collector_ != NULL); }
InlineExitCollector* exit_collector() const { return exit_collector_; }
+ intptr_t args_pushed() const { return args_pushed_; }
+ void add_args_pushed(intptr_t n) { args_pushed_ += n; }
+
private:
intptr_t parameter_count() const {
return num_copied_params_ + num_non_copied_params_;
@@ -162,6 +165,9 @@
intptr_t try_index_;
GraphEntryInstr* graph_entry_;
+ // Outgoing argument stack height.
+ intptr_t args_pushed_;
+
DISALLOW_IMPLICIT_CONSTRUCTORS(FlowGraphBuilder);
};
@@ -318,6 +324,10 @@
temp_index_ -= n;
}
+ // Returns a local variable index for a temporary local that is
+ // on top of the current expression stack.
+ intptr_t GetCurrentTempLocalIndex() const;
+
Value* BuildObjectAllocation(ConstructorCallNode* node);
void BuildConstructorCall(ConstructorCallNode* node,
PushArgumentInstr* alloc_value);
@@ -346,21 +356,23 @@
Value* BuildNullValue();
- private:
- // Specify a definition of the final result. Adds the definition to
- // the graph, but normally overridden in subclasses.
- virtual void ReturnDefinition(Definition* definition) {
- Do(definition);
- }
-
- protected:
// Returns true if the run-time type check can be eliminated.
bool CanSkipTypeCheck(intptr_t token_pos,
Value* value,
const AbstractType& dst_type,
const String& dst_name);
+ void BuildLetTempExpressions(LetNode* node);
+
private:
+ friend class TempLocalScope; // For ReturnDefinition.
+
+ // Specify a definition of the final result. Adds the definition to
+ // the graph, but normally overridden in subclasses.
+ virtual void ReturnDefinition(Definition* definition) {
+ Do(definition);
+ }
+
// Shared global state.
FlowGraphBuilder* owner_;
@@ -401,6 +413,7 @@
virtual void VisitStoreStaticFieldNode(StoreStaticFieldNode* node);
virtual void VisitTypeNode(TypeNode* node);
virtual void VisitCommaNode(CommaNode* node);
+ virtual void VisitLetNode(LetNode* node);
Value* value() const { return value_; }
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index a5d50b1..d56842f 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -738,7 +738,7 @@
}
// Allocate all unallocated input locations.
- const bool should_pop = !instr->IsPushArgument();
+ const bool should_pop = !instr->IsPushArgument() && !instr->IsPushTemp();
for (intptr_t i = locs->input_count() - 1; i >= 0; i--) {
Location loc = locs->in(i);
Register reg = kNoRegister;
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index c4317a9..07981a1 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -1408,17 +1408,47 @@
}
+// Implement equality spec: if any of the arguments is null do identity check.
+// Fallthrough calls super equality.
void FlowGraphCompiler::EmitSuperEqualityCallPrologue(Register result,
Label* skip_call) {
- UNIMPLEMENTED();
+ Label check_identity, fall_through;
+ __ LoadImmediate(IP, reinterpret_cast<intptr_t>(Object::null()));
+ __ ldr(result, Address(SP, 0 * kWordSize)); // Load right operand.
+ __ cmp(result, ShifterOperand(IP)); // Is right null?
+ __ ldr(result, Address(SP, 1 * kWordSize)); // Load left operand.
+ __ b(&check_identity, EQ); // Branch if right (IP) is null; left in result.
+ __ cmp(result, ShifterOperand(IP)); // Right is non-null; is left null?
+ __ b(&fall_through, NE);
+ // Right is non-null, left is null. We could return false, but we save code
+ // by falling through with an IP different than null.
+ __ mov(IP, ShifterOperand(0));
+ __ Bind(&check_identity);
+ __ cmp(result, ShifterOperand(IP));
+ __ LoadObject(result, Bool::True(), EQ);
+ __ LoadObject(result, Bool::False(), NE);
+ __ Drop(2);
+ __ b(skip_call);
+ __ Bind(&fall_through);
}
void FlowGraphCompiler::SaveLiveRegisters(LocationSummary* locs) {
// TODO(vegorov): consider saving only caller save (volatile) registers.
- const intptr_t fpu_registers = locs->live_registers()->fpu_registers();
- if (fpu_registers > 0) {
- UNIMPLEMENTED();
+ const intptr_t fpu_regs_count = locs->live_registers()->fpu_regs_count();
+ if (fpu_regs_count > 0) {
+ __ AddImmediate(SP, -(fpu_regs_count * kFpuRegisterSize));
+ // Store fpu registers with the lowest register number at the lowest
+ // address.
+ intptr_t offset = 0;
+ for (intptr_t reg_idx = 0; reg_idx < kNumberOfFpuRegisters; ++reg_idx) {
+ DRegister fpu_reg = static_cast<DRegister>(reg_idx);
+ if (locs->live_registers()->ContainsFpuRegister(fpu_reg)) {
+ __ vstrd(fpu_reg, Address(SP, offset));
+ offset += kFpuRegisterSize;
+ }
+ }
+ ASSERT(offset == (fpu_regs_count * kFpuRegisterSize));
}
// Store general purpose registers with the lowest register number at the
@@ -1440,9 +1470,19 @@
__ PopList(cpu_registers);
}
- const intptr_t fpu_registers = locs->live_registers()->fpu_registers();
- if (fpu_registers > 0) {
- UNIMPLEMENTED();
+ const intptr_t fpu_regs_count = locs->live_registers()->fpu_regs_count();
+ if (fpu_regs_count > 0) {
+ // Fpu registers have the lowest register number at the lowest address.
+ intptr_t offset = 0;
+ for (intptr_t reg_idx = 0; reg_idx < kNumberOfFpuRegisters; ++reg_idx) {
+ DRegister fpu_reg = static_cast<DRegister>(reg_idx);
+ if (locs->live_registers()->ContainsFpuRegister(fpu_reg)) {
+ __ vldrd(fpu_reg, Address(SP, offset));
+ offset += kFpuRegisterSize;
+ }
+ }
+ ASSERT(offset == (fpu_regs_count * kFpuRegisterSize));
+ __ AddImmediate(SP, offset);
}
}
@@ -1498,7 +1538,13 @@
FpuRegister left,
FpuRegister right,
BranchInstr* branch) {
- UNIMPLEMENTED();
+ ASSERT(branch != NULL);
+ assembler()->vcmpd(left, right);
+ assembler()->vmstat();
+ BlockEntryInstr* nan_result = (true_condition == NE) ?
+ branch->true_successor() : branch->false_successor();
+ assembler()->b(GetJumpLabel(nan_result), VS);
+ branch->EmitBranchOnCondition(this, true_condition);
}
@@ -1506,7 +1552,13 @@
FpuRegister left,
FpuRegister right,
Register result) {
- UNIMPLEMENTED();
+ assembler()->vcmpd(left, right);
+ assembler()->vmstat();
+ assembler()->LoadObject(result, Bool::False());
+ Label done;
+ assembler()->b(&done, VS); // NaN -> false.
+ assembler()->LoadObject(result, Bool::True(), true_condition);
+ assembler()->Bind(&done);
}
diff --git a/runtime/vm/flow_graph_inliner.cc b/runtime/vm/flow_graph_inliner.cc
index 4788723..80a93ee 100644
--- a/runtime/vm/flow_graph_inliner.cc
+++ b/runtime/vm/flow_graph_inliner.cc
@@ -990,6 +990,9 @@
bool PolymorphicInliner::TryInlining(const Function& target) {
+ if (!target.is_optimizable()) {
+ return false;
+ }
GrowableArray<Value*> arguments(call_->ArgumentCount());
for (int i = 0; i < call_->ArgumentCount(); ++i) {
arguments.Add(call_->PushArgumentAt(i)->value());
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index 81ebad6..f22e386 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -5061,6 +5061,18 @@
}
+void ConstantPropagator::VisitPushTemp(PushTempInstr* instr) {
+ // Instruction is eliminated when translating to SSA.
+ UNREACHABLE();
+}
+
+
+void ConstantPropagator::VisitDropTemps(DropTempsInstr* instr) {
+ // Instruction is eliminated when translating to SSA.
+ UNREACHABLE();
+}
+
+
void ConstantPropagator::VisitStoreLocal(StoreLocalInstr* instr) {
// Instruction is eliminated when translating to SSA.
UNREACHABLE();
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
index d096872..7dc47d2 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -857,6 +857,16 @@
}
+CompileType PushTempInstr::ComputeType() const {
+ return CompileType::Dynamic();
+}
+
+
+CompileType DropTempsInstr::ComputeType() const {
+ return CompileType::Dynamic();
+}
+
+
CompileType* StoreLocalInstr::ComputeInitialType() const {
// Returns stored value.
return value()->Type();
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index e5d855b..3fd1a11 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -1579,6 +1579,35 @@
}
+LocationSummary* PushTempInstr::MakeLocationSummary() const {
+ return LocationSummary::Make(1,
+ Location::NoLocation(),
+ LocationSummary::kNoCall);
+}
+
+
+void PushTempInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ ASSERT(!compiler->is_optimizing());
+ // Nothing to do.
+}
+
+
+LocationSummary* DropTempsInstr::MakeLocationSummary() const {
+ return LocationSummary::Make(1,
+ Location::SameAsFirstInput(),
+ LocationSummary::kNoCall);
+}
+
+
+void DropTempsInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
+ ASSERT(!compiler->is_optimizing());
+ Register value = locs()->in(0).reg();
+ Register result = locs()->out().reg();
+ ASSERT(result == value); // Assert that register assignment is correct.
+ __ Drop(num_temps());
+}
+
+
void StoreContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
// Nothing to do. Context register was loaded by the register allocator.
ASSERT(locs()->in(0).reg() == CTX);
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index 19976f6..d998fec 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -529,6 +529,8 @@
M(PolymorphicInstanceCall) \
M(StaticCall) \
M(LoadLocal) \
+ M(PushTemp) \
+ M(DropTemps) \
M(StoreLocal) \
M(StrictCompare) \
M(EqualityCompare) \
@@ -3145,6 +3147,69 @@
};
+class PushTempInstr : public TemplateDefinition<1> {
+ public:
+ explicit PushTempInstr(Value* value) {
+ SetInputAt(0, value);
+ }
+
+ DECLARE_INSTRUCTION(PushTemp)
+
+ Value* value() const { return inputs_[0]; }
+
+ virtual CompileType ComputeType() const;
+
+ virtual bool CanDeoptimize() const { return false; }
+
+ virtual EffectSet Effects() const {
+ UNREACHABLE(); // Eliminated by SSA construction.
+ return EffectSet::None();
+ }
+
+ virtual bool MayThrow() const {
+ UNREACHABLE();
+ return false;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(PushTempInstr);
+};
+
+
+class DropTempsInstr : public TemplateDefinition<1> {
+ public:
+ explicit DropTempsInstr(intptr_t num_temps, Value* value)
+ : num_temps_(num_temps) {
+ SetInputAt(0, value);
+ }
+
+ DECLARE_INSTRUCTION(DropTemps)
+
+ Value* value() const { return inputs_[0]; }
+
+ intptr_t num_temps() const { return num_temps_; }
+
+ virtual CompileType ComputeType() const;
+
+ virtual bool CanDeoptimize() const { return false; }
+
+ virtual EffectSet Effects() const {
+ UNREACHABLE(); // Eliminated by SSA construction.
+ return EffectSet::None();
+ }
+
+ virtual bool MayThrow() const {
+ UNREACHABLE();
+ return false;
+ }
+
+ private:
+ intptr_t num_temps_;
+
+ DISALLOW_COPY_AND_ASSIGN(DropTempsInstr);
+};
+
+
class StoreLocalInstr : public TemplateDefinition<1> {
public:
StoreLocalInstr(const LocalVariable& local, Value* value)
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index 7e3c96b..0f9444a 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -264,13 +264,32 @@
LocationSummary* ArgumentDefinitionTestInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* locs =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
+ locs->set_in(0, Location::RegisterLocation(R0));
+ locs->set_out(Location::RegisterLocation(R0));
+ return locs;
}
void ArgumentDefinitionTestInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ Register saved_args_desc = locs()->in(0).reg();
+ Register result = locs()->out().reg();
+
+ // Push the result place holder initialized to NULL.
+ __ PushObject(Object::ZoneHandle());
+ __ LoadImmediate(IP, Smi::RawValue(formal_parameter_index()));
+ __ Push(IP);
+ __ PushObject(formal_parameter_name());
+ __ Push(saved_args_desc);
+ compiler->GenerateCallRuntime(token_pos(),
+ deopt_id(),
+ kArgumentDefinitionTestRuntimeEntry,
+ locs());
+ __ Drop(3);
+ __ Pop(result); // Pop bool result.
}
@@ -565,7 +584,43 @@
Token::Kind kind,
BranchInstr* branch,
intptr_t deopt_id) {
- UNIMPLEMENTED();
+ ASSERT((kind == Token::kEQ) || (kind == Token::kNE));
+ Register left = locs.in(0).reg();
+ Register right = locs.in(1).reg();
+ Register temp = locs.temp(0).reg();
+ Label* deopt = compiler->AddDeoptStub(deopt_id, kDeoptEquality);
+ __ tst(left, ShifterOperand(kSmiTagMask));
+ __ b(deopt, EQ);
+ // 'left' is not Smi.
+ Label identity_compare;
+ __ LoadImmediate(IP, reinterpret_cast<intptr_t>(Object::null()));
+ __ cmp(right, ShifterOperand(IP));
+ __ b(&identity_compare, EQ);
+ __ cmp(left, ShifterOperand(IP));
+ __ b(&identity_compare, EQ);
+
+ __ LoadClassId(temp, left);
+ const intptr_t len = ic_data.NumberOfChecks();
+ for (intptr_t i = 0; i < len; i++) {
+ __ CompareImmediate(temp, ic_data.GetReceiverClassIdAt(i));
+ if (i == (len - 1)) {
+ __ b(deopt, NE);
+ } else {
+ __ b(&identity_compare, EQ);
+ }
+ }
+ __ Bind(&identity_compare);
+ __ cmp(left, ShifterOperand(right));
+ if (branch == NULL) {
+ Register result = locs.out().reg();
+ __ LoadObject(result,
+ (kind == Token::kEQ) ? Bool::True() : Bool::False(), EQ);
+ __ LoadObject(result,
+ (kind == Token::kEQ) ? Bool::False() : Bool::True(), NE);
+ } else {
+ Condition cond = TokenKindToSmiCondition(kind);
+ branch->EmitBranchOnCondition(compiler, cond);
+ }
}
@@ -679,11 +734,36 @@
}
+static Condition TokenKindToDoubleCondition(Token::Kind kind) {
+ switch (kind) {
+ case Token::kEQ: return EQ;
+ case Token::kNE: return NE;
+ case Token::kLT: return LT;
+ case Token::kGT: return GT;
+ case Token::kLTE: return LE;
+ case Token::kGTE: return GE;
+ default:
+ UNREACHABLE();
+ return VS;
+ }
+}
+
+
static void EmitDoubleComparisonOp(FlowGraphCompiler* compiler,
const LocationSummary& locs,
Token::Kind kind,
BranchInstr* branch) {
- UNIMPLEMENTED();
+ DRegister left = locs.in(0).fpu_reg();
+ DRegister right = locs.in(1).fpu_reg();
+
+ Condition true_condition = TokenKindToDoubleCondition(kind);
+ if (branch != NULL) {
+ compiler->EmitDoubleCompareBranch(
+ true_condition, left, right, branch);
+ } else {
+ compiler->EmitDoubleCompareBool(
+ true_condition, left, right, locs.out().reg());
+ }
}
@@ -958,13 +1038,21 @@
LocationSummary* StringFromCharCodeInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 1;
+ // TODO(fschneider): Allow immediate operands for the char code.
+ return LocationSummary::Make(kNumInputs,
+ Location::RequiresRegister(),
+ LocationSummary::kNoCall);
}
void StringFromCharCodeInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ Register char_code = locs()->in(0).reg();
+ Register result = locs()->out().reg();
+ __ LoadImmediate(result,
+ reinterpret_cast<uword>(Symbols::PredefinedAddress()));
+ __ AddImmediate(result, Symbols::kNullCharCodeSymbolOffset * kWordSize);
+ __ ldr(result, Address(result, char_code, LSL, 1)); // Char code is a smi.
}
@@ -1135,7 +1223,33 @@
if ((representation() == kUnboxedDouble) ||
(representation() == kUnboxedMint) ||
(representation() == kUnboxedFloat32x4)) {
- UNIMPLEMENTED();
+ DRegister result = locs()->out().fpu_reg();
+ switch (class_id()) {
+ case kTypedDataInt32ArrayCid:
+ UNIMPLEMENTED();
+ break;
+ case kTypedDataUint32ArrayCid:
+ UNIMPLEMENTED();
+ break;
+ case kTypedDataFloat32ArrayCid:
+ // Load single precision float and promote to double.
+ // vldrs does not support indexed addressing.
+ __ add(index.reg(), index.reg(), ShifterOperand(array));
+ element_address = Address(index.reg(), 0);
+ __ vldrs(S0, element_address);
+ __ vcvtds(result, S0);
+ break;
+ case kTypedDataFloat64ArrayCid:
+ // vldrd does not support indexed addressing.
+ __ add(index.reg(), index.reg(), ShifterOperand(array));
+ element_address = Address(index.reg(), 0);
+ __ vldrd(result, element_address);
+ break;
+ case kTypedDataFloat32x4ArrayCid:
+ UNIMPLEMENTED();
+ break;
+ }
+ return;
}
Register result = locs()->out().reg();
@@ -1674,14 +1788,19 @@
LocationSummary*
AllocateObjectWithBoundsCheckInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ return MakeCallSummary();
}
void AllocateObjectWithBoundsCheckInstr::EmitNativeCode(
FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ compiler->GenerateCallRuntime(token_pos(),
+ deopt_id(),
+ kAllocateObjectWithBoundsCheckRuntimeEntry,
+ locs());
+ __ Drop(3);
+ ASSERT(locs()->out().reg() == R0);
+ __ Pop(R0); // Pop new instance.
}
@@ -1856,13 +1975,28 @@
LocationSummary* CloneContextInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* locs =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
+ locs->set_in(0, Location::RegisterLocation(R0));
+ locs->set_out(Location::RegisterLocation(R0));
+ return locs;
}
void CloneContextInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ Register context_value = locs()->in(0).reg();
+ Register result = locs()->out().reg();
+
+ __ PushObject(Object::ZoneHandle()); // Make room for the result.
+ __ Push(context_value);
+ compiler->GenerateCallRuntime(token_pos(),
+ deopt_id(),
+ kCloneContextRuntimeEntry,
+ locs());
+ __ Drop(1); // Remove argument.
+ __ Pop(result); // Get result (cloned context).
}
@@ -2056,20 +2190,29 @@
LocationSummary* BinarySmiOpInstr::MakeLocationSummary() const {
const intptr_t kNumInputs = 2;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
if (op_kind() == Token::kTRUNCDIV) {
- UNIMPLEMENTED();
- return NULL;
- } else {
- const intptr_t kNumTemps = 0;
- LocationSummary* summary =
- new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
- summary->set_in(0, Location::RequiresRegister());
- summary->set_in(1, Location::RegisterOrSmiConstant(right()));
- // We make use of 3-operand instructions by not requiring result register
- // to be identical to first input register as on Intel.
- summary->set_out(Location::RequiresRegister());
+ if (RightIsPowerOfTwoConstant()) {
+ summary->set_in(0, Location::RequiresRegister());
+ ConstantInstr* right_constant = right()->definition()->AsConstant();
+ summary->set_in(1, Location::Constant(right_constant->value()));
+ summary->set_out(Location::RequiresRegister());
+ } else {
+ // Both inputs must be writable because they will be untagged.
+ summary->set_in(0, Location::WritableRegister());
+ summary->set_in(1, Location::WritableRegister());
+ summary->set_out(Location::RequiresRegister());
+ }
return summary;
}
+ summary->set_in(0, Location::RequiresRegister());
+ summary->set_in(1, Location::RegisterOrSmiConstant(right()));
+ // We make use of 3-operand instructions by not requiring result register
+ // to be identical to first input register as on Intel.
+ summary->set_out(Location::RequiresRegister());
+ return summary;
}
@@ -2130,7 +2273,31 @@
break;
}
case Token::kTRUNCDIV: {
- UNIMPLEMENTED();
+ const intptr_t value = Smi::Cast(constant).Value();
+ if (value == 1) {
+ // Do nothing.
+ break;
+ } else if (value == -1) {
+ // Check the corner case of dividing the 'MIN_SMI' with -1, in which
+ // case we cannot negate the result.
+ __ CompareImmediate(left, 0x80000000);
+ __ b(deopt, EQ);
+ __ rsb(result, left, ShifterOperand(0));
+ break;
+ }
+ ASSERT((value != 0) && Utils::IsPowerOfTwo(Utils::Abs(value)));
+ const intptr_t shift_count =
+ Utils::ShiftForPowerOfTwo(Utils::Abs(value)) + kSmiTagSize;
+ ASSERT(kSmiTagSize == 1);
+ __ mov(IP, ShifterOperand(left, ASR, 31));
+ ASSERT(shift_count > 1); // 1, -1 case handled above.
+ __ add(left, left, ShifterOperand(IP, LSR, 32 - shift_count));
+ ASSERT(shift_count > 0);
+ __ mov(result, ShifterOperand(left, ASR, shift_count));
+ if (value < 0) {
+ __ rsb(result, result, ShifterOperand(0));
+ }
+ __ SmiTag(result);
break;
}
case Token::kBIT_AND: {
@@ -2245,7 +2412,20 @@
break;
}
case Token::kTRUNCDIV: {
- UNIMPLEMENTED();
+ // Handle divide by zero in runtime.
+ __ cmp(right, ShifterOperand(0));
+ __ b(deopt, EQ);
+ __ SmiUntag(left);
+ __ SmiUntag(right);
+ if (!CPUFeatures::integer_division_supported()) {
+ UNIMPLEMENTED();
+ }
+ __ sdiv(result, left, right);
+ // Check the corner case of dividing the 'MIN_SMI' with -1, in which
+ // case we cannot tag the result.
+ __ CompareImmediate(result, 0x40000000);
+ __ b(deopt, EQ);
+ __ SmiTag(result);
break;
}
case Token::kSHR: {
@@ -2278,35 +2458,142 @@
LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ intptr_t left_cid = left()->Type()->ToCid();
+ intptr_t right_cid = right()->Type()->ToCid();
+ ASSERT((left_cid != kDoubleCid) && (right_cid != kDoubleCid));
+ const intptr_t kNumInputs = 2;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresRegister());
+ summary->set_in(1, Location::RequiresRegister());
+ return summary;
}
void CheckEitherNonSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ Label* deopt = compiler->AddDeoptStub(deopt_id(), kDeoptBinaryDoubleOp);
+ intptr_t left_cid = left()->Type()->ToCid();
+ intptr_t right_cid = right()->Type()->ToCid();
+ Register left = locs()->in(0).reg();
+ Register right = locs()->in(1).reg();
+ if (left_cid == kSmiCid) {
+ __ tst(right, ShifterOperand(kSmiTagMask));
+ } else if (right_cid == kSmiCid) {
+ __ tst(left, ShifterOperand(kSmiTagMask));
+ } else {
+ __ orr(IP, left, ShifterOperand(right));
+ __ tst(IP, ShifterOperand(kSmiTagMask));
+ }
+ __ b(deopt, EQ);
}
LocationSummary* BoxDoubleInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs,
+ kNumTemps,
+ LocationSummary::kCallOnSlowPath);
+ summary->set_in(0, Location::RequiresFpuRegister());
+ summary->set_out(Location::RequiresRegister());
+ return summary;
}
+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) {
- UNIMPLEMENTED();
+ BoxDoubleSlowPath* slow_path = new BoxDoubleSlowPath(this);
+ compiler->AddSlowPathCode(slow_path);
+
+ Register out_reg = locs()->out().reg();
+ DRegister value = locs()->in(0).fpu_reg();
+
+ __ TryAllocate(compiler->double_class(),
+ slow_path->entry_label(),
+ out_reg);
+ __ Bind(slow_path->exit_label());
+ __ StoreDToOffset(value, out_reg, Double::value_offset() - kHeapObjectTag);
}
LocationSummary* UnboxDoubleInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 1;
+ const intptr_t value_cid = value()->Type()->ToCid();
+ const bool needs_temp = ((value_cid != kSmiCid) && (value_cid != kDoubleCid));
+ const bool needs_writable_input = (value_cid == kSmiCid);
+ const intptr_t kNumTemps = needs_temp ? 1 : 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_in(0, needs_writable_input
+ ? Location::WritableRegister()
+ : Location::RequiresRegister());
+ if (needs_temp) summary->set_temp(0, Location::RequiresRegister());
+ summary->set_out(Location::RequiresFpuRegister());
+ return summary;
}
void UnboxDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ const intptr_t value_cid = value()->Type()->ToCid();
+ const Register value = locs()->in(0).reg();
+ const DRegister result = locs()->out().fpu_reg();
+
+ if (value_cid == kDoubleCid) {
+ __ LoadDFromOffset(result, value, Double::value_offset() - kHeapObjectTag);
+ } else if (value_cid == kSmiCid) {
+ __ SmiUntag(value); // Untag input before conversion.
+ __ vmovsr(S0, value);
+ __ vcvtdi(result, S0);
+ } else {
+ Label* deopt = compiler->AddDeoptStub(deopt_id_, kDeoptBinaryDoubleOp);
+ Register temp = locs()->temp(0).reg();
+ Label is_smi, done;
+ __ tst(value, ShifterOperand(kSmiTagMask));
+ __ b(&is_smi, EQ);
+ __ CompareClassId(value, kDoubleCid, temp);
+ __ b(deopt, NE);
+ __ LoadDFromOffset(result, value, Double::value_offset() - kHeapObjectTag);
+ __ b(&done);
+ __ Bind(&is_smi);
+ // TODO(regis): Why do we preserve value here but not above?
+ __ mov(IP, ShifterOperand(value, ASR, 1)); // Copy and untag.
+ __ vmovsr(S0, IP);
+ __ vcvtdi(result, S0);
+ __ Bind(&done);
+ }
}
@@ -2355,13 +2642,28 @@
LocationSummary* BinaryDoubleOpInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 2;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresFpuRegister());
+ summary->set_in(1, Location::RequiresFpuRegister());
+ summary->set_out(Location::RequiresFpuRegister());
+ return summary;
}
void BinaryDoubleOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ DRegister left = locs()->in(0).fpu_reg();
+ DRegister right = locs()->in(1).fpu_reg();
+ DRegister result = locs()->out().fpu_reg();
+ switch (op_kind()) {
+ case Token::kADD: __ vaddd(result, left, right); break;
+ case Token::kSUB: __ vsubd(result, left, right); break;
+ case Token::kMUL: __ vmuld(result, left, right); break;
+ case Token::kDIV: __ vdivd(result, left, right); break;
+ default: UNREACHABLE();
+ }
}
@@ -2574,79 +2876,213 @@
LocationSummary* MathSqrtInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresFpuRegister());
+ summary->set_out(Location::RequiresFpuRegister());
+ return summary;
}
void MathSqrtInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ __ vsqrtd(locs()->out().fpu_reg(), locs()->in(0).fpu_reg());
}
LocationSummary* UnarySmiOpInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* summary =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ summary->set_in(0, Location::RequiresRegister());
+ // We make use of 3-operand instructions by not requiring result register
+ // to be identical to first input register as on Intel.
+ summary->set_out(Location::RequiresRegister());
+ return summary;
}
void UnarySmiOpInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ Register value = locs()->in(0).reg();
+ Register result = locs()->out().reg();
+ switch (op_kind()) {
+ case Token::kNEGATE: {
+ Label* deopt = compiler->AddDeoptStub(deopt_id(),
+ kDeoptUnaryOp);
+ __ rsbs(result, value, ShifterOperand(0));
+ __ b(deopt, VS);
+ break;
+ }
+ case Token::kBIT_NOT:
+ __ mvn(result, ShifterOperand(value));
+ // Remove inverted smi-tag.
+ __ bic(result, result, ShifterOperand(kSmiTagMask));
+ break;
+ default:
+ UNREACHABLE();
+ }
}
LocationSummary* SmiToDoubleInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* result =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ result->set_in(0, Location::WritableRegister());
+ result->set_out(Location::RequiresFpuRegister());
+ return result;
}
void SmiToDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ Register value = locs()->in(0).reg();
+ FpuRegister result = locs()->out().fpu_reg();
+ __ SmiUntag(value);
+ __ vmovsr(S0, value);
+ __ vcvtdi(result, S0);
}
LocationSummary* DoubleToIntegerInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* result =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kCall);
+ result->set_in(0, Location::RegisterLocation(R1));
+ result->set_out(Location::RegisterLocation(R0));
+ return result;
}
void DoubleToIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ Register result = locs()->out().reg();
+ Register value_obj = locs()->in(0).reg();
+ ASSERT(result == R0);
+ ASSERT(result != value_obj);
+ __ LoadDFromOffset(D0, value_obj, Double::value_offset() - kHeapObjectTag);
+ __ vcvtid(S0, D0);
+ __ vmovrs(result, S0);
+ // Overflow is signaled with minint.
+ Label do_call, done;
+ // Check for overflow and that it fits into Smi.
+ __ CompareImmediate(result, 0xC0000000);
+ __ b(&do_call, MI);
+ __ SmiTag(result);
+ __ b(&done);
+ __ Bind(&do_call);
+ __ Push(value_obj);
+ ASSERT(instance_call()->HasICData());
+ const ICData& ic_data = *instance_call()->ic_data();
+ ASSERT((ic_data.NumberOfChecks() == 1));
+ const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(0));
+
+ const intptr_t kNumberOfArguments = 1;
+ compiler->GenerateStaticCall(deopt_id(),
+ instance_call()->token_pos(),
+ target,
+ kNumberOfArguments,
+ Array::Handle(), // No argument names.,
+ locs());
+ __ Bind(&done);
}
LocationSummary* DoubleToSmiInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* result = new LocationSummary(
+ kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ result->set_in(0, Location::RequiresFpuRegister());
+ result->set_out(Location::RequiresRegister());
+ return result;
}
void DoubleToSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ Label* deopt = compiler->AddDeoptStub(deopt_id(), kDeoptDoubleToSmi);
+ Register result = locs()->out().reg();
+ DRegister value = locs()->in(0).fpu_reg();
+ __ vcvtid(S0, value);
+ __ vmovrs(result, S0);
+ // Check for overflow and that it fits into Smi.
+ __ CompareImmediate(result, 0xC0000000);
+ __ b(deopt, MI);
+ __ SmiTag(result);
}
LocationSummary* DoubleToDoubleInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ const intptr_t kNumInputs = 1;
+ const intptr_t kNumTemps = 0;
+ LocationSummary* result =
+ new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
+ result->set_in(0, Location::RequiresFpuRegister());
+ result->set_out(Location::RequiresFpuRegister());
+ return result;
}
void DoubleToDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ // DRegister value = locs()->in(0).fpu_reg();
+ // DRegister result = locs()->out().fpu_reg();
+ switch (recognized_kind()) {
+ case MethodRecognizer::kDoubleTruncate:
+ UNIMPLEMENTED();
+ // __ roundsd(result, value, Assembler::kRoundToZero);
+ break;
+ case MethodRecognizer::kDoubleFloor:
+ UNIMPLEMENTED();
+ // __ roundsd(result, value, Assembler::kRoundDown);
+ break;
+ case MethodRecognizer::kDoubleCeil:
+ UNIMPLEMENTED();
+ // __ roundsd(result, value, Assembler::kRoundUp);
+ break;
+ default:
+ UNREACHABLE();
+ }
}
LocationSummary* InvokeMathCFunctionInstr::MakeLocationSummary() const {
- UNIMPLEMENTED();
- return NULL;
+ ASSERT((InputCount() == 1) || (InputCount() == 2));
+ const intptr_t kNumTemps = 0;
+ LocationSummary* result =
+ new LocationSummary(InputCount(), kNumTemps, LocationSummary::kCall);
+ result->set_in(0, Location::FpuRegisterLocation(D1));
+ if (InputCount() == 2) {
+ result->set_in(1, Location::FpuRegisterLocation(D2));
+ }
+ result->set_out(Location::FpuRegisterLocation(D1));
+ return result;
}
void InvokeMathCFunctionInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- UNIMPLEMENTED();
+ // For pow-function return NAN if exponent is NAN.
+ Label do_call, skip_call;
+ if (recognized_kind() == MethodRecognizer::kDoublePow) {
+ DRegister exp = locs()->in(1).fpu_reg();
+ __ vcmpd(exp, exp);
+ __ vmstat();
+ __ b(&do_call, VC); // NaN -> false;
+ // Exponent is NaN, return NaN.
+ __ vmovd(locs()->out().fpu_reg(), exp);
+ __ b(&skip_call);
+ }
+ __ Bind(&do_call);
+ // TODO(regis): Using D0 as the reserved scratch value is not a good idea.
+ __ vmovd(D0, locs()->in(0).fpu_reg());
+ if (InputCount() == 2) {
+ __ vmovd(D1, locs()->in(1).fpu_reg());
+ }
+ UNIMPLEMENTED(); // TODO(regis): We need to support double type leaf calls.
+ __ CallRuntime(TargetFunction());
+ __ vmovd(locs()->out().fpu_reg(), D0);
+ __ Bind(&skip_call);
}
diff --git a/runtime/vm/intrinsifier_arm.cc b/runtime/vm/intrinsifier_arm.cc
index 694f64b..2e551ab 100644
--- a/runtime/vm/intrinsifier_arm.cc
+++ b/runtime/vm/intrinsifier_arm.cc
@@ -833,7 +833,6 @@
bool Intrinsifier::Integer_bitXorFromInteger(Assembler* assembler) {
Label fall_through;
- __ Untested("Intrinsifier::Integer_bitXorFromInteger");
TestBothArgumentsSmis(assembler, &fall_through); // checks two smis
__ eor(R0, R0, ShifterOperand(R1));
@@ -1126,12 +1125,10 @@
TestLastArgumentIsDouble(assembler, &is_smi, &fall_through);
// Both arguments are double, right operand is in R0.
- __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
- __ vldrd(D1, Address(R0));
+ __ LoadDFromOffset(D1, R0, Double::value_offset() - kHeapObjectTag);
__ Bind(&double_op);
__ ldr(R0, Address(SP, 1 * kWordSize)); // Left argument.
- __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
- __ vldrd(D0, Address(R0));
+ __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag);
__ vcmpd(D0, D1);
__ vmstat();
@@ -1183,13 +1180,9 @@
TestLastArgumentIsDouble(assembler, &fall_through, &fall_through);
// Both arguments are double, right operand is in R0.
- // Can't use FieldAddress here. R0 is heap-object-tagged, so the offset will
- // not be 4-byte aligned.
- __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
- __ vldrd(D1, Address(R0));
+ __ LoadDFromOffset(D1, R0, Double::value_offset() - kHeapObjectTag);
__ ldr(R0, Address(SP, 1 * kWordSize)); // Left argument.
- __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
- __ vldrd(D0, Address(R0));
+ __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag);
switch (kind) {
case Token::kADD: __ vaddd(D0, D0, D1); break;
case Token::kSUB: __ vsubd(D0, D0, D1); break;
@@ -1200,8 +1193,7 @@
const Class& double_class = Class::Handle(
Isolate::Current()->object_store()->double_class());
__ TryAllocate(double_class, &fall_through, R0); // Result register.
- __ AddImmediate(R1, R0, Double::value_offset() - kHeapObjectTag);
- __ vstrd(D0, Address(R1));
+ __ StoreDToOffset(D0, R0, Double::value_offset() - kHeapObjectTag);
__ Ret();
__ Bind(&fall_through);
return false;
@@ -1231,7 +1223,6 @@
// Left is double right is integer (Bigint, Mint or Smi)
bool Intrinsifier::Double_mulFromInteger(Assembler* assembler) {
Label fall_through;
- __ Untested("Intrinsifier::Double_mulFromInteger");
// Only Smi-s allowed.
__ ldr(R0, Address(SP, 0 * kWordSize));
__ tst(R0, ShifterOperand(kSmiTagMask));
@@ -1241,14 +1232,12 @@
__ vmovsr(S0, R0);
__ vcvtdi(D1, S0);
__ ldr(R0, Address(SP, 1 * kWordSize));
- __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
- __ vldrd(D0, Address(R0));
+ __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag);
__ vmuld(D0, D0, D1);
const Class& double_class = Class::Handle(
Isolate::Current()->object_store()->double_class());
__ TryAllocate(double_class, &fall_through, R0); // Result register.
- __ AddImmediate(R1, R0, Double::value_offset() - kHeapObjectTag);
- __ vstrd(D0, Address(R1));
+ __ StoreDToOffset(D0, R0, Double::value_offset() - kHeapObjectTag);
__ Ret();
__ Bind(&fall_through);
return false;
@@ -1268,8 +1257,7 @@
const Class& double_class = Class::Handle(
Isolate::Current()->object_store()->double_class());
__ TryAllocate(double_class, &fall_through, R0); // Result register.
- __ AddImmediate(R1, R0, Double::value_offset() - kHeapObjectTag);
- __ vstrd(D0, Address(R1));
+ __ StoreDToOffset(D0, R0, Double::value_offset() - kHeapObjectTag);
__ Ret();
__ Bind(&fall_through);
return false;
@@ -1278,14 +1266,12 @@
bool Intrinsifier::Double_getIsNaN(Assembler* assembler) {
Label is_true;
- __ Untested("Intrinsifier::Double_getIsNaN");
__ ldr(R0, Address(SP, 0 * kWordSize));
- __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
- __ vldrd(D0, Address(R0));
+ __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag);
__ vcmpd(D0, D0);
__ vmstat();
- __ LoadObject(R0, Bool::False(), VS);
- __ LoadObject(R0, Bool::True(), VC);
+ __ LoadObject(R0, Bool::False(), VC);
+ __ LoadObject(R0, Bool::True(), VS);
__ Ret();
return true;
}
@@ -1293,10 +1279,8 @@
bool Intrinsifier::Double_getIsNegative(Assembler* assembler) {
Label is_false, is_true, is_zero;
- __ Untested("Intrinsifier::Double_getIsNegative");
__ ldr(R0, Address(SP, 0 * kWordSize));
- __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
- __ vldrd(D0, Address(R0));
+ __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag);
__ LoadDImmediate(D1, 0.0, R1);
__ vcmpd(D0, D1);
__ vmstat();
@@ -1325,8 +1309,7 @@
bool Intrinsifier::Double_toInt(Assembler* assembler) {
__ ldr(R0, Address(SP, 0 * kWordSize));
- __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
- __ vldrd(D0, Address(R0));
+ __ LoadDFromOffset(D0, R0, Double::value_offset() - kHeapObjectTag);
__ vcvtid(S0, D0);
__ vmovrs(R0, S0);
// Overflow is signaled with minint.
@@ -1343,18 +1326,15 @@
bool Intrinsifier::Math_sqrt(Assembler* assembler) {
Label fall_through, is_smi, double_op;
- __ Untested("Intrinsifier::Math_sqrt");
TestLastArgumentIsDouble(assembler, &is_smi, &fall_through);
// Argument is double and is in R0.
- __ AddImmediate(R0, Double::value_offset() - kHeapObjectTag);
- __ vldrd(D1, Address(R0));
+ __ LoadDFromOffset(D1, R0, Double::value_offset() - kHeapObjectTag);
__ Bind(&double_op);
__ vsqrtd(D0, D1);
const Class& double_class = Class::Handle(
Isolate::Current()->object_store()->double_class());
__ TryAllocate(double_class, &fall_through, R0); // Result register.
- __ AddImmediate(R1, R0, Double::value_offset() - kHeapObjectTag);
- __ vstrd(D0, Address(R1));
+ __ StoreDToOffset(D0, R0, Double::value_offset() - kHeapObjectTag);
__ Ret();
__ Bind(&is_smi);
__ SmiUntag(R0);
@@ -1398,8 +1378,6 @@
ASSERT(Utils::IsUint(32, a_int_value));
int32_t a_int32_value = static_cast<int32_t>(a_int_value);
- __ Untested("Random_nextState");
-
__ ldr(R0, Address(SP, 0 * kWordSize)); // Receiver.
__ ldr(R1, FieldAddress(R0, state_field.Offset())); // Field '_state'.
// Addresses of _state[0] and _state[1].
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 4c1a93b..ec65512 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -297,7 +297,7 @@
}
-static void DeleteWeakPersistentHandle(Dart_Handle handle) {
+static void DeleteWeakPersistentHandle(Dart_WeakPersistentHandle handle) {
ApiState* state = Isolate::Current()->api_state();
ASSERT(state != NULL);
FinalizablePersistentHandle* weak_ref =
@@ -322,14 +322,14 @@
Heap* heap = isolate->heap();
// Allocate the read only object handles here.
- empty_array_ = Array::ReadOnlyHandle(isolate);
- sentinel_ = Instance::ReadOnlyHandle(isolate);
- transition_sentinel_ = Instance::ReadOnlyHandle(isolate);
- unknown_constant_ = Instance::ReadOnlyHandle(isolate);
- non_constant_ = Instance::ReadOnlyHandle(isolate);
- bool_true_ = Bool::ReadOnlyHandle(isolate);
- bool_false_ = Bool::ReadOnlyHandle(isolate);
- snapshot_writer_error_ = LanguageError::ReadOnlyHandle(isolate);
+ empty_array_ = Array::ReadOnlyHandle();
+ sentinel_ = Instance::ReadOnlyHandle();
+ transition_sentinel_ = Instance::ReadOnlyHandle();
+ unknown_constant_ = Instance::ReadOnlyHandle();
+ non_constant_ = Instance::ReadOnlyHandle();
+ bool_true_ = Bool::ReadOnlyHandle();
+ bool_false_ = Bool::ReadOnlyHandle();
+ snapshot_writer_error_ = LanguageError::ReadOnlyHandle();
// Allocate and initialize the null instance.
// 'null_' must be the first object allocated as it is used in allocation to
@@ -1578,19 +1578,24 @@
// To work properly, this call requires the super class of this class to be
// resolved, which is checked by the SuperClass() call.
Class& cls = Class::Handle(raw());
- if (IsSignatureClass()) {
- const Function& signature_fun = Function::Handle(signature_function());
- if (!signature_fun.is_static() &&
- !signature_fun.HasInstantiatedSignature()) {
- cls = signature_fun.Owner();
+ intptr_t num_type_args = 0;
+
+ do {
+ if (cls.IsSignatureClass()) {
+ const Function& signature_fun =
+ Function::Handle(cls.signature_function());
+ if (!signature_fun.is_static() &&
+ !signature_fun.HasInstantiatedSignature()) {
+ cls = signature_fun.Owner();
+ }
}
- }
- intptr_t num_type_args = NumTypeParameters();
- cls = cls.SuperClass();
- // Object is its own super class during bootstrap.
- if (!cls.IsNull() && (cls.raw() != raw())) {
- num_type_args += cls.NumTypeArguments();
- }
+ num_type_args += cls.NumTypeParameters();
+ // Object is its own super class during bootstrap.
+ if (cls.SuperClass() == Class::null() || cls.SuperClass() == cls.raw()) {
+ break;
+ }
+ cls = cls.SuperClass();
+ } while (true);
return num_type_args;
}
@@ -5118,7 +5123,7 @@
}
-void TokenStream::DataFinalizer(Dart_Handle handle, void *peer) {
+void TokenStream::DataFinalizer(Dart_WeakPersistentHandle handle, void *peer) {
ASSERT(peer != NULL);
::free(peer);
DeleteWeakPersistentHandle(handle);
@@ -5300,15 +5305,10 @@
RawTokenStream* TokenStream::New() {
ASSERT(Object::token_stream_class() != Class::null());
- TokenStream& result = TokenStream::Handle();
- {
- RawObject* raw = Object::Allocate(TokenStream::kClassId,
- TokenStream::InstanceSize(),
- Heap::kOld);
- NoGCScope no_gc;
- result ^= raw;
- }
- return result.raw();
+ RawObject* raw = Object::Allocate(TokenStream::kClassId,
+ TokenStream::InstanceSize(),
+ Heap::kOld);
+ return reinterpret_cast<RawTokenStream*>(raw);
}
@@ -9234,15 +9234,10 @@
if (cls.EnsureIsFinalized(isolate) != Error::null()) {
return Instance::null();
}
- Instance& result = Instance::Handle(isolate);
- {
- intptr_t instance_size = cls.instance_size();
- ASSERT(instance_size > 0);
- RawObject* raw = Object::Allocate(cls.id(), instance_size, space);
- NoGCScope no_gc;
- result ^= raw;
- }
- return result.raw();
+ intptr_t instance_size = cls.instance_size();
+ ASSERT(instance_size > 0);
+ RawObject* raw = Object::Allocate(cls.id(), instance_size, space);
+ return reinterpret_cast<RawInstance*>(raw);
}
@@ -12337,7 +12332,8 @@
}
-void ExternalOneByteString::Finalize(Dart_Handle handle, void* peer) {
+void ExternalOneByteString::Finalize(Dart_WeakPersistentHandle handle,
+ void* peer) {
delete reinterpret_cast<ExternalStringData<uint8_t>*>(peer);
DeleteWeakPersistentHandle(handle);
}
@@ -12374,7 +12370,8 @@
}
-void ExternalTwoByteString::Finalize(Dart_Handle handle, void* peer) {
+void ExternalTwoByteString::Finalize(Dart_WeakPersistentHandle handle,
+ void* peer) {
delete reinterpret_cast<ExternalStringData<uint16_t>*>(peer);
DeleteWeakPersistentHandle(handle);
}
@@ -13320,15 +13317,10 @@
RawWeakProperty* WeakProperty::New(Heap::Space space) {
ASSERT(Isolate::Current()->object_store()->weak_property_class()
!= Class::null());
- WeakProperty& result = WeakProperty::Handle();
- {
- RawObject* raw = Object::Allocate(WeakProperty::kClassId,
- WeakProperty::InstanceSize(),
- space);
- NoGCScope no_gc;
- result ^= raw;
- }
- return result.raw();
+ RawObject* raw = Object::Allocate(WeakProperty::kClassId,
+ WeakProperty::InstanceSize(),
+ space);
+ return reinterpret_cast<RawWeakProperty*>(raw);
}
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 01b8c78..349542f 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -78,7 +78,7 @@
initializeHandle(obj, raw_ptr); \
return *obj; \
} \
- static object* ReadOnlyHandle(Isolate* isolate) { \
+ static object* ReadOnlyHandle() { \
object* obj = reinterpret_cast<object*>( \
Dart::AllocateReadOnlyHandle()); \
initializeHandle(obj, object::null()); \
@@ -2052,7 +2052,7 @@
void SetPrivateKey(const String& value) const;
static RawTokenStream* New();
- static void DataFinalizer(Dart_Handle handle, void *peer);
+ static void DataFinalizer(Dart_WeakPersistentHandle handle, void *peer);
FINAL_HEAP_OBJECT_IMPLEMENTATION(TokenStream, Object);
friend class Class;
@@ -4753,7 +4753,7 @@
raw_ptr(str)->external_data_ = data;
}
- static void Finalize(Dart_Handle handle, void* peer);
+ static void Finalize(Dart_WeakPersistentHandle handle, void* peer);
static RawExternalOneByteString* ReadFrom(SnapshotReader* reader,
intptr_t object_id,
@@ -4819,7 +4819,7 @@
raw_ptr(str)->external_data_ = data;
}
- static void Finalize(Dart_Handle handle, void* peer);
+ static void Finalize(Dart_WeakPersistentHandle handle, void* peer);
static RawExternalTwoByteString* ReadFrom(SnapshotReader* reader,
intptr_t object_id,
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 303bd75..7659c44 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -116,13 +116,6 @@
}
-LocalVariable* ParsedFunction::CreateArrayLiteralVar(intptr_t token_pos) {
- return new LocalVariable(token_pos,
- Symbols::ArrayLiteralVar(),
- Type::ZoneHandle(Type::ArrayType()));
-}
-
-
void ParsedFunction::SetNodeSequence(SequenceNode* node_sequence) {
ASSERT(node_sequence_ == NULL);
ASSERT(node_sequence != NULL);
@@ -788,10 +781,6 @@
UNREACHABLE();
}
- parsed_function->set_array_literal_var(
- ParsedFunction::CreateArrayLiteralVar(func.token_pos()));
- node_sequence->scope()->AddVariable(parsed_function->array_literal_var());
-
if (!HasReturnNode(node_sequence)) {
// Add implicit return node.
node_sequence->Add(new ReturnNode(func.end_token_pos()));
@@ -1409,18 +1398,6 @@
}
-LocalVariable* Parser::BuildArrayTempLocal(intptr_t token_pos) {
- char name[64];
- OS::SNPrint(name, 64, ":arrlit%"Pd, token_pos);
- LocalVariable* temp =
- new LocalVariable(token_pos,
- String::ZoneHandle(Symbols::New(name)),
- Type::ZoneHandle(Type::ArrayType()));
- current_block_->scope->AddVariable(temp);
- return temp;
-}
-
-
StaticCallNode* Parser::BuildInvocationMirrorAllocation(
intptr_t call_pos,
const String& function_name,
@@ -1438,9 +1415,8 @@
arguments->Add(new LiteralNode(args_pos, args_descriptor));
// The third argument is an array containing the original function arguments,
// including the receiver.
- ArrayNode* args_array = new ArrayNode(
- args_pos, Type::ZoneHandle(Type::ArrayType()),
- *BuildArrayTempLocal(call_pos));
+ ArrayNode* args_array =
+ new ArrayNode(args_pos, Type::ZoneHandle(Type::ArrayType()));
for (intptr_t i = 0; i < function_args.length(); i++) {
args_array->AddElement(function_args.NodeAt(i));
}
@@ -7028,71 +7004,42 @@
}
-// A compound assignment consists of a store and a load part. In order
-// to control inputs with potential side effects, the store part stores any
-// side effect creating inputs into locals. The load part reads then from
-// those locals. If expr may have side effects, it will be split into two new
-// left and right nodes. 'expr' becomes the right node, left node is returned as
-// result.
-AstNode* Parser::PrepareCompoundAssignmentNodes(AstNode** expr) {
+LetNode* Parser::PrepareCompoundAssignmentNodes(AstNode** expr) {
AstNode* node = *expr;
+ intptr_t token_pos = node->token_pos();
+ LetNode* result = new LetNode(token_pos);
if (node->IsLoadIndexedNode()) {
- LoadIndexedNode* left_node = node->AsLoadIndexedNode();
- LoadIndexedNode* right_node = left_node;
- intptr_t token_pos = node->token_pos();
- node = NULL; // Do not use it.
- if (!IsSimpleLocalOrLiteralNode(left_node->array())) {
- LocalVariable* temp =
- CreateTempConstVariable(token_pos, "lia");
- StoreLocalNode* save =
- new StoreLocalNode(token_pos, temp, left_node->array());
- left_node = new LoadIndexedNode(token_pos,
- save,
- left_node->index_expr(),
- left_node->super_class());
- right_node = new LoadIndexedNode(token_pos,
- new LoadLocalNode(token_pos, temp),
- right_node->index_expr(),
- right_node->super_class());
+ LoadIndexedNode* load_indexed = node->AsLoadIndexedNode();
+ AstNode* array = load_indexed->array();
+ AstNode* index = load_indexed->index_expr();
+ if (!IsSimpleLocalOrLiteralNode(load_indexed->array())) {
+ LocalVariable* t0 = result->AddInitializer(load_indexed->array());
+ array = new LoadLocalNode(token_pos, t0);
}
- if (!IsSimpleLocalOrLiteralNode(left_node->index_expr())) {
- LocalVariable* temp =
- CreateTempConstVariable(token_pos, "lix");
- StoreLocalNode* save =
- new StoreLocalNode(token_pos, temp, left_node->index_expr());
- left_node = new LoadIndexedNode(token_pos,
- left_node->array(),
- save,
- left_node->super_class());
- right_node = new LoadIndexedNode(token_pos,
- right_node->array(),
- new LoadLocalNode(token_pos, temp),
- right_node->super_class());
+ if (!IsSimpleLocalOrLiteralNode(load_indexed->index_expr())) {
+ LocalVariable* t1 = result->AddInitializer(
+ load_indexed->index_expr());
+ index = new LoadLocalNode(token_pos, t1);
}
- *expr = right_node;
- return left_node;
+ *expr = new LoadIndexedNode(token_pos,
+ array,
+ index,
+ load_indexed->super_class());
+ return result;
}
if (node->IsInstanceGetterNode()) {
- InstanceGetterNode* left_node = node->AsInstanceGetterNode();
- InstanceGetterNode* right_node = left_node;
- intptr_t token_pos = node->token_pos();
- node = NULL; // Do not use it.
- if (!IsSimpleLocalOrLiteralNode(left_node->receiver())) {
- LocalVariable* temp =
- CreateTempConstVariable(token_pos, "igr");
- StoreLocalNode* save =
- new StoreLocalNode(token_pos, temp, left_node->receiver());
- left_node = new InstanceGetterNode(token_pos,
- save,
- left_node->field_name());
- right_node = new InstanceGetterNode(token_pos,
- new LoadLocalNode(token_pos, temp),
- right_node->field_name());
+ InstanceGetterNode* getter = node->AsInstanceGetterNode();
+ AstNode* receiver = getter->receiver();
+ if (!IsSimpleLocalOrLiteralNode(getter->receiver())) {
+ LocalVariable* t0 = result->AddInitializer(getter->receiver());
+ receiver = new LoadLocalNode(token_pos, t0);
}
- *expr = right_node;
- return left_node;
+ *expr = new InstanceGetterNode(token_pos,
+ receiver,
+ getter->field_name());
+ return result;
}
- return *expr;
+ return result;
}
@@ -7123,12 +7070,12 @@
AstNode* Parser::ParseCascades(AstNode* expr) {
intptr_t cascade_pos = TokenPos();
- LocalVariable* cascade_receiver_var =
- CreateTempConstVariable(cascade_pos, "casc");
+ LetNode* result = new LetNode(cascade_pos);
+ LocalVariable* cascade_receiver_var = result->AddInitializer(expr);
+ // TODO(fschneider): Make LetNode support more than one body node and
+ // replace the SequenceNode here and CommaNode here and in postfix
+ // expressions.
SequenceNode* cascade = new SequenceNode(cascade_pos, NULL);
- StoreLocalNode* save_cascade =
- new StoreLocalNode(cascade_pos, cascade_receiver_var, expr);
- cascade->Add(save_cascade);
while (CurrentToken() == Token::kCASCADE) {
cascade_pos = TokenPos();
LoadLocalNode* load_cascade_receiver =
@@ -7150,30 +7097,42 @@
const intptr_t assignment_pos = TokenPos();
ConsumeToken();
AstNode* right_expr = ParseExpr(kAllowConst, kNoCascades);
- AstNode* left_expr = expr;
if (assignment_op != Token::kASSIGN) {
// Compound assignment: store inputs with side effects into
// temporary locals.
- left_expr = PrepareCompoundAssignmentNodes(&expr);
+ LetNode* let_expr = PrepareCompoundAssignmentNodes(&expr);
+ right_expr =
+ ExpandAssignableOp(assignment_pos, assignment_op, expr, right_expr);
+ AstNode* assign_expr = CreateAssignmentNode(expr, right_expr);
+ if (assign_expr == NULL) {
+ ErrorMsg(assignment_pos,
+ "left hand side of '%s' is not assignable",
+ Token::Str(assignment_op));
+ }
+ let_expr->set_body(assign_expr);
+ expr = let_expr;
+ } else {
+ right_expr =
+ ExpandAssignableOp(assignment_pos, assignment_op, expr, right_expr);
+ AstNode* assign_expr = CreateAssignmentNode(expr, right_expr);
+ if (assign_expr == NULL) {
+ ErrorMsg(assignment_pos,
+ "left hand side of '%s' is not assignable",
+ Token::Str(assignment_op));
+ }
+ expr = assign_expr;
}
- right_expr =
- ExpandAssignableOp(assignment_pos, assignment_op, expr, right_expr);
- AstNode* assign_expr = CreateAssignmentNode(left_expr, right_expr);
- if (assign_expr == NULL) {
- ErrorMsg(assignment_pos,
- "left hand side of '%s' is not assignable",
- Token::Str(assignment_op));
- }
- expr = assign_expr;
}
cascade->Add(expr);
}
// The result is a pair of the (side effects of the) cascade sequence
// followed by the (value of the) receiver temp variable load.
- return new CommaNode(
+ CommaNode* body = new CommaNode(
cascade_pos,
cascade,
new LoadLocalNode(cascade_pos, cascade_receiver_var));
+ result->set_body(body);
+ return result;
}
@@ -7207,20 +7166,30 @@
ErrorMsg(right_expr_pos, "expression must be a compile-time constant");
}
AstNode* right_expr = ParseExpr(require_compiletime_const, consume_cascades);
- AstNode* left_expr = expr;
if (assignment_op != Token::kASSIGN) {
// Compound assignment: store inputs with side effects into temp. locals.
- left_expr = PrepareCompoundAssignmentNodes(&expr);
+ LetNode* let_expr = PrepareCompoundAssignmentNodes(&expr);
+ AstNode* assigned_value =
+ ExpandAssignableOp(assignment_pos, assignment_op, expr, right_expr);
+ AstNode* assign_expr = CreateAssignmentNode(expr, assigned_value);
+ if (assign_expr == NULL) {
+ ErrorMsg(assignment_pos,
+ "left hand side of '%s' is not assignable",
+ Token::Str(assignment_op));
+ }
+ let_expr->set_body(assign_expr);
+ return let_expr;
+ } else {
+ AstNode* assigned_value =
+ ExpandAssignableOp(assignment_pos, assignment_op, expr, right_expr);
+ AstNode* assign_expr = CreateAssignmentNode(expr, assigned_value);
+ if (assign_expr == NULL) {
+ ErrorMsg(assignment_pos,
+ "left hand side of '%s' is not assignable",
+ Token::Str(assignment_op));
+ }
+ return assign_expr;
}
- right_expr =
- ExpandAssignableOp(assignment_pos, assignment_op, expr, right_expr);
- AstNode* assign_expr = CreateAssignmentNode(left_expr, right_expr);
- if (assign_expr == NULL) {
- ErrorMsg(assignment_pos,
- "left hand side of '%s' is not assignable",
- Token::Str(assignment_op));
- }
- return assign_expr;
}
@@ -7278,7 +7247,7 @@
ErrorMsg("expression is not assignable");
}
// Is prefix.
- AstNode* left_expr = PrepareCompoundAssignmentNodes(&expr);
+ LetNode* let_expr = PrepareCompoundAssignmentNodes(&expr);
Token::Kind binary_op =
(incr_op == Token::kINCR) ? Token::kADD : Token::kSUB;
BinaryOpNode* add = new BinaryOpNode(
@@ -7286,9 +7255,10 @@
binary_op,
expr,
new LiteralNode(op_pos, Smi::ZoneHandle(Smi::New(1))));
- AstNode* store = CreateAssignmentNode(left_expr, add);
+ AstNode* store = CreateAssignmentNode(expr, add);
ASSERT(store != NULL);
- expr = store;
+ let_expr->set_body(store);
+ expr = let_expr;
} else {
expr = ParsePostfixExpr();
}
@@ -7770,24 +7740,24 @@
}
ConsumeToken();
// Not prefix.
- AstNode* left_expr = PrepareCompoundAssignmentNodes(&postfix_expr);
- const LocalVariable* temp = GetIncrementTempLocal();
- AstNode* save =
- new StoreLocalNode(postfix_expr_pos, temp, postfix_expr);
+ LetNode* let_expr = PrepareCompoundAssignmentNodes(&postfix_expr);
+ LocalVariable* temp = let_expr->AddInitializer(postfix_expr);
Token::Kind binary_op =
(incr_op == Token::kINCR) ? Token::kADD : Token::kSUB;
BinaryOpNode* add = new BinaryOpNode(
postfix_expr_pos,
binary_op,
- save,
+ new LoadLocalNode(postfix_expr_pos, temp),
new LiteralNode(postfix_expr_pos, Smi::ZoneHandle(Smi::New(1))));
- AstNode* store = CreateAssignmentNode(left_expr, add);
+ AstNode* store = CreateAssignmentNode(postfix_expr, add);
+ ASSERT(store != NULL);
// The result is a pair of the (side effects of the) store followed by
// the (value of the) initial value temp variable load.
- return new CommaNode(
+ let_expr->set_body(new CommaNode(
postfix_expr_pos,
store,
- new LoadLocalNode(postfix_expr_pos, temp));
+ new LoadLocalNode(postfix_expr_pos, temp)));
+ return let_expr;
}
return postfix_expr;
}
@@ -8118,6 +8088,10 @@
if (const_value.IsError()) {
const Error& error = Error::Cast(const_value);
if (error.IsUnhandledException()) {
+ // 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);
field.set_value(Instance::Handle());
// It is a compile-time error if evaluation of a compile-time constant
// would raise an exception.
@@ -8181,6 +8155,10 @@
arg_values,
arg_descriptor));
if (result.IsError()) {
+ // 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);
if (result.IsUnhandledException()) {
return result.raw();
} else {
@@ -8862,9 +8840,7 @@
new LiteralNode(TokenPos(), empty_array);
factory_param->Add(empty_array_literal);
} else {
- const LocalVariable& temp_local = *BuildArrayTempLocal(type_pos);
- ArrayNode* list =
- new ArrayNode(TokenPos(), type, temp_local, element_list);
+ ArrayNode* list = new ArrayNode(TokenPos(), type, element_list);
factory_param->Add(list);
}
return CreateConstructorCallNode(literal_pos,
@@ -8883,13 +8859,10 @@
if (!type_arguments.IsNull() && !type_arguments.IsInstantiated()) {
EnsureExpressionTemp();
}
- LocalVariable* allocated =
- CreateTempConstVariable(token_pos, "alloc");
return new ConstructorCallNode(token_pos,
type_arguments,
constructor,
- arguments,
- allocated);
+ arguments);
}
@@ -9087,7 +9060,6 @@
ArrayNode* kv_pairs = new ArrayNode(
TokenPos(),
Type::ZoneHandle(Type::ArrayType()),
- *BuildArrayTempLocal(type_pos),
kv_pairs_list);
factory_param->Add(kv_pairs);
return CreateConstructorCallNode(literal_pos,
@@ -9474,7 +9446,6 @@
ArrayNode* values = new ArrayNode(
TokenPos(),
Type::ZoneHandle(Type::ArrayType()),
- *BuildArrayTempLocal(TokenPos()),
values_list);
interpolate_arg->Add(values);
primary = MakeStaticCall(Symbols::StringBase(),
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index b7310eb..e7431a1 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -39,7 +39,6 @@
saved_current_context_var_(NULL),
saved_entry_context_var_(NULL),
expression_temp_var_(NULL),
- array_literal_var_(NULL),
first_parameter_index_(0),
first_stack_local_index_(0),
num_copied_params_(0),
@@ -102,17 +101,6 @@
}
static LocalVariable* CreateExpressionTempVar(intptr_t token_pos);
- void set_array_literal_var(LocalVariable* local) {
- ASSERT((local != NULL) && (array_literal_var_ == NULL));
- array_literal_var_ = local;
- }
- LocalVariable* array_literal_var() const {
- ASSERT(array_literal_var_ != NULL);
- return array_literal_var_;
- }
-
- static LocalVariable* CreateArrayLiteralVar(intptr_t token_pos);
-
int first_parameter_index() const { return first_parameter_index_; }
int first_stack_local_index() const { return first_stack_local_index_; }
int num_copied_params() const { return num_copied_params_; }
@@ -128,9 +116,6 @@
LocalVariable* saved_current_context_var_;
LocalVariable* saved_entry_context_var_;
LocalVariable* expression_temp_var_;
- // TODO(hausner): Remove once ArrayNode creation is removed from flow
- // graph builder.
- LocalVariable* array_literal_var_;
int first_parameter_index_;
int first_stack_local_index_;
@@ -600,7 +585,7 @@
Token::Kind assignment_op,
AstNode* lhs,
AstNode* rhs);
- AstNode* PrepareCompoundAssignmentNodes(AstNode** expr);
+ LetNode* PrepareCompoundAssignmentNodes(AstNode** expr);
LocalVariable* CreateTempConstVariable(intptr_t token_pos, const char* s);
static bool IsAssignableExpr(AstNode* expr);
@@ -636,8 +621,6 @@
const Function& constructor,
ArgumentListNode* arguments);
- LocalVariable* BuildArrayTempLocal(intptr_t token_pos);
-
Script& script_;
TokenStream::Iterator tokens_iterator_;
Token::Kind token_kind_; // Cached token kind for current token.
diff --git a/runtime/vm/scopes.h b/runtime/vm/scopes.h
index 4b0fd2a..fa95e9d 100644
--- a/runtime/vm/scopes.h
+++ b/runtime/vm/scopes.h
@@ -32,7 +32,7 @@
is_final_(false),
is_captured_(false),
is_invisible_(false),
- index_(LocalVariable::kUnitializedIndex) {
+ index_(LocalVariable::kUninitializedIndex) {
ASSERT(type.IsZoneHandle());
ASSERT(type.IsFinalized());
}
@@ -54,7 +54,7 @@
void set_is_captured() { is_captured_ = true; }
bool HasIndex() const {
- return index_ != kUnitializedIndex;
+ return index_ != kUninitializedIndex;
}
int index() const {
ASSERT(HasIndex());
@@ -63,8 +63,7 @@
// Assign an index to a local.
void set_index(int index) {
- ASSERT(!HasIndex());
- ASSERT(index != kUnitializedIndex);
+ ASSERT(index != kUninitializedIndex);
index_ = index;
}
@@ -95,7 +94,7 @@
int BitIndexIn(intptr_t var_count) const;
private:
- static const int kUnitializedIndex = INT_MIN;
+ static const int kUninitializedIndex = INT_MIN;
const intptr_t token_pos_;
const String& name_;
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index 3542587..14442b8 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -2826,14 +2826,6 @@
UnimplementedInstruction(instr);
}
}
- } else if (instr->IsMrcIdIsar0()) {
- // mrc of ID_ISAR0.
- Register rd = instr->RdField();
- if (CPUFeatures::integer_division_supported()) {
- set_register(rd, 0x02100010); // sim has sdiv, udiv, bkpt and clz.
- } else {
- set_register(rd, 0x00100010); // simulator has only bkpt and clz.
- }
} else {
UnimplementedInstruction(instr);
}
diff --git a/runtime/vm/symbols.cc b/runtime/vm/symbols.cc
index a8d4cae..d35b1c1 100644
--- a/runtime/vm/symbols.cc
+++ b/runtime/vm/symbols.cc
@@ -65,7 +65,7 @@
// The symbol_table needs to be reloaded as it might have grown in the
// previous iteration.
symbol_table = object_store->symbol_table();
- String* str = String::ReadOnlyHandle(isolate);
+ String* str = String::ReadOnlyHandle();
*str = OneByteString::New(names[i], Heap::kOld);
Add(symbol_table, *str);
symbol_handles_[i] = str;
@@ -81,7 +81,7 @@
ASSERT(idx < kMaxPredefinedId);
ASSERT(Utf::IsLatin1(c));
uint8_t ch = static_cast<uint8_t>(c);
- String* str = String::ReadOnlyHandle(isolate);
+ String* str = String::ReadOnlyHandle();
*str = OneByteString::New(&ch, 1, Heap::kOld);
Add(symbol_table, *str);
predefined_[c] = str->raw();
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 6bc6f34..741a96f 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -58,7 +58,6 @@
V(SavedTryContextVar, ":saved_try_context_var") \
V(ExceptionVar, ":exception_var") \
V(StacktraceVar, ":stacktrace_var") \
- V(ArrayLiteralVar, ":array_literal_var") \
V(ListLiteralElement, "list literal element") \
V(ForInIter, ":for-in-iter") \
V(Library, "library") \
diff --git a/runtime/vm/unit_test.cc b/runtime/vm/unit_test.cc
index bbde54f..a91a7e1 100644
--- a/runtime/vm/unit_test.cc
+++ b/runtime/vm/unit_test.cc
@@ -139,7 +139,7 @@
if (tag == kCanonicalizeUrl) {
return url;
}
- return Api::Success(Isolate::Current());
+ return Api::Success();
}
diff --git a/sdk/bin/dart b/sdk/bin/dart
index 22abed8..43855cb 100755
--- a/sdk/bin/dart
+++ b/sdk/bin/dart
@@ -12,11 +12,11 @@
DART_CONFIGURATION="ReleaseIA32"
fi
-if [[ `uname` == 'Darwin' ]];
+if [[ `uname` == 'Darwin' ]];
then
- BIN_DIR="$CUR_DIR"/../../xcodebuild/$DART_CONFIGURATION
+ BIN_DIR="$CUR_DIR"/../../xcodebuild/$DART_CONFIGURATION/dart-sdk/bin
else
- BIN_DIR="$CUR_DIR"/../../out/$DART_CONFIGURATION
-fi
+ BIN_DIR="$CUR_DIR"/../../out/$DART_CONFIGURATION/dart-sdk/bin
+fi
exec "$BIN_DIR"/dart "$@"
diff --git a/sdk/bin/dart2js b/sdk/bin/dart2js
index 96354ca..2baaba7 100755
--- a/sdk/bin/dart2js
+++ b/sdk/bin/dart2js
@@ -41,9 +41,6 @@
declare -a EXTRA_VM_OPTIONS
if test -f "$SNAPSHOT"; then
- # TODO(ahe): Remove the following line when we are relatively sure it works.
- echo Using snapshot "$SNAPSHOT" 1>&2
-
EXTRA_OPTIONS[${#EXTRA_OPTIONS[@]}]="--library-root=$SDK_DIR"
fi
diff --git a/sdk/bin/dart2js.bat b/sdk/bin/dart2js.bat
index be0219f..aa6efb7 100644
--- a/sdk/bin/dart2js.bat
+++ b/sdk/bin/dart2js.bat
@@ -29,7 +29,6 @@
)
if exist "%SNAPSHOT%" (
- echo Using snapshot "%SNAPSHOT%" >&2
set EXTRA_OPTIONS=%EXTRA_OPTIONS% "--library-root=%SDK_DIR%"
)
diff --git a/sdk/bin/pub b/sdk/bin/pub
index 76085ab..19acaa3 100755
--- a/sdk/bin/pub
+++ b/sdk/bin/pub
@@ -1,11 +1,46 @@
#!/bin/bash
-# Run pub.dart on the Dart VM. This script assumes the Dart SDK's directory
-# structure.
+# 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.
-# Setting BIN_DIR this way is ugly, but is needed to handle the case where
-# dart-sdk/bin has been symlinked to. On MacOS, readlink doesn't work
-# with this case.
-BIN_DIR="$(cd "${0%/*}" ; pwd -P)"
-DART_SDK="$(cd "${BIN_DIR%/*}" ; pwd -P)"
+function follow_links() {
+ while [ -h "$1" ]; do
+ # On Mac OS, readlink -f doesn't work.
+ 1="$(readlink "$1")"
+ done
+ echo "$1"
+}
-exec "$BIN_DIR"/dart "$DART_SDK"/bin/snapshots/pub.dart.snapshot $@
+# Unlike $0, $BASH_SOURCE points to the absolute path of this file.
+PROG_NAME="$(follow_links "$BASH_SOURCE")"
+
+# Handle the case where dart-sdk/bin has been symlinked to.
+BIN_DIR="$(follow_links "$(cd "${PROG_NAME%/*}" ; pwd -P)")"
+
+SDK_DIR="$(cd "${BIN_DIR}/.." ; pwd -P)"
+
+DART="$BIN_DIR/dart"
+
+SNAPSHOT="$BIN_DIR/snapshots/pub.dart.snapshot"
+
+if test -f "$SNAPSHOT"; then
+ # We are running the snapshot in the built SDK.
+ exec "$DART" "--checked" "$SNAPSHOT" "$@"
+else
+ # We are running pub from source in the development repo.
+ if [ -z "$DART_CONFIGURATION" ];
+ then
+ DART_CONFIGURATION="ReleaseIA32"
+ fi
+
+ if [[ `uname` == 'Darwin' ]];
+ then
+ PACKAGES_DIR="$SDK_DIR"/../xcodebuild/$DART_CONFIGURATION/packages/
+ else
+ PACKAGES_DIR="$SDK_DIR"/../out/$DART_CONFIGURATION/packages/
+ fi
+
+ PUB="$SDK_DIR/lib/_internal/pub/bin/pub.dart"
+
+ exec "$DART" "--checked" "--package-root=$PACKAGES_DIR" "$PUB" "$@"
+fi
diff --git a/sdk/lib/_internal/compiler/implementation/apiimpl.dart b/sdk/lib/_internal/compiler/implementation/apiimpl.dart
index c582bc0..067417a 100644
--- a/sdk/lib/_internal/compiler/implementation/apiimpl.dart
+++ b/sdk/lib/_internal/compiler/implementation/apiimpl.dart
@@ -59,6 +59,8 @@
preserveComments: hasOption(options, '--preserve-comments'),
verbose: hasOption(options, '--verbose'),
sourceMapUri: extractSourceMapUri(options),
+ globalJsName: extractStringOption(
+ options, '--global-js-name=', r'$'),
buildId: extractStringOption(
options, '--build-id=',
"build number could not be determined")) {
diff --git a/sdk/lib/_internal/compiler/implementation/closure.dart b/sdk/lib/_internal/compiler/implementation/closure.dart
index b1d62ca..35b227e 100644
--- a/sdk/lib/_internal/compiler/implementation/closure.dart
+++ b/sdk/lib/_internal/compiler/implementation/closure.dart
@@ -112,8 +112,11 @@
// classes (since the emitter sorts classes by their id).
compiler.getNextFreeClassId(),
STATE_DONE) {
- compiler.closureClass.ensureResolved(compiler);
- supertype = compiler.closureClass.computeType(compiler);
+ ClassElement superclass = methodElement.isInstanceMember()
+ ? compiler.boundClosureClass
+ : compiler.closureClass;
+ superclass.ensureResolved(compiler);
+ supertype = superclass.computeType(compiler);
interfaces = const Link<DartType>();
allSupertypes = const Link<DartType>().prepend(supertype);
thisType = rawType = new InterfaceType(this);
diff --git a/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart b/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
index 47b66c2..7a31f2e 100644
--- a/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
+++ b/sdk/lib/_internal/compiler/implementation/compile_time_constants.dart
@@ -62,11 +62,13 @@
void registerStaticUse(Element element) {
if (isMetadata) return;
+ compiler.analyzeElement(element.declaration);
compiler.enqueuer.codegen.registerStaticUse(element);
}
void registerGetOfStaticFunction(FunctionElement element) {
if (isMetadata) return;
+ compiler.analyzeElement(element.declaration);
compiler.enqueuer.codegen.registerGetOfStaticFunction(element);
}
@@ -124,7 +126,7 @@
return result;
}
return compiler.withCurrentElement(element, () {
- TreeElements definitions = compiler.analyzeElement(element);
+ TreeElements definitions = compiler.analyzeElement(element.declaration);
Constant constant = compileVariableWithDefinitions(
element, definitions, isConst: isConst);
return constant;
@@ -645,6 +647,10 @@
Send send = node.send;
FunctionElement constructor = elements[send];
+ // TODO(ahe): This is nasty: we must eagerly analyze the
+ // constructor to ensure the redirectionTarget has been computed
+ // correctly. Find a way to avoid this.
+ compiler.analyzeElement(constructor.declaration);
constructor = constructor.redirectionTarget;
ClassElement classElement = constructor.getEnclosingClass();
// The constructor must be an implementation to ensure that field
diff --git a/sdk/lib/_internal/compiler/implementation/compiler.dart b/sdk/lib/_internal/compiler/implementation/compiler.dart
index f14543f..be0fc84 100644
--- a/sdk/lib/_internal/compiler/implementation/compiler.dart
+++ b/sdk/lib/_internal/compiler/implementation/compiler.dart
@@ -286,6 +286,12 @@
*/
final Uri sourceMapUri;
+ /**
+ * The name to use for the global JS object in JS output. Default
+ * value is "$".
+ */
+ final String globalJsName;
+
final api.CompilerOutputProvider outputProvider;
bool disableInlining = false;
@@ -306,6 +312,7 @@
ClassElement objectClass;
ClassElement closureClass;
+ ClassElement boundClosureClass;
ClassElement dynamicClass;
ClassElement boolClass;
ClassElement numClass;
@@ -412,6 +419,9 @@
static const SourceString START_ROOT_ISOLATE =
const SourceString('startRootIsolate');
+ static const String UNDETERMINED_BUILD_ID =
+ "build number could not be determined";
+
final Selector iteratorSelector =
new Selector.getter(const SourceString('iterator'), null);
final Selector currentSelector =
@@ -459,15 +469,15 @@
this.preserveComments: false,
this.verbose: false,
this.sourceMapUri: null,
- this.buildId: "build number could not be determined",
+ this.buildId: UNDETERMINED_BUILD_ID,
+ this.globalJsName: r'$',
outputProvider,
List<String> strips: const []})
: this.analyzeOnly = analyzeOnly || analyzeSignaturesOnly,
this.analyzeSignaturesOnly = analyzeSignaturesOnly,
- this.outputProvider =
- (outputProvider == null) ? NullSink.outputProvider : outputProvider
-
- {
+ this.outputProvider = (outputProvider == null)
+ ? NullSink.outputProvider
+ : outputProvider {
world = new World(this);
closureMapping.ClosureNamer closureNamer;
@@ -508,6 +518,8 @@
Universe get resolverWorld => enqueuer.resolution.universe;
Universe get codegenWorld => enqueuer.codegen.universe;
+ bool get hasBuildId => buildId != UNDETERMINED_BUILD_ID;
+
int getNextFreeClassId() => nextFreeClassId++;
void ensure(bool condition) {
@@ -643,6 +655,7 @@
}
if (uri == Uri.parse('dart:mirrors')) {
mirrorSystemClass = library.find(const SourceString('MirrorSystem'));
+ metadataHandler = constantHandler;
} else if (uri == Uri.parse('dart:_collection-dev')) {
symbolImplementationClass = library.find(const SourceString('Symbol'));
}
@@ -702,6 +715,7 @@
return result;
}
jsInvocationMirrorClass = lookupHelperClass('JSInvocationMirror');
+ boundClosureClass = lookupHelperClass('BoundClosure');
closureClass = lookupHelperClass('Closure');
dynamicClass = lookupHelperClass('Dynamic_');
nullClass = lookupHelperClass('Null');
@@ -822,6 +836,7 @@
// Elements required by enqueueHelpers are global dependencies
// that are not pulled in by a particular element.
backend.enqueueHelpers(enqueuer.resolution, globalDependencies);
+ resolveReflectiveDataIfNeeded();
processQueue(enqueuer.resolution, main);
enqueuer.resolution.logSummary(log);
@@ -864,8 +879,19 @@
checkQueues();
}
+ void resolveReflectiveDataIfNeeded() {
+ // Only need reflective data when dart:mirrors is loaded.
+ if (mirrorSystemClass == null) return;
+
+ for (LibraryElement library in libraries.values) {
+ for (Link link = library.metadata; !link.isEmpty; link = link.tail) {
+ link.head.ensureResolved(this);
+ }
+ }
+ }
+
void fullyEnqueueLibrary(LibraryElement library) {
- library.forEachLocalMember(fullyEnqueueTopLevelElement);
+ library.implementation.forEachLocalMember(fullyEnqueueTopLevelElement);
}
void fullyEnqueueTopLevelElement(Element element) {
@@ -948,7 +974,8 @@
TreeElements analyzeElement(Element element) {
assert(invariant(element, element.isDeclaration));
assert(!element.isForwardingConstructor);
- TreeElements elements = enqueuer.resolution.getCachedElements(element);
+ ResolutionEnqueuer world = enqueuer.resolution;
+ TreeElements elements = world.getCachedElements(element);
if (elements != null) return elements;
assert(parser != null);
Node tree = parser.parse(element);
@@ -956,8 +983,9 @@
elements = resolver.resolve(element);
if (elements != null && !analyzeSignaturesOnly) {
// Only analyze nodes with a corresponding [TreeElements].
- checker.check(tree, elements);
+ checker.check(elements);
}
+ world.resolvedElements[element] = elements;
return elements;
}
@@ -978,8 +1006,6 @@
TreeElements result = world.getCachedElements(element);
if (result != null) return result;
result = analyzeElement(element);
- assert(invariant(element, element.isDeclaration));
- world.resolvedElements[element] = result;
return result;
}
diff --git a/sdk/lib/_internal/compiler/implementation/dart2js.dart b/sdk/lib/_internal/compiler/implementation/dart2js.dart
index 8d3c7da..96c5ff1 100644
--- a/sdk/lib/_internal/compiler/implementation/dart2js.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart2js.dart
@@ -29,13 +29,19 @@
*/
String BUILD_ID = null;
-typedef void HandleOption(String option);
+/**
+ * The data passed to the [HandleOption] callback is either a single
+ * string argument, or the arguments iterator for multiple arguments
+ * handlers.
+ */
+typedef void HandleOption(data);
class OptionHandler {
- String pattern;
- HandleOption handle;
+ final String pattern;
+ final HandleOption handle;
+ final bool multipleArguments;
- OptionHandler(this.pattern, this.handle);
+ OptionHandler(this.pattern, this.handle, {this.multipleArguments: false});
}
/**
@@ -64,12 +70,20 @@
patterns.add(handler.pattern);
}
var pattern = new RegExp('^(${patterns.join(")\$|(")})\$');
- OUTER: for (String argument in argv) {
+
+ Iterator<String> arguments = argv.iterator;
+ OUTER: while (arguments.moveNext()) {
+ String argument = arguments.current;
Match match = pattern.firstMatch(argument);
assert(match.groupCount == handlers.length);
for (int i = 0; i < handlers.length; i++) {
if (match[i + 1] != null) {
- handlers[i].handle(argument);
+ OptionHandler handler = handlers[i];
+ if (handler.multipleArguments) {
+ handler.handle(arguments);
+ } else {
+ handler.handle(argument);
+ }
continue OUTER;
}
}
@@ -86,6 +100,7 @@
List<String> options = new List<String>();
bool explicitOut = false;
bool wantHelp = false;
+ bool wantVersion = false;
String outputLanguage = 'JavaScript';
bool stripArgumentSet = false;
bool analyzeOnly = false;
@@ -107,9 +122,18 @@
packageRoot = currentDirectory.resolve(extractPath(argument));
}
- setOutput(String argument) {
+ setOutput(Iterator<String> arguments) {
+ String path;
+ if (arguments.current == '-o') {
+ if (!arguments.moveNext()) {
+ helpAndFail('Error: Missing file after -o option.');
+ }
+ path = arguments.current;
+ } else {
+ path = extractParameter(arguments.current);
+ }
explicitOut = true;
- out = currentDirectory.resolve(nativeToUriPath(extractParameter(argument)));
+ out = currentDirectory.resolve(nativeToUriPath(path));
sourceMapOut = Uri.parse('$out.map');
}
@@ -165,7 +189,15 @@
}
}
}
- return passThrough('--categories=${categories.join(",")}');
+ passThrough('--categories=${categories.join(",")}');
+ }
+
+ checkGlobalName(String argument) {
+ String globalName = extractParameter(argument);
+ if (!new RegExp(r'^\$[a-z]*$').hasMatch(globalName)) {
+ fail('Error: "$globalName" must match "\\\$[a-z]*"');
+ }
+ passThrough(argument);
}
handleShortOptions(String argument) {
@@ -197,8 +229,9 @@
(_) => diagnosticHandler.showWarnings = false),
new OptionHandler('--output-type=dart|--output-type=js', setOutputType),
new OptionHandler('--verbose', setVerbose),
+ new OptionHandler('--version', (_) => wantVersion = true),
new OptionHandler('--library-root=.+', setLibraryRoot),
- new OptionHandler('--out=.+|-o.+', setOutput),
+ new OptionHandler('--out=.+|-o.*', setOutput, multipleArguments: true),
new OptionHandler('--allow-mock-compilation', passThrough),
new OptionHandler('--minify', passThrough),
new OptionHandler('--force-strip=.*', setStrip),
@@ -224,6 +257,7 @@
new OptionHandler('--report-sdk-use-of-deprecated-language-features',
passThrough),
new OptionHandler('--categories=.*', setCategories),
+ new OptionHandler('--global-js-name=.*', checkGlobalName),
// The following two options must come last.
new OptionHandler('-.*', (String argument) {
@@ -235,7 +269,9 @@
];
parseCommandLine(handlers, argv);
- if (wantHelp) helpAndExit(diagnosticHandler.verbose);
+ if (wantHelp || wantVersion) {
+ helpAndExit(wantHelp, wantVersion, diagnosticHandler.verbose);
+ }
if (outputLanguage != OUTPUT_LANGUAGE_DART && stripArgumentSet) {
helpAndFail('Error: --force-strip may only be used with '
@@ -322,7 +358,7 @@
}
}
- var controller = new StreamController<String>();
+ var controller = new StreamController<String>(sync: true);
controller.stream.listen(output.write, onDone: onDone);
sink = new CountingSink(controller);
return sink;
@@ -389,19 +425,19 @@
Compiles Dart to JavaScript.
Common options:
- -o<file> Generate the output into <file>.
- -c Insert runtime type checks and enable assertions (checked mode).
- -h Display this message (add -v for information about all options).''');
+ -o <file> Generate the output into <file>.
+ -c Insert runtime type checks and enable assertions (checked mode).
+ -h Display this message (add -v for information about all options).''');
}
void verboseHelp() {
- print('''
+ print(r'''
Usage: dart2js [options] dartfile
Compiles Dart to JavaScript.
Supported options:
- -o<file>, --out=<file>
+ -o <file>, --out=<file>
Generate the output into <file>.
-c, --enable-checked-mode, --checked
@@ -413,6 +449,9 @@
-v, --verbose
Display verbose information.
+ --version
+ Display version information.
+
-p<path>, --package-root=<path>
Where to find packages, that is, "package:..." imports.
@@ -484,14 +523,27 @@
unsupported category, for example, --categories=help. To enable
all categories, use --categories=all.
+ --global-js-name=<name>
+ By default, dart2js generates JavaScript output that uses a global
+ variable named "$". The name of this global can be overridden
+ with this option. The name must match the regular expression "\$[a-z]*".
+
'''.trim());
}
-void helpAndExit(bool verbose) {
- if (verbose) {
- verboseHelp();
- } else {
- help();
+void helpAndExit(bool wantHelp, bool wantVersion, bool verbose) {
+ if (wantVersion) {
+ var version = (BUILD_ID == null)
+ ? '<non-SDK build>'
+ : BUILD_ID;
+ print('Dart-to-JavaScript compiler (dart2js) version: $version');
+ }
+ if (wantHelp) {
+ if (verbose) {
+ verboseHelp();
+ } else {
+ help();
+ }
}
exit(0);
}
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart
index 2d67ace..83a067fe 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart
@@ -48,7 +48,15 @@
SendVisitor(this.collector, TreeElements elements) : super(elements);
- visitOperatorSend(Send node) {}
+ visitOperatorSend(Send node) {
+ if (node.isParameterCheck) {
+ final element = elements[node.receiver];
+ if (element != null) {
+ collector.tryMakeLocalPlaceholder(element, node.receiver);
+ }
+ }
+ }
+
visitForeignSend(Send node) {}
visitSuperSend(Send node) {
@@ -236,9 +244,11 @@
}
void tryMakeLocalPlaceholder(Element element, Identifier node) {
- bool isOptionalParameter() {
+ bool isNamedOptionalParameter() {
FunctionElement function = element.enclosingElement;
- for (Element parameter in function.functionSignature.optionalParameters) {
+ FunctionSignature signature = function.functionSignature;
+ if (!signature.optionalParametersAreNamed) return false;
+ for (Element parameter in signature.optionalParameters) {
if (identical(parameter, element)) return true;
}
return false;
@@ -247,7 +257,7 @@
// TODO(smok): Maybe we should rename privates as well, their privacy
// should not matter if they are local vars.
if (node.source.isPrivate()) return;
- if (element.isParameter() && isOptionalParameter()) {
+ if (element.isParameter() && isNamedOptionalParameter()) {
currentFunctionScope.registerParameter(node);
} else if (Elements.isLocal(element)) {
makeLocalPlaceholder(node);
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/renamer.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/renamer.dart
index 5ad2230..a936b7d 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/renamer.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/renamer.dart
@@ -167,20 +167,24 @@
// A function that takes original identifier name and generates a new unique
// identifier.
Function generateUniqueName;
+
+ Set<String> allNamedParameterIdentifiers = new Set<String>();
+ for (var functionScope in placeholderCollector.functionScopes.values) {
+ allNamedParameterIdentifiers.addAll(functionScope.parameterIdentifiers);
+ }
+
if (compiler.enableMinification) {
MinifyingGenerator generator = new MinifyingGenerator();
Set<String> forbiddenIdentifiers = new Set<String>.from(['main']);
forbiddenIdentifiers.addAll(Keyword.keywords.keys);
forbiddenIdentifiers.addAll(fixedMemberNames);
generateUniqueName = (_) =>
- generator.generate(forbiddenIdentifiers.contains);
+ generator.generate((name) =>
+ forbiddenIdentifiers.contains(name)
+ || allNamedParameterIdentifiers.contains(name));
rename = makeRenamer(generateUniqueName);
renameElement = makeElementRenamer(rename, generateUniqueName);
- Set<String> allParameterIdentifiers = new Set<String>();
- for (var functionScope in placeholderCollector.functionScopes.values) {
- allParameterIdentifiers.addAll(functionScope.parameterIdentifiers);
- }
// Build a sorted (by usage) list of local nodes that will be renamed to
// the same identifier. So the top-used local variables in all functions
// will be renamed first and will all share the same new identifier.
@@ -209,10 +213,7 @@
renameElement(elementRenamable.element);
String memberRenamer(MemberRenamable memberRenamable) =>
generator.generate(forbiddenIdentifiers.contains);
- String localRenamer(LocalRenamable localRenamable) =>
- generator.generate((name) =>
- allParameterIdentifiers.contains(name)
- || forbiddenIdentifiers.contains(name));
+ Function localRenamer = generateUniqueName;
List<Renamable> renamables = [];
placeholderCollector.elementNodes.forEach(
(Element element, Set<Node> nodes) {
@@ -239,7 +240,9 @@
usedTopLevelOrMemberIdentifiers.addAll(fixedMemberNames);
generateUniqueName = (originalName) {
String newName = conservativeGenerator(
- originalName, usedTopLevelOrMemberIdentifiers.contains);
+ originalName, (name) =>
+ usedTopLevelOrMemberIdentifiers.contains(name)
+ || allNamedParameterIdentifiers.contains(name));
usedTopLevelOrMemberIdentifiers.add(newName);
return newName;
};
diff --git a/sdk/lib/_internal/compiler/implementation/elements/elements.dart b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
index bd1fac2..3d7982b 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/elements.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
@@ -721,6 +721,8 @@
void forEachOptionalParameter(void function(Element parameter));
void orderedForEachParameter(void function(Element parameter));
+
+ bool isCompatibleWith(FunctionSignature constructorSignature);
}
abstract class FunctionElement extends Element {
@@ -733,6 +735,8 @@
FunctionElement get patch;
FunctionElement get origin;
+ bool get isRedirectingFactory;
+
// TODO(kasperl): These are bit fishy. Do we really need them?
void set patch(FunctionElement value);
void set origin(FunctionElement value);
diff --git a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
index 1ea7a23..27b8fa6 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
@@ -317,6 +317,7 @@
get origin => unsupported();
get defaultImplementation => unsupported();
+ bool get isRedirectingFactory => unsupported();
bool get isPatched => unsupported();
bool get isPatch => unsupported();
@@ -594,6 +595,15 @@
LibraryElement get declaration => super.declaration;
LibraryElement get implementation => super.implementation;
+ Link<MetadataAnnotation> get metadata {
+ return (libraryTag == null) ? super.metadata : libraryTag.metadata;
+ }
+
+ set metadata(value) {
+ // The metadata is stored on [libraryTag].
+ throw new SpannableAssertionFailure(this, 'Cannot set metadata on Library');
+ }
+
CompilationUnitElement getCompilationUnit() => entryCompilationUnit;
void addCompilationUnit(CompilationUnitElement element) {
@@ -1093,6 +1103,38 @@
}
int get parameterCount => requiredParameterCount + optionalParameterCount;
+
+ /**
+ * Check whether a function with this signature can be used instead of a
+ * function with signature [signature] without causing a `noSuchMethod`
+ * exception/call.
+ */
+ bool isCompatibleWith(FunctionSignature signature) {
+ if (optionalParametersAreNamed != signature.optionalParametersAreNamed) {
+ return false;
+ }
+ if (optionalParametersAreNamed) {
+ if (requiredParameterCount != signature.requiredParameterCount) {
+ return false;
+ }
+ for (Element namedParameter in signature.optionalParameters) {
+ if (!optionalParameters.contains(namedParameter)) {
+ return false;
+ }
+ }
+ } else {
+ // There must be at least as many arguments as in the other signature, but
+ // this signature must not have more required parameters. Having more
+ // optional parameters is not a problem, they simply are never provided
+ // by call sites of a call to a method with the other signature.
+ if (requiredParameterCount > signature.requiredParameterCount ||
+ requiredParameterCount < signature.parameterCount ||
+ parameterCount < signature.parameterCount) {
+ return false;
+ }
+ }
+ return true;
+ }
}
class FunctionElementX extends ElementX implements FunctionElement {
@@ -1152,6 +1194,8 @@
bool get isPatched => patch != null;
bool get isPatch => origin != null;
+ bool get isRedirectingFactory => defaultImplementation != this;
+
FunctionElement get redirectionTarget {
if (this == defaultImplementation) return this;
var target = defaultImplementation;
diff --git a/sdk/lib/_internal/compiler/implementation/enqueue.dart b/sdk/lib/_internal/compiler/implementation/enqueue.dart
index 18bf774..7397b2f 100644
--- a/sdk/lib/_internal/compiler/implementation/enqueue.dart
+++ b/sdk/lib/_internal/compiler/implementation/enqueue.dart
@@ -87,6 +87,8 @@
final Function itemCompilationContextCreator;
final Map<String, Link<Element>> instanceMembersByName
= new Map<String, Link<Element>>();
+ final Map<String, Link<Element>> instanceFunctionsByName
+ = new Map<String, Link<Element>>();
final Set<ClassElement> seenClasses = new Set<ClassElement>();
final Universe universe = new Universe();
@@ -193,36 +195,71 @@
assert(invariant(member, member.isDeclaration));
if (isProcessed(member)) return;
if (!member.isInstanceMember()) return;
- if (member.isField()) {
- // Fields are implicitly used by the constructor of the
- // instantiated class they are part of.
- compiler.world.registerUsedElement(member);
- // Native fields need to go into instanceMembersByName as they
- // are virtual instantiation points and escape points. Test the
- // enclosing class, since the metadata has not been parsed yet.
- if (!member.enclosingElement.isNative()) return;
- }
String memberName = member.name.slowToString();
- if (member.kind == ElementKind.FUNCTION) {
+ if (member.kind == ElementKind.FIELD) {
+ // The obvious thing to test here would be "member.isNative()",
+ // however, that only works after metadata has been parsed/analyzed,
+ // and that may not have happened yet.
+ // So instead we use the enclosing class, which we know have had
+ // its metadata parsed and analyzed.
+ // Note: this assumes that there are no non-native fields on native
+ // classes, which may not be the case when a native class is subclassed.
+ if (cls.isNative()) {
+ compiler.world.registerUsedElement(member);
+ nativeEnqueuer.handleFieldAnnotations(member);
+ if (universe.hasInvokedGetter(member, compiler) ||
+ universe.hasInvocation(member, compiler)) {
+ nativeEnqueuer.registerFieldLoad(member);
+ // In handleUnseenSelector we can't tell if the field is loaded or
+ // stored. We need the basic algorithm to be Church-Rosser, since the
+ // resolution 'reduction' order is different to the codegen order. So
+ // register that the field is also stored. In other words: if we
+ // don't register the store here during resolution, the store could be
+ // registered during codegen on the handleUnseenSelector path, and
+ // cause the set of codegen elements to include unresolved elements.
+ nativeEnqueuer.registerFieldStore(member);
+ return;
+ }
+ if (universe.hasInvokedSetter(member, compiler)) {
+ nativeEnqueuer.registerFieldStore(member);
+ // See comment after registerFieldLoad above.
+ nativeEnqueuer.registerFieldLoad(member);
+ return;
+ }
+ // Native fields need to go into instanceMembersByName as they
+ // are virtual instantiation points and escape points.
+ } else {
+ // The codegen inlines instance fields initialization, so it
+ // does not need to add individual fields in the work list.
+ if (isResolutionQueue) {
+ addToWorkList(member);
+ }
+ return;
+ }
+ } else if (member.kind == ElementKind.FUNCTION) {
if (member.name == Compiler.NO_SUCH_METHOD) {
enableNoSuchMethod(member);
}
- if (universe.hasInvocation(member, compiler)) {
- return addToWorkList(member);
- }
// If there is a property access with the same name as a method we
// need to emit the method.
if (universe.hasInvokedGetter(member, compiler)) {
- // We will emit a closure, so make sure the closure class is
+ // We will emit a closure, so make sure the bound closure class is
// generated.
- compiler.closureClass.ensureResolved(compiler);
- registerInstantiatedClass(compiler.closureClass,
+ registerInstantiatedClass(compiler.boundClosureClass,
// Precise dependency is not important here.
compiler.globalDependencies);
return addToWorkList(member);
}
+ // Store the member in [instanceFunctionsByName] to catch
+ // getters on the function.
+ Link<Element> members = instanceFunctionsByName.putIfAbsent(
+ memberName, () => const Link<Element>());
+ instanceFunctionsByName[memberName] = members.prepend(member);
+ if (universe.hasInvocation(member, compiler)) {
+ return addToWorkList(member);
+ }
} else if (member.kind == ElementKind.GETTER) {
if (universe.hasInvokedGetter(member, compiler)) {
return addToWorkList(member);
@@ -236,28 +273,6 @@
if (universe.hasInvokedSetter(member, compiler)) {
return addToWorkList(member);
}
- } else if (member.kind == ElementKind.FIELD &&
- member.enclosingElement.isNative()) {
- nativeEnqueuer.handleFieldAnnotations(member);
- if (universe.hasInvokedGetter(member, compiler) ||
- universe.hasInvocation(member, compiler)) {
- nativeEnqueuer.registerFieldLoad(member);
- // In handleUnseenSelector we can't tell if the field is loaded or
- // stored. We need the basic algorithm to be Church-Rosser, since the
- // resolution 'reduction' order is different to the codegen order. So
- // register that the field is also stored. In other words: if we don't
- // register the store here during resolution, the store could be
- // registered during codegen on the handleUnseenSelector path, and cause
- // the set of codegen elements to include unresolved elements.
- nativeEnqueuer.registerFieldStore(member);
- return;
- }
- if (universe.hasInvokedSetter(member, compiler)) {
- nativeEnqueuer.registerFieldStore(member);
- // See comment after registerFieldLoad above.
- nativeEnqueuer.registerFieldLoad(member);
- return;
- }
}
// The element is not yet used. Add it to the list of instance
@@ -282,12 +297,6 @@
cls.ensureResolved(compiler);
cls.implementation.forEachMember(processInstantiatedClassMember);
if (isResolutionQueue) {
- // Only the resolution queue needs to operate on individual
- // fields. The codegen enqueuer inlines the potential field
- // intializations in the constructor.
- cls.implementation.forEachInstanceField((_, Element field) {
- addToWorkList(field);
- }, includeSuperAndInjectedMembers: true);
compiler.resolver.checkClass(cls);
}
}
@@ -386,22 +395,32 @@
void registerNewSymbol(TreeElements elements) {
}
- processInstanceMembers(SourceString n, bool f(Element e)) {
+ processLink(Map<String, Link<Element>> map,
+ SourceString n,
+ bool f(Element e)) {
String memberName = n.slowToString();
- Link<Element> members = instanceMembersByName[memberName];
+ Link<Element> members = map[memberName];
if (members != null) {
LinkBuilder<Element> remaining = new LinkBuilder<Element>();
for (; !members.isEmpty; members = members.tail) {
if (!f(members.head)) remaining.addLast(members.head);
}
- instanceMembersByName[memberName] = remaining.toLink();
+ map[memberName] = remaining.toLink();
}
}
+ processInstanceMembers(SourceString n, bool f(Element e)) {
+ processLink(instanceMembersByName, n, f);
+ }
+
+ processInstanceFunctions(SourceString n, bool f(Element e)) {
+ processLink(instanceFunctionsByName, n, f);
+ }
+
void handleUnseenSelector(SourceString methodName, Selector selector) {
processInstanceMembers(methodName, (Element member) {
if (selector.appliesUnnamed(member, compiler)) {
- if (member.isField() && member.enclosingElement.isNative()) {
+ if (member.isField() && member.getEnclosingClass().isNative()) {
if (selector.isGetter() || selector.isCall()) {
nativeEnqueuer.registerFieldLoad(member);
// We have to also handle storing to the field because we only get
@@ -410,6 +429,7 @@
// TODO(sra): Process fields for storing separately.
nativeEnqueuer.registerFieldStore(member);
} else {
+ assert(selector.isSetter());
nativeEnqueuer.registerFieldStore(member);
// We have to also handle loading from the field because we only get
// one look at each member and there might be a load we have not
@@ -424,6 +444,19 @@
}
return false;
});
+ if (selector.isGetter()) {
+ processInstanceFunctions(methodName, (Element member) {
+ if (selector.appliesUnnamed(member, compiler)) {
+ // We will emit a closure, so make sure the bound closure class is
+ // generated.
+ registerInstantiatedClass(compiler.boundClosureClass,
+ // Precise dependency is not important here.
+ compiler.globalDependencies);
+ return true;
+ }
+ return false;
+ });
+ }
}
/**
@@ -439,6 +472,8 @@
void registerGetOfStaticFunction(FunctionElement element) {
registerStaticUse(element);
+ registerInstantiatedClass(compiler.closureClass,
+ compiler.globalDependencies);
universe.staticFunctionsNeedingGetter.add(element);
}
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
index 6ecbfd5..417dca9 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
@@ -58,7 +58,6 @@
bool needsInheritFunction = false;
bool needsDefineClass = false;
bool needsMixinSupport = false;
- bool needsClosureClass = false;
bool needsLazyInitializer = false;
final Namer namer;
ConstantEmitter constantEmitter;
@@ -1558,6 +1557,10 @@
emitSuper(superName, builder);
emitRuntimeName(runtimeName, builder);
emitClassFields(classElement, builder, superName);
+ var metadata = buildMetadataFunction(classElement);
+ if (metadata != null) {
+ builder.addProperty("@", metadata);
+ }
emitClassGettersSetters(classElement, builder);
if (!classElement.isMixinApplication) {
emitInstanceMembers(classElement, builder);
@@ -1756,19 +1759,6 @@
return (ClassElement cls) => !unneededClasses.contains(cls);
}
- void emitClosureClassIfNeeded(CodeBuffer buffer) {
- // The closure class could have become necessary because of the generation
- // of stubs.
- ClassElement closureClass = compiler.closureClass;
- if (needsClosureClass && !instantiatedClasses.contains(closureClass)) {
- ClassElement objectClass = compiler.objectClass;
- if (!instantiatedClasses.contains(objectClass)) {
- generateClass(objectClass, bufferForElement(objectClass, buffer));
- }
- generateClass(closureClass, bufferForElement(closureClass, buffer));
- }
- }
-
void emitFinishClassesInvocationIfNecessary(CodeBuffer buffer) {
if (needsDefineClass) {
buffer.write('$finishClassesName($classesCollector,'
@@ -1855,7 +1845,7 @@
String staticName = namer.getName(element);
String superName = namer.getName(compiler.closureClass);
String name = 'Closure\$${element.name.slowToString()}';
- needsClosureClass = true;
+ assert(instantiatedClasses.contains(compiler.closureClass));
ClassElement closureClassElement = new ClosureClassElement(
null, new SourceString(name), compiler, element,
@@ -1877,7 +1867,7 @@
// If a static function is used as a closure we need to add its name
// in case it is used in spawnFunction.
String methodName = namer.STATIC_CLOSURE_NAME_NAME;
- emitBoundClosureClassHeader(
+ emitClosureClassHeader(
mangledName, superName, <String>[invocationName, methodName],
closureBuilder);
@@ -1889,7 +1879,7 @@
closureBuilder.addProperty(operator, js('true'));
});
- // TODO(ngeoffray): Cache common base classes for clsures, bound
+ // TODO(ngeoffray): Cache common base classes for closures, bound
// closures, and static closures that have common type checks.
boundClosures.add(
js('$classesCollector.$mangledName = #',
@@ -1899,10 +1889,10 @@
}
}
- void emitBoundClosureClassHeader(String mangledName,
- String superName,
- List<String> fieldNames,
- ClassBuilder builder) {
+ void emitClosureClassHeader(String mangledName,
+ String superName,
+ List<String> fieldNames,
+ ClassBuilder builder) {
builder.addProperty('',
js.string("$superName;${fieldNames.join(',')}"));
}
@@ -1915,6 +1905,7 @@
void emitDynamicFunctionGetter(FunctionElement member,
DefineStubFunction defineStub) {
assert(invariant(member, member.isDeclaration));
+ assert(instantiatedClasses.contains(compiler.boundClosureClass));
// For every method that has the same name as a property-get we create a
// getter that returns a bound closure. Say we have a class 'A' with method
// 'foo' and somewhere in the code there is a dynamic property get of
@@ -1924,8 +1915,7 @@
// foo(x, y, z) { ... } // Original function.
// get foo { return new BoundClosure499(this, "foo"); }
// }
- // class BoundClosure499 extends Closure {
- // var self;
+ // class BoundClosure499 extends BoundClosure {
// BoundClosure499(this.self, this.name);
// $call3(x, y, z) { return self[name](x, y, z); }
// }
@@ -1940,21 +1930,18 @@
int parameterCount = member.parameterCount(compiler);
Map<int, String> cache;
- String extraArg = null;
// Intercepted methods take an extra parameter, which is the
// receiver of the call.
bool inInterceptor = backend.isInterceptedMethod(member);
if (inInterceptor) {
cache = interceptorClosureCache;
- extraArg = 'receiver';
} else {
cache = boundClosureCache;
}
- List<String> fieldNames = compiler.enableMinification
- ? inInterceptor ? const ['a', 'b', 'c']
- : const ['a', 'b']
- : inInterceptor ? const ['self', 'target', 'receiver']
- : const ['self', 'target'];
+ List<String> fieldNames = <String>[];
+ compiler.boundClosureClass.forEachInstanceField((_, Element field) {
+ fieldNames.add(namer.getName(field));
+ });
Iterable<Element> typedefChecks =
getTypedefChecksOn(member.computeType(compiler));
@@ -1983,12 +1970,11 @@
member.getCompilationUnit());
String mangledName = namer.getName(closureClassElement);
String superName = namer.getName(closureClassElement.superclass);
- needsClosureClass = true;
// Define the constructor with a name so that Object.toString can
// find the class name of the closure class.
ClassBuilder boundClosureBuilder = new ClassBuilder();
- emitBoundClosureClassHeader(
+ emitClosureClassHeader(
mangledName, superName, fieldNames, boundClosureBuilder);
// Now add the methods on the closure class. The instance method does not
// have the correct name. Since [addParameterStubs] use the name to create
@@ -2044,8 +2030,12 @@
arguments.add(js('this'));
arguments.add(js.string(targetName));
if (inInterceptor) {
- parameters.add(extraArg);
- arguments.add(js(extraArg));
+ String receiverArg = fieldNames[2];
+ parameters.add(receiverArg);
+ arguments.add(js(receiverArg));
+ } else {
+ // Put null in the intercepted receiver field.
+ arguments.add(new jsAst.LiteralNull());
}
jsAst.Expression getterFunction = js.fun(
@@ -2940,6 +2930,26 @@
if (compiler.enableMinification) buffer.write('\n');
}
+ /// The metadata function returns the metadata associated with
+ /// [element] in generated code. The metadata needs to be wrapped
+ /// in a function as it refers to constants that may not have been
+ /// constructed yet. For example, a class is allowed to be
+ /// annotated with itself. The metadata function is used by
+ /// mirrors_patch to implement DeclarationMirror.metadata.
+ jsAst.Fun buildMetadataFunction(Element element) {
+ if (compiler.mirrorSystemClass == null) return null;
+ var metadata = [];
+ Link link = element.metadata;
+ // TODO(ahe): Why is metadata sometimes null?
+ if (link != null) {
+ for (; !link.isEmpty; link = link.tail) {
+ metadata.add(constantReference(link.head.value));
+ }
+ }
+ if (metadata.isEmpty) return null;
+ return js.fun([], [js.return_(new jsAst.ArrayInitializer.from(metadata))]);
+ }
+
String assembleProgram() {
measure(() {
// Compute the required type checks to know which classes need a
@@ -2948,7 +2958,7 @@
computeNeededClasses();
- mainBuffer.add(GENERATED_BY);
+ mainBuffer.add(buildGeneratedBy());
addComment(HOOKS_API_USAGE, mainBuffer);
mainBuffer.add('function ${namer.isolateName}()$_{}\n');
mainBuffer.add('init()$N$n');
@@ -2997,7 +3007,6 @@
}
emitStaticFunctionClosures();
- emitClosureClassIfNeeded(mainBuffer);
addComment('Bound closures', mainBuffer);
// Now that we have emitted all classes, we know all the bound
@@ -3021,13 +3030,13 @@
mainBuffer.write(';');
}
mainBuffer
- ..write(REFLECTION_DATA_PARSER)
+ ..write(getReflectionDataParser())
..write('([$n');
emitDeferredPreambleWhenEmpty(deferredBuffer);
deferredBuffer.add('\$\$$_=$_{};$n');
deferredBuffer
- ..write(REFLECTION_DATA_PARSER)
+ ..write(getReflectionDataParser())
..write('([$n');
var sortedLibraries = Elements.sortedByPosition(libraryBuffers.keys);
for (LibraryElement library in sortedLibraries) {
@@ -3042,9 +3051,13 @@
compiler.sourceMapUri, library.canonicalUri, false);
}
if (buffer != null) {
+ var metadata = buildMetadataFunction(library);
mainBuffer
..write('["${library.getLibraryOrScriptName()}",$_')
..write('"${uri}",$_')
+ ..write(metadata == null
+ ? "" : jsAst.prettyPrint(metadata, compiler))
+ ..write(',$_')
..write('{$n')
..addBuffer(buffer)
..write('}],$n');
@@ -3054,6 +3067,7 @@
deferredBuffer
..write('["${library.getLibraryOrScriptName()}",$_')
..write('"${uri}",$_')
+ ..write('[],$_')
..write('{$n')
..addBuffer(buffer)
..write('}],$n');
@@ -3173,7 +3187,7 @@
void emitDeferredPreambleWhenEmpty(CodeBuffer buffer) {
if (!buffer.isEmpty) return;
- buffer.write(GENERATED_BY);
+ buffer.write(buildGeneratedBy());
buffer.write('var old${namer.CURRENT_ISOLATE}$_='
'$_${namer.CURRENT_ISOLATE}$N');
@@ -3186,6 +3200,12 @@
'$_${namer.isolateName}.prototype$N$n');
}
+ String buildGeneratedBy() {
+ var suffix = '';
+ if (compiler.hasBuildId) suffix = ' version: ${compiler.buildId}';
+ return '// Generated by dart2js, the Dart to JavaScript compiler$suffix.\n';
+ }
+
String buildSourceMap(CodeBuffer buffer, SourceFile compiledFile) {
SourceMapBuilder sourceMapBuilder =
new SourceMapBuilder(compiler.sourceMapUri);
@@ -3212,6 +3232,39 @@
MessageKind.GENERIC.error({'text': message}),
api.Diagnostic.WARNING);
}
+
+ // TODO(ahe): This code should be integrated in finishClasses.
+ String getReflectionDataParser() {
+ return '''
+(function (reflectionData) {
+ if (!init.libraries) init.libraries = [];
+ var libraries = init.libraries;
+ var hasOwnProperty = Object.prototype.hasOwnProperty;
+ var length = reflectionData.length;
+ for (var i = 0; i < length; i++) {
+ var data = reflectionData[i];
+ var name = data[0];
+ var uri = data[1];
+ var metadata = data[2];
+ var descriptor = data[3];
+ var classes = [];
+ var functions = [];
+ for (var property in descriptor) {
+ if (!hasOwnProperty.call(descriptor, property)) continue;
+ var element = descriptor[property];
+ if (typeof element === "function") {
+ ${namer.CURRENT_ISOLATE}[property] = element;
+ functions.push(property);
+ } else {
+ $classesCollector[property] = element;
+ classes.push(property);
+ classes.push(element[""]);
+ }
+ }
+ libraries.push([name, uri, classes, functions, metadata]);
+ }
+})''';
+ }
}
const String GENERATED_BY = """
@@ -3227,34 +3280,3 @@
// Instead, a closure that will invoke [main] is
// passed to [dartMainRunner].
""";
-
-// TODO(ahe): This code should be integrated in finishClasses.
-// TODO(ahe): The uri field below is fake.
-const String REFLECTION_DATA_PARSER = r'''
-(function (reflectionData) {
- if (!init.libraries) init.libraries = [];
- var libraries = init.libraries;
- var hasOwnProperty = Object.prototype.hasOwnProperty;
- var length = reflectionData.length;
- for (var i = 0; i < length; i++) {
- var data = reflectionData[i];
- var name = data[0];
- var uri = data[1];
- var descriptor = data[2];
- var classes = [];
- var functions = [];
- for (var property in descriptor) {
- if (!hasOwnProperty.call(descriptor, property)) continue;
- var element = descriptor[property];
- if (typeof element === "function") {
- $[property] = element;
- functions.push(property);
- } else {
- $$[property] = element;
- classes.push(property);
- classes.push(element[""]);
- }
- }
- libraries.push([name, uri, classes, functions]);
- }
-})''';
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/emitter_no_eval.dart b/sdk/lib/_internal/compiler/implementation/js_backend/emitter_no_eval.dart
index e739b58..ebdb9fd 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/emitter_no_eval.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/emitter_no_eval.dart
@@ -25,10 +25,10 @@
}
}
- void emitBoundClosureClassHeader(String mangledName,
- String superName,
- List<String> fieldNames,
- ClassBuilder builder) {
+ void emitClosureClassHeader(String mangledName,
+ String superName,
+ List<String> fieldNames,
+ ClassBuilder builder) {
builder.addProperty('', buildConstructor(mangledName, fieldNames));
emitSuper(superName, builder);
}
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart b/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
index 3f43bc6..c83e714 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
@@ -172,7 +172,7 @@
return _jsVariableReserved;
}
- final String CURRENT_ISOLATE = r'$';
+ final String CURRENT_ISOLATE;
final String getterPrefix = r'get$';
final String setterPrefix = r'set$';
@@ -204,6 +204,7 @@
Namer(Compiler compiler)
: compiler = compiler,
+ CURRENT_ISOLATE = compiler.globalJsName,
globals = new Map<Element, String>(),
shortPrivateNameOwners = new Map<String, LibraryElement>(),
bailoutNames = new Map<Element, String>(),
diff --git a/sdk/lib/_internal/compiler/implementation/lib/foreign_helper.dart b/sdk/lib/_internal/compiler/implementation/lib/foreign_helper.dart
index fb06bf3..3cfe86a 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/foreign_helper.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/foreign_helper.dart
@@ -90,14 +90,14 @@
*/
// Add additional optional arguments if needed. The method is treated internally
// as a variable argument method.
-dynamic JS(String typeDescription, String codeTemplate,
- [var arg0, var arg1, var arg2, var arg3, var arg4, var arg5, var arg6,
- var arg7, var arg8, var arg9, var arg10, var arg11]) {}
+JS(String typeDescription, String codeTemplate,
+ [arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11])
+{}
/**
* Returns the isolate in which this code is running.
*/
-IsolateContext JS_CURRENT_ISOLATE() {}
+IsolateContext JS_CURRENT_ISOLATE_CONTEXT() {}
abstract class IsolateContext {
/// Holds a (native) JavaScript instance of Isolate, see
@@ -108,12 +108,12 @@
/**
* Invokes [function] in the context of [isolate].
*/
-dynamic JS_CALL_IN_ISOLATE(var isolate, Function function) {}
+JS_CALL_IN_ISOLATE(isolate, Function function) {}
/**
* Converts the Dart closure [function] into a JavaScript closure.
*/
-dynamic DART_CLOSURE_TO_JS(Function function) {}
+DART_CLOSURE_TO_JS(Function function) {}
/**
* Returns a raw reference to the JavaScript function which implements
@@ -127,17 +127,17 @@
* to V8's Error.captureStackTrace. See
* https://code.google.com/p/v8/wiki/JavaScriptStackTraceApi.
*/
-dynamic RAW_DART_FUNCTION_REF(Function function) {}
+RAW_DART_FUNCTION_REF(Function function) {}
/**
* Sets the current isolate to [isolate].
*/
-void JS_SET_CURRENT_ISOLATE(var isolate) {}
+void JS_SET_CURRENT_ISOLATE(isolate) {}
/**
* Creates an isolate and returns it.
*/
-dynamic JS_CREATE_ISOLATE() {}
+JS_CREATE_ISOLATE() {}
/**
* Returns the JavaScript constructor function for Dart's Object class.
@@ -146,7 +146,7 @@
* if (JS('bool', '# instanceof #', obj, JS_DART_OBJECT_CONSTRUCTOR()))
* ...
*/
-dynamic JS_DART_OBJECT_CONSTRUCTOR() {}
+JS_DART_OBJECT_CONSTRUCTOR() {}
/**
* Returns the prefix used for generated is checks on classes.
@@ -158,8 +158,16 @@
*/
String JS_OPERATOR_AS_PREFIX() {}
+/// Returns the name of the class `Object` in the generated code.
+String JS_OBJECT_CLASS_NAME() {}
+
/**
* Returns the field name used for determining if an object or its
* interceptor has JavaScript indexing behavior.
*/
String JS_IS_INDEXABLE_FIELD_NAME() {}
+
+/**
+ * Returns the object corresponding to Namer.CURRENT_ISOLATE.
+ */
+JS_CURRENT_ISOLATE() {}
diff --git a/sdk/lib/_internal/compiler/implementation/lib/io_patch.dart b/sdk/lib/_internal/compiler/implementation/lib/io_patch.dart
index feb7009..37dc6b8 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/io_patch.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/io_patch.dart
@@ -90,9 +90,6 @@
patch static _deleteLink(String path) {
throw new UnsupportedError("File._deleteLink");
}
- patch static _directory(String path) {
- throw new UnsupportedError("File._directory");
- }
patch static _lengthFromPath(String path) {
throw new UnsupportedError("File._lengthFromPath");
}
diff --git a/sdk/lib/_internal/compiler/implementation/lib/isolate_helper.dart b/sdk/lib/_internal/compiler/implementation/lib/isolate_helper.dart
index 3c79299..2f85b44 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/isolate_helper.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/isolate_helper.dart
@@ -12,6 +12,7 @@
import 'dart:_foreign_helper' show DART_CLOSURE_TO_JS,
JS,
JS_CREATE_ISOLATE,
+ JS_CURRENT_ISOLATE_CONTEXT,
JS_CURRENT_ISOLATE,
JS_SET_CURRENT_ISOLATE,
IsolateContext;
@@ -425,7 +426,7 @@
* JavaScript workers.
*/
static String computeThisScript() {
- var currentScript = JS('', r'$.$currentScript');
+ var currentScript = JS('', r'#.$currentScript', JS_CURRENT_ISOLATE());
if (currentScript != null) {
return JS('String', 'String(#.src)', currentScript);
}
@@ -555,11 +556,11 @@
/** Find a constructor given its name. */
static dynamic _getJSConstructorFromName(String factoryName) {
- return JS("", r"$[#]", factoryName);
+ return JS("", "#[#]", JS_CURRENT_ISOLATE(), factoryName);
}
static dynamic _getJSFunctionFromName(String functionName) {
- return JS("", r"$[#]", functionName);
+ return JS("", "#[#]", JS_CURRENT_ISOLATE(), functionName);
}
/**
diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart b/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart
index 17507a2..2cbd650 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart
@@ -9,10 +9,12 @@
JS,
JS_CALL_IN_ISOLATE,
JS_CURRENT_ISOLATE,
+ JS_CURRENT_ISOLATE_CONTEXT,
JS_DART_OBJECT_CONSTRUCTOR,
- JS_OPERATOR_IS_PREFIX,
- JS_OPERATOR_AS_PREFIX,
JS_IS_INDEXABLE_FIELD_NAME,
+ JS_OBJECT_CLASS_NAME,
+ JS_OPERATOR_AS_PREFIX,
+ JS_OPERATOR_IS_PREFIX,
RAW_DART_FUNCTION_REF;
import 'dart:_interceptors';
import "dart:_collection-dev" as _symbol_dev;
@@ -145,13 +147,13 @@
static int hashCodeSeed = 0;
static int objectHashCode(object) {
- int hash = JS('var', r'#.$identityHash', object);
+ int hash = JS('int|Null', r'#.$identityHash', object);
if (hash == null) {
// TOOD(ahe): We should probably randomize this somehow.
hash = ++hashCodeSeed;
JS('void', r'#.$identityHash = #', object, hash);
}
- return hash;
+ return JS('int', '#', hash);
}
/**
@@ -576,8 +578,7 @@
if (JS('bool', '# == "num"', int)) return const JSNumber();
if (JS('bool', '# == "bool"', int)) return const JSBool();
if (JS('bool', '# == "List"', int)) return const JSArray();
- // TODO(ahe): How to safely access $?
- return JS('var', r'$[#]', className);
+ return JS('var', '#[#]', JS_CURRENT_ISOLATE(), className);
}
static bool identicalImplementation(a, b) {
@@ -932,7 +933,7 @@
// Capture the current isolate now. Remember that "#"
// in JS is simply textual substitution of compiled
// expressions.
- JS_CURRENT_ISOLATE(),
+ JS_CURRENT_ISOLATE_CONTEXT(),
DART_CLOSURE_TO_JS(invokeClosure));
JS('void', r'#.$identity = #', closure, function);
@@ -946,6 +947,28 @@
String toString() => "Closure";
}
+class BoundClosure extends Closure {
+ var self;
+ var target;
+ var receiver;
+
+ bool operator==(other) {
+ if (identical(this, other)) return true;
+ if (other is! BoundClosure) return false;
+ return JS('bool', '# === # && # === # && # === #',
+ self, other.self,
+ target, other.target,
+ receiver, other.receiver);
+ }
+
+ int get hashCode {
+ return JS('int', '(# + # + #) & 0x3ffffff',
+ self.hashCode,
+ target.hashCode,
+ receiver.hashCode);
+ }
+}
+
bool jsHasOwnProperty(var jsObject, String property) {
return JS('bool', r'#.hasOwnProperty(#)', jsObject, property);
}
diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_mirrors.dart b/sdk/lib/_internal/compiler/implementation/lib/js_mirrors.dart
new file mode 100644
index 0000000..d1f93ed
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/lib/js_mirrors.dart
@@ -0,0 +1,486 @@
+// 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 dart._js_mirrors;
+
+import 'dart:async';
+import 'dart:mirrors';
+
+import 'dart:_foreign_helper' show JS, JS_CURRENT_ISOLATE;
+import 'dart:_collection-dev' as _symbol_dev;
+import 'dart:_js_helper' show
+ Closure,
+ JSInvocationMirror,
+ Null,
+ Primitives,
+ createInvocationMirror;
+import 'dart:_interceptors' show Interceptor;
+
+String getName(Symbol symbol) => n(symbol);
+
+class JsMirrorSystem implements MirrorSystem {
+ TypeMirror get dynamicType => _dynamicType;
+ TypeMirror get voidType => _voidType;
+
+ final static TypeMirror _dynamicType =
+ new JsTypeMirror(const Symbol('dynamic'));
+ final static TypeMirror _voidType = new JsTypeMirror(const Symbol('void'));
+
+ static final Map<String, List<LibraryMirror>> librariesByName =
+ computeLibrariesByName();
+
+ Iterable<LibraryMirror> findLibrary(Symbol libraryName) {
+ return new List<LibraryMirror>.from(librariesByName[n(libraryName)]);
+ }
+
+ static Map<String, List<LibraryMirror>> computeLibrariesByName() {
+ var result = new Map<String, List<LibraryMirror>>();
+ var jsLibraries = JS('=List|Null', 'init.libraries');
+ if (jsLibraries == null) return result;
+ for (List data in jsLibraries) {
+ String name = data[0];
+ Uri uri = Uri.parse(data[1]);
+ List<String> classes = data[2];
+ List<String> functions = data[3];
+ var metadataFunction = data[4];
+ List metadata = (metadataFunction == null)
+ ? null : JS('List', '#()', metadataFunction);
+ var libraries = result.putIfAbsent(name, () => <LibraryMirror>[]);
+ libraries.add(
+ new JsLibraryMirror(s(name), uri, classes, functions, metadata));
+ }
+ return result;
+ }
+}
+
+class JsTypeMirror implements TypeMirror {
+ final Symbol simpleName;
+ JsTypeMirror(this.simpleName);
+}
+
+class JsLibraryMirror extends JsObjectMirror implements LibraryMirror {
+ final Symbol simpleName;
+ final Uri uri;
+ final List<String> _classes;
+ final List<String> _functions;
+ final List _metadata;
+
+ JsLibraryMirror(this.simpleName,
+ this.uri,
+ this._classes,
+ this._functions,
+ this._metadata);
+
+ Symbol get qualifiedName => simpleName;
+
+ Map<Symbol, ClassMirror> get classes {
+ var result = new Map<Symbol, ClassMirror>();
+ for (int i = 0; i < _classes.length; i += 2) {
+ Symbol symbol = s(_classes[i]);
+ JsClassMirror cls = reflectClassByName(symbol, _classes[i + 1]);
+ result[symbol] = cls;
+ cls._owner = this;
+ }
+ return result;
+ }
+
+ InstanceMirror setField(Symbol fieldName, Object arg) {
+ // TODO(ahe): This is extremely dangerous!!!
+ JS('void', '#[#] = #', JS_CURRENT_ISOLATE(), n(fieldName), arg);
+ return reflect(arg);
+ }
+
+ InstanceMirror getField(Symbol fieldName) {
+ // TODO(ahe): This is extremely dangerous!!!
+ return reflect(JS('', '#[#]', JS_CURRENT_ISOLATE(), n(fieldName)));
+ }
+
+ Map<Symbol, MethodMirror> get functions {
+ var result = new Map<Symbol, MethodMirror>();
+ for (int i = 0; i < _functions.length; i++) {
+ String name = _functions[i];
+ Symbol symbol = s(name);
+ int parameterCount = null; // TODO(ahe): Compute this.
+ JsMethodMirror mirror =
+ // TODO(ahe): Create accessor for accessing $. It is also
+ // used in js_helper.
+ new JsMethodMirror(
+ symbol, JS('', '#[#]', JS_CURRENT_ISOLATE(), name), parameterCount);
+ // TODO(ahe): Cache mirrors.
+ result[symbol] = mirror;
+ mirror._owner = this;
+ }
+ return result;
+ }
+
+ Map<Symbol, MethodMirror> get getters {
+ var result = new Map<Symbol, MethodMirror>();
+ // TODO(ahe): Implement this.
+ return result;
+ }
+
+ Map<Symbol, MethodMirror> get setters {
+ var result = new Map<Symbol, MethodMirror>();
+ // TODO(ahe): Implement this.
+ return result;
+ }
+
+ Map<Symbol, VariableMirror> get variables {
+ var result = new Map<Symbol, VariableMirror>();
+ // TODO(ahe): Implement this.
+ return result;
+ }
+
+ Map<Symbol, Mirror> get members {
+ Map<Symbol, Mirror> result = new Map<Symbol, Mirror>.from(classes);
+ addToResult(Symbol key, Mirror value) {
+ result[key] = value;
+ }
+ functions.forEach(addToResult);
+ getters.forEach(addToResult);
+ setters.forEach(addToResult);
+ variables.forEach(addToResult);
+ return result;
+ }
+
+ List<InstanceMirror> get metadata => _metadata.map(reflect).toList();
+}
+
+String n(Symbol symbol) => _symbol_dev.Symbol.getName(symbol);
+
+Symbol s(String name) {
+ if (name == null) return null;
+ return new _symbol_dev.Symbol.unvalidated(name);
+}
+
+final JsMirrorSystem currentJsMirrorSystem = new JsMirrorSystem();
+
+InstanceMirror reflect(Object reflectee) {
+ if (reflectee is Closure) {
+ return new JsClosureMirror(reflectee);
+ } else {
+ return new JsInstanceMirror(reflectee);
+ }
+}
+
+final Expando<ClassMirror> classMirrors = new Expando<ClassMirror>();
+
+ClassMirror reflectType(Type key) => reflectClassByName(s('$key'), null);
+
+ClassMirror reflectClassByName(Symbol symbol, String fields) {
+ String className = n(symbol);
+ var constructor = Primitives.getConstructor(className);
+ if (constructor == null) {
+ // Probably an intercepted class.
+ // TODO(ahe): How to handle intercepted classes?
+ throw new UnsupportedError('Cannot find class for: $className');
+ }
+ var mirror = classMirrors[constructor];
+ if (mirror == null) {
+ mirror = new JsClassMirror(symbol, constructor, fields);
+ classMirrors[constructor] = mirror;
+ }
+ return mirror;
+}
+
+abstract class JsObjectMirror implements ObjectMirror {
+ Future<InstanceMirror> setFieldAsync(Symbol fieldName, Object value) {
+ return new Future<InstanceMirror>(() => this.setField(fieldName, value));
+ }
+
+ Future<InstanceMirror> getFieldAsync(Symbol fieldName) {
+ return new Future<InstanceMirror>(() => this.getField(fieldName));
+ }
+}
+
+class JsInstanceMirror extends JsObjectMirror implements InstanceMirror {
+ final reflectee;
+
+ JsInstanceMirror(this.reflectee);
+
+ bool get hasReflectee => true;
+
+ ClassMirror get type => reflectType(reflectee.runtimeType);
+
+ Future<InstanceMirror> invokeAsync(Symbol memberName,
+ List<Object> positionalArguments,
+ [Map<Symbol, dynamic> namedArguments]) {
+ if (namedArguments != null && !namedArguments.isEmpty) {
+ throw new UnsupportedError('Named arguments are not implemented');
+ }
+ return
+ new Future<InstanceMirror>(
+ () => invoke(memberName, positionalArguments, namedArguments));
+ }
+
+ InstanceMirror invoke(Symbol memberName,
+ List positionalArguments,
+ [Map<Symbol,dynamic> namedArguments]) {
+ if (namedArguments != null && !namedArguments.isEmpty) {
+ throw new UnsupportedError('Named arguments are not implemented');
+ }
+ // Copy the list to ensure that it can safely be passed to
+ // JavaScript.
+ var jsList = new List.from(positionalArguments);
+ return _invoke(
+ memberName, JSInvocationMirror.METHOD,
+ '${n(memberName)}\$${positionalArguments.length}', jsList);
+ }
+
+ InstanceMirror _invoke(Symbol name,
+ int type,
+ String mangledName,
+ List arguments) {
+ // TODO(ahe): Get the argument names.
+ List<String> argumentNames = [];
+ Invocation invocation = createInvocationMirror(
+ n(name), mangledName, type, arguments, argumentNames);
+
+ return reflect(delegate(invocation));
+ }
+
+ InstanceMirror setField(Symbol fieldName, Object arg) {
+ _invoke(
+ fieldName, JSInvocationMirror.SETTER, 'set\$${n(fieldName)}', [arg]);
+ return reflect(arg);
+ }
+
+ InstanceMirror getField(Symbol fieldName) {
+ return _invoke(
+ fieldName, JSInvocationMirror.GETTER, 'get\$${n(fieldName)}', []);
+ }
+
+ delegate(Invocation invocation) {
+ return JSInvocationMirror.invokeFromMirror(invocation, reflectee);
+ }
+
+ String toString() => 'InstanceMirror($reflectee)';
+}
+
+class JsClassMirror extends JsObjectMirror implements ClassMirror {
+ final Symbol simpleName;
+ final _jsConstructor;
+ final String _fields;
+ List _metadata;
+ // Set as side-effect of accessing JsLibraryMirror.classes.
+ JsLibraryMirror _owner;
+
+ JsClassMirror(this.simpleName, this._jsConstructor, this._fields);
+
+ Symbol get qualifiedName => computeQualifiedName(owner, simpleName);
+
+ Map<Symbol, MethodMirror> get functions {
+ var result = new Map<Symbol, MethodMirror>();
+ // TODO(ahe): Implement this.
+ return result;
+ }
+
+ Map<Symbol, MethodMirror> get getters {
+ var result = new Map<Symbol, MethodMirror>();
+ // TODO(ahe): Implement this.
+ return result;
+ }
+
+ Map<Symbol, MethodMirror> get setters {
+ var result = new Map<Symbol, MethodMirror>();
+ // TODO(ahe): Implement this.
+ return result;
+ }
+
+ Map<Symbol, VariableMirror> get variables {
+ var result = new Map<Symbol, VariableMirror>();
+ var s = _fields.split(";");
+ var fields = s[1] == "" ? [] : s[1].split(",");
+ for (String field in fields) {
+ JsVariableMirror mirror = new JsVariableMirror.from(field);
+ result[mirror.simpleName] = mirror;
+ mirror._owner = this;
+ }
+ return result;
+ }
+
+ Map<Symbol, Mirror> get members {
+ Map<Symbol, Mirror> result = new Map<Symbol, Mirror>.from(functions);
+ addToResult(Symbol key, Mirror value) {
+ result[key] = value;
+ }
+ getters.forEach(addToResult);
+ setters.forEach(addToResult);
+ variables.forEach(addToResult);
+ return result;
+ }
+
+ InstanceMirror setField(Symbol fieldName, Object arg) {
+ // TODO(ahe): This is extremely dangerous!!!
+ JS('void', '#[#] = #', JS_CURRENT_ISOLATE(),
+ '${n(simpleName)}_${n(fieldName)}', arg);
+ return reflect(arg);
+ }
+
+ InstanceMirror getField(Symbol fieldName) {
+ // TODO(ahe): This is extremely dangerous!!!
+ return reflect(
+ JS('', '#[#]', JS_CURRENT_ISOLATE(),
+ '${n(simpleName)}_${n(fieldName)}'));
+ }
+
+ InstanceMirror newInstance(Symbol constructorName,
+ List positionalArguments,
+ [Map<Symbol,dynamic> namedArguments]) {
+ if (namedArguments != null && !namedArguments.isEmpty) {
+ throw new UnsupportedError('Named arguments are not implemented');
+ }
+ String constructorName = '${n(simpleName)}\$${n(constructorName)}';
+ return reflect(JS('', r'#[#].apply(#, #)', JS_CURRENT_ISOLATE(),
+ constructorName,
+ JS_CURRENT_ISOLATE(),
+ new List.from(positionalArguments)));
+ }
+
+ Future<InstanceMirror> newInstanceAsync(
+ Symbol constructorName,
+ List positionalArguments,
+ [Map<Symbol, dynamic> namedArguments]) {
+ if (namedArguments != null && !namedArguments.isEmpty) {
+ throw new UnsupportedError('Named arguments are not implemented');
+ }
+ return new Future<InstanceMirror>(
+ () => newInstance(
+ constructorName, positionalArguments, namedArguments));
+ }
+
+ DeclarationMirror get owner {
+ if (_owner == null) {
+ if (_jsConstructor is Interceptor) {
+ _owner = reflectType(Object).owner;
+ } else {
+ for (var list in JsMirrorSystem.librariesByName.values) {
+ for (JsLibraryMirror library in list) {
+ // This will set _owner field on all clasess as a side
+ // effect. This gives us a fast path to reflect on a
+ // class without parsing reflection data.
+ library.classes;
+ }
+ }
+ }
+ if (_owner == null) {
+ throw new StateError('Class "${n(simpleName)}" has no owner');
+ }
+ }
+ return _owner;
+ }
+
+ List<InstanceMirror> get metadata {
+ if (_metadata == null) {
+ var metadataFunction = JS('', '#.prototype["@"]', _jsConstructor);
+ _metadata = (metadataFunction == null)
+ ? const [] : JS('', '#()', metadataFunction);
+ }
+ return _metadata.map(reflect).toList();
+ }
+
+ String toString() => 'ClassMirror(${n(simpleName)})';
+}
+
+class JsVariableMirror implements VariableMirror {
+ // TODO(ahe): The values in these fields are virtually untested.
+ final Symbol simpleName;
+ final String _jsName;
+ final bool _readOnly;
+ DeclarationMirror _owner;
+
+ JsVariableMirror(this.simpleName, this._jsName, this._readOnly);
+
+ factory JsVariableMirror.from(String descriptor) {
+ int length = descriptor.length;
+ var code = fieldCode(descriptor.codeUnitAt(length - 1));
+ if (code == 0) {
+ throw new RuntimeError('Bad field descriptor: $descriptor');
+ }
+ bool hasGetter = (code & 3) != 0;
+ bool hasSetter = (code >> 2) != 0;
+ String jsName;
+ String accessorName = jsName = descriptor.substring(0, length - 1);
+ int divider = descriptor.indexOf(":");
+ if (divider > 0) {
+ accessorName = accessorName.substring(0, divider);
+ jsName = accessorName.substring(divider + 1);
+ }
+ bool readOnly = !hasSetter;
+ return new JsVariableMirror(s(accessorName), jsName, readOnly);
+ }
+
+ TypeMirror get type => JsMirrorSystem._dynamicType;
+
+ DeclarationMirror get owner => _owner;
+
+ Symbol get qualifiedName => computeQualifiedName(owner, simpleName);
+
+ static int fieldCode(int code) {
+ if (code >= 60 && code <= 64) return code - 59;
+ if (code >= 123 && code <= 126) return code - 117;
+ if (code >= 37 && code <= 43) return code - 27;
+ return 0;
+ }
+}
+
+class JsClosureMirror extends JsInstanceMirror implements ClosureMirror {
+ JsClosureMirror(reflectee) : super(reflectee);
+
+ MethodMirror get function {
+ // TODO(ahe): What about optional parameters (named or not).
+ var extractCallName = JS('', r'''
+function(reflectee) {
+ for (var property in reflectee) {
+ if ("call$" == property.substring(0, 5)) return property;
+ }
+ return null;
+}
+''');
+ String callName = JS('String|Null', '#(#)', extractCallName, reflectee);
+ if (callName == null) {
+ throw new RuntimeError('Cannot find callName on "$reflectee"');
+ }
+ var jsFunction = JS('', '#[#]', reflectee, callName);
+ int parameterCount = int.parse(callName.split(r'$')[1]);
+ return new JsMethodMirror(s(callName), jsFunction, parameterCount);
+ }
+
+ InstanceMirror apply(List positionalArguments,
+ [Map<Symbol, dynamic> namedArguments]) {
+ return reflect(
+ Function.apply(reflectee, positionalArguments, namedArguments));
+ }
+
+ Future<InstanceMirror> applyAsync(List positionalArguments,
+ [Map<Symbol, dynamic> namedArguments]) {
+ return new Future<InstanceMirror>(
+ () => apply(positionalArguments, namedArguments));
+ }
+}
+
+class JsMethodMirror implements MethodMirror {
+ final Symbol simpleName;
+ final _jsFunction;
+ final int _parameterCount;
+ DeclarationMirror _owner;
+
+ JsMethodMirror(this.simpleName, this._jsFunction, this._parameterCount);
+
+ List<ParameterMirror> get parameters {
+ // TODO(ahe): Fill the list with parameter mirrors.
+ return new List<ParameterMirror>(_parameterCount);
+ }
+
+ DeclarationMirror get owner => _owner;
+
+ Symbol get qualifiedName => computeQualifiedName(owner, simpleName);
+}
+
+Symbol computeQualifiedName(DeclarationMirror owner, Symbol simpleName) {
+ if (owner == null) return simpleName;
+ String ownerName = n(owner.qualifiedName);
+ if (ownerName == '') return simpleName;
+ return s('$ownerName.${n(simpleName)}');
+}
diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_rti.dart b/sdk/lib/_internal/compiler/implementation/lib/js_rti.dart
index 721f38f..0cd37e1 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/js_rti.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/js_rti.dart
@@ -119,7 +119,7 @@
* against.
*/
bool checkSubtype(Object object, String isField, List checks, String asField) {
- if (object == null) return true;
+ if (object == null) return false;
var arguments = getRuntimeTypeInfo(object);
// Interceptor is needed for JSArray and native classes.
// TODO(sra): It could be a more specialized interceptor since [object] is not
@@ -143,7 +143,7 @@
}
Object subtypeCast(Object object, String isField, List checks, String asField) {
- if (!checkSubtype(object, isField, checks, asField)) {
+ if (object != null && !checkSubtype(object, isField, checks, asField)) {
String actualType = Primitives.objectTypeName(object);
String typeName = computeTypeName(isField, checks);
throw new CastErrorImplementation(object, typeName);
@@ -153,7 +153,7 @@
Object assertSubtype(Object object, String isField, List checks,
String asField) {
- if (!checkSubtype(object, isField, checks, asField)) {
+ if (object != null && !checkSubtype(object, isField, checks, asField)) {
String typeName = computeTypeName(isField, checks);
throw new TypeErrorImplementation(object, typeName);
}
@@ -195,13 +195,19 @@
getField(var object, var name) => JS('var', r'#[#]', object, name);
+bool isSubtypeOfNull(type) {
+ // `null` means `dynamic`.
+ return type == null || getConstructorName(type) == JS_OBJECT_CLASS_NAME();
+}
+
/**
* Tests whether the Dart object [o] is a subtype of the runtime type
* representation [t], which is a type representation as described in the
* comment on [isSubtype].
*/
bool checkSubtypeOfRuntimeType(Object o, var t) {
- if (JS('bool', '# == null', o) || JS('bool', '# == null', t)) return true;
+ if (JS('bool', '# == null', o)) return isSubtypeOfNull(t);
+ if (JS('bool', '# == null', t)) return true;
// Get the runtime type information from the object here, because we may
// overwrite o with the interceptor below.
var rti = getRuntimeTypeInfo(o);
@@ -224,7 +230,7 @@
}
Object subtypeOfRuntimeTypeCast(Object object, var type) {
- if (!checkSubtypeOfRuntimeType(object, type)) {
+ if (object != null && !checkSubtypeOfRuntimeType(object, type)) {
String actualType = Primitives.objectTypeName(object);
throw new CastErrorImplementation(actualType, runtimeTypeToString(type));
}
@@ -232,7 +238,7 @@
}
Object assertSubtypeOfRuntimeType(Object object, var type) {
- if (!checkSubtypeOfRuntimeType(object, type)) {
+ if (object != null && !checkSubtypeOfRuntimeType(object, type)) {
throw new TypeErrorImplementation(object, runtimeTypeToString(type));
}
return object;
diff --git a/sdk/lib/_internal/compiler/implementation/lib/mirrors_patch.dart b/sdk/lib/_internal/compiler/implementation/lib/mirrors_patch.dart
index ffcef0a..2fddaef 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/mirrors_patch.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/mirrors_patch.dart
@@ -4,463 +4,18 @@
// Patch library for dart:mirrors.
-import 'dart:_foreign_helper' show JS;
-import 'dart:_collection-dev' as _symbol_dev;
-import 'dart:_js_helper' show createInvocationMirror;
-import 'dart:_interceptors' show Interceptor;
+import 'dart:_js_mirrors' as js;
patch class MirrorSystem {
- patch static String getName(Symbol symbol) => _n(symbol);
+ patch static String getName(Symbol symbol) => js.getName(symbol);
}
-class _MirrorSystem implements MirrorSystem {
- TypeMirror get dynamicType => _dynamicType;
- TypeMirror get voidType => _voidType;
-
- final static TypeMirror _dynamicType =
- new _TypeMirror(const Symbol('dynamic'));
- final static TypeMirror _voidType = new _TypeMirror(const Symbol('void'));
-
- static final Map<String, List<LibraryMirror>> librariesByName =
- computeLibrariesByName();
-
- Iterable<LibraryMirror> findLibrary(Symbol libraryName) {
- return new List<LibraryMirror>.from(librariesByName[_n(libraryName)]);
- }
-
- static Map<String, List<LibraryMirror>> computeLibrariesByName() {
- var result = new Map<String, List<LibraryMirror>>();
- var jsLibraries = JS('=List|Null', 'init.libraries');
- if (jsLibraries == null) return result;
- for (List data in jsLibraries) {
- String name = data[0];
- Uri uri = Uri.parse(data[1]);
- List<String> classes = data[2];
- List<String> functions = data[3];
- var libraries = result.putIfAbsent(name, () => <LibraryMirror>[]);
- libraries.add(new _LibraryMirror(_s(name), uri, classes, functions));
- }
- return result;
- }
-}
-
-class _TypeMirror implements TypeMirror {
- final Symbol simpleName;
- _TypeMirror(this.simpleName);
-}
-
-class _LibraryMirror extends _ObjectMirror implements LibraryMirror {
- final Symbol simpleName;
- final Uri uri;
- final List<String> _classes;
- final List<String> _functions;
-
- _LibraryMirror(this.simpleName, this.uri, this._classes, this._functions);
-
- Symbol get qualifiedName => simpleName;
-
- Map<Symbol, ClassMirror> get classes {
- var result = new Map<Symbol, ClassMirror>();
- for (int i = 0; i < _classes.length; i += 2) {
- Symbol symbol = _s(_classes[i]);
- _ClassMirror cls = _reflectClass(symbol, _classes[i + 1]);
- result[symbol] = cls;
- cls._owner = this;
- }
- return result;
- }
-
- InstanceMirror setField(Symbol fieldName, Object arg) {
- // TODO(ahe): This is extremely dangerous!!!
- JS('void', r'$[#] = #', _n(fieldName), arg);
- return _reflect(arg);
- }
-
- InstanceMirror getField(Symbol fieldName) {
- // TODO(ahe): This is extremely dangerous!!!
- return _reflect(JS('', r'$[#]', _n(fieldName)));
- }
-
- Map<Symbol, MethodMirror> get functions {
- var result = new Map<Symbol, MethodMirror>();
- for (int i = 0; i < _functions.length; i++) {
- String name = _functions[i];
- Symbol symbol = _s(name);
- int parameterCount = null; // TODO(ahe): Compute this.
- _MethodMirror mirror =
- // TODO(ahe): Create accessor for accessing $. It is also
- // used in js_helper.
- new _MethodMirror(symbol, JS('', r'$[#]', name), parameterCount);
- // TODO(ahe): Cache mirrors.
- result[symbol] = mirror;
- mirror._owner = this;
- }
- return result;
- }
-
- Map<Symbol, MethodMirror> get getters {
- var result = new Map<Symbol, MethodMirror>();
- // TODO(ahe): Implement this.
- return result;
- }
-
- Map<Symbol, MethodMirror> get setters {
- var result = new Map<Symbol, MethodMirror>();
- // TODO(ahe): Implement this.
- return result;
- }
-
- Map<Symbol, VariableMirror> get variables {
- var result = new Map<Symbol, VariableMirror>();
- // TODO(ahe): Implement this.
- return result;
- }
-
- Map<Symbol, Mirror> get members {
- Map<Symbol, Mirror> result = new Map<Symbol, Mirror>.from(classes);
- addToResult(Symbol key, Mirror value) {
- result[key] = value;
- }
- functions.forEach(addToResult);
- getters.forEach(addToResult);
- setters.forEach(addToResult);
- variables.forEach(addToResult);
- return result;
- }
-}
-
-String _n(Symbol symbol) => _symbol_dev.Symbol.getName(symbol);
-
-Symbol _s(String name) {
- if (name == null) return null;
- return new _symbol_dev.Symbol.unvalidated(name);
-}
-
-patch MirrorSystem currentMirrorSystem() => _currentMirrorSystem;
-
-final _MirrorSystem _currentMirrorSystem = new _MirrorSystem();
+patch MirrorSystem currentMirrorSystem() => js.currentJsMirrorSystem;
patch Future<MirrorSystem> mirrorSystemOf(SendPort port) {
throw new UnsupportedError("MirrorSystem not implemented");
}
-// TODO(ahe): This is a workaround for http://dartbug.com/10543
-patch InstanceMirror reflect(Object reflectee) => _reflect(reflectee);
+patch InstanceMirror reflect(Object reflectee) => js.reflect(reflectee);
-InstanceMirror _reflect(Object reflectee) {
- if (reflectee is Closure) {
- return new _ClosureMirror(reflectee);
- } else {
- return new _InstanceMirror(reflectee);
- }
-}
-
-final Expando<ClassMirror> _classMirrors = new Expando<ClassMirror>();
-
-patch ClassMirror reflectClass(Type key) => __reflectClass(key);
-
-// TODO(ahe): This is a workaround for http://dartbug.com/10543
-ClassMirror __reflectClass(Type key) => _reflectClass(_s('$key'), null);
-
-ClassMirror _reflectClass(Symbol symbol, String fields) {
- String className = _n(symbol);
- var constructor = Primitives.getConstructor(className);
- if (constructor == null) {
- // Probably an intercepted class.
- // TODO(ahe): How to handle intercepted classes?
- throw new UnsupportedError('Cannot find class for: $className');
- }
- var mirror = _classMirrors[constructor];
- if (mirror == null) {
- mirror = new _ClassMirror(symbol, constructor, fields);
- _classMirrors[constructor] = mirror;
- }
- return mirror;
-}
-
-abstract class _ObjectMirror implements ObjectMirror {
- Future<InstanceMirror> setFieldAsync(Symbol fieldName, Object value) {
- return new Future<InstanceMirror>(() => this.setField(fieldName, value));
- }
-
- Future<InstanceMirror> getFieldAsync(Symbol fieldName) {
- return new Future<InstanceMirror>(() => this.getField(fieldName));
- }
-}
-
-class _InstanceMirror extends _ObjectMirror implements InstanceMirror {
- final reflectee;
-
- _InstanceMirror(this.reflectee);
-
- bool get hasReflectee => true;
-
- ClassMirror get type => __reflectClass(reflectee.runtimeType);
-
- Future<InstanceMirror> invokeAsync(Symbol memberName,
- List<Object> positionalArguments,
- [Map<String,Object> namedArguments]) {
- if (namedArguments != null && !namedArguments.isEmpty) {
- throw new UnsupportedError('Named arguments are not implemented');
- }
- return
- new Future<InstanceMirror>(
- () => invoke(memberName, positionalArguments, namedArguments));
- }
-
- InstanceMirror invoke(Symbol memberName,
- List positionalArguments,
- [Map<Symbol,dynamic> namedArguments]) {
- if (namedArguments != null && !namedArguments.isEmpty) {
- throw new UnsupportedError('Named arguments are not implemented');
- }
- // Copy the list to ensure that it can safely be passed to
- // JavaScript.
- var jsList = new List.from(positionalArguments);
- return _invoke(
- memberName, JSInvocationMirror.METHOD,
- '${_n(memberName)}\$${positionalArguments.length}', jsList);
- }
-
- InstanceMirror _invoke(Symbol name,
- int type,
- String mangledName,
- List arguments) {
- // TODO(ahe): Get the argument names.
- List<String> argumentNames = [];
- Invocation invocation = createInvocationMirror(
- _n(name), mangledName, type, arguments, argumentNames);
-
- return _reflect(delegate(invocation));
- }
-
- InstanceMirror setField(Symbol fieldName, Object arg) {
- _invoke(
- fieldName, JSInvocationMirror.SETTER, 'set\$${_n(fieldName)}', [arg]);
- return _reflect(arg);
- }
-
- InstanceMirror getField(Symbol fieldName) {
- return _invoke(
- fieldName, JSInvocationMirror.GETTER, 'get\$${_n(fieldName)}', []);
- }
-
- delegate(Invocation invocation) {
- return JSInvocationMirror.invokeFromMirror(invocation, reflectee);
- }
-
- String toString() => 'InstanceMirror($reflectee)';
-}
-
-class _ClassMirror extends _ObjectMirror implements ClassMirror {
- final Symbol simpleName;
- final _jsConstructor;
- final String _fields;
- // Set as side-effect of accessing _LibraryMirror.classes.
- _LibraryMirror _owner;
-
- _ClassMirror(this.simpleName, this._jsConstructor, this._fields);
-
- Symbol get qualifiedName => _computeQualifiedName(owner, simpleName);
-
- Map<Symbol, MethodMirror> get functions {
- var result = new Map<Symbol, MethodMirror>();
- // TODO(ahe): Implement this.
- return result;
- }
-
- Map<Symbol, MethodMirror> get getters {
- var result = new Map<Symbol, MethodMirror>();
- // TODO(ahe): Implement this.
- return result;
- }
-
- Map<Symbol, MethodMirror> get setters {
- var result = new Map<Symbol, MethodMirror>();
- // TODO(ahe): Implement this.
- return result;
- }
-
- Map<Symbol, VariableMirror> get variables {
- var result = new Map<Symbol, VariableMirror>();
- var s = _fields.split(";");
- var fields = s[1] == "" ? [] : s[1].split(",");
- for (String field in fields) {
- _VariableMirror mirror = new _VariableMirror.from(field);
- result[mirror.simpleName] = mirror;
- mirror._owner = this;
- }
- return result;
- }
-
- Map<Symbol, Mirror> get members {
- Map<Symbol, Mirror> result = new Map<Symbol, Mirror>.from(functions);
- addToResult(Symbol key, Mirror value) {
- result[key] = value;
- }
- getters.forEach(addToResult);
- setters.forEach(addToResult);
- variables.forEach(addToResult);
- return result;
- }
-
- InstanceMirror setField(Symbol fieldName, Object arg) {
- // TODO(ahe): This is extremely dangerous!!!
- JS('void', r'$[#] = #', '${_n(simpleName)}_${_n(fieldName)}', arg);
- return _reflect(arg);
- }
-
- InstanceMirror getField(Symbol fieldName) {
- // TODO(ahe): This is extremely dangerous!!!
- return _reflect(
- JS('', r'$[#]', '${_n(simpleName)}_${_n(fieldName)}'));
- }
-
- InstanceMirror newInstance(Symbol constructorName,
- List positionalArguments,
- [Map<Symbol,dynamic> namedArguments]) {
- if (namedArguments != null && !namedArguments.isEmpty) {
- throw new UnsupportedError('Named arguments are not implemented');
- }
- String constructorName = '${_n(simpleName)}\$${_n(constructorName)}';
- return _reflect(JS('', r'$[#].apply($, #)', constructorName,
- new List.from(positionalArguments)));
- }
-
- Future<InstanceMirror> newInstanceAsync(
- Symbol constructorName,
- List positionalArguments,
- [Map<Symbol, dynamic> namedArguments]) {
- if (namedArguments != null && !namedArguments.isEmpty) {
- throw new UnsupportedError('Named arguments are not implemented');
- }
- return new Future<InstanceMirror>(
- () => newInstance(
- constructorName, positionalArguments, namedArguments));
- }
-
- DeclarationMirror get owner {
- if (_owner == null) {
- if (_jsConstructor is Interceptor) {
- _owner = __reflectClass(Object).owner;
- } else {
- for (var list in _MirrorSystem.librariesByName.values) {
- for (_LibraryMirror library in list) {
- // This will set _owner field on all clasess as a side
- // effect. This gives us a fast path to reflect on a
- // class without parsing reflection data.
- library.classes;
- }
- }
- }
- if (_owner == null) {
- throw new StateError('Class "${_n(simpleName)}" has no owner');
- }
- }
- return _owner;
- }
-
- String toString() => 'ClassMirror(${_n(simpleName)})';
-}
-
-class _VariableMirror implements VariableMirror {
- // TODO(ahe): The values in these fields are virtually untested.
- final Symbol simpleName;
- final String _jsName;
- final bool _readOnly;
- DeclarationMirror _owner;
-
- _VariableMirror(this.simpleName, this._jsName, this._readOnly);
-
- factory _VariableMirror.from(String descriptor) {
- int length = descriptor.length;
- var code = fieldCode(descriptor.codeUnitAt(length - 1));
- if (code == 0) {
- throw new RuntimeError('Bad field descriptor: $descriptor');
- }
- bool hasGetter = (code & 3) != 0;
- bool hasSetter = (code >> 2) != 0;
- String jsName;
- String accessorName = jsName = descriptor.substring(0, length - 1);
- int divider = descriptor.indexOf(":");
- if (divider > 0) {
- accessorName = accessorName.substring(0, divider);
- jsName = accessorName.substring(divider + 1);
- }
- bool readOnly = !hasSetter;
- return new _VariableMirror(_s(accessorName), jsName, readOnly);
- }
-
- TypeMirror get type => _MirrorSystem._dynamicType;
-
- DeclarationMirror get owner => _owner;
-
- Symbol get qualifiedName => _computeQualifiedName(owner, simpleName);
-
- static int fieldCode(int code) {
- if (code >= 60 && code <= 64) return code - 59;
- if (code >= 123 && code <= 126) return code - 117;
- if (code >= 37 && code <= 43) return code - 27;
- return 0;
- }
-}
-
-class _ClosureMirror extends _InstanceMirror implements ClosureMirror {
- _ClosureMirror(reflectee) : super(reflectee);
-
- MethodMirror get function {
- // TODO(ahe): What about optional parameters (named or not).
- var extractCallName = JS('', r'''
-function(reflectee) {
- for (var property in reflectee) {
- if ("call$" == property.substring(0, 5)) return property;
- }
- return null;
-}
-''');
- String callName = JS('String|Null', '#(#)', extractCallName, reflectee);
- if (callName == null) {
- throw new RuntimeError('Cannot find callName on "$reflectee"');
- }
- var jsFunction = JS('', '#[#]', reflectee, callName);
- int parameterCount = int.parse(callName.split(r'$')[1]);
- return new _MethodMirror(_s(callName), jsFunction, parameterCount);
- }
-
- InstanceMirror apply(List positionalArguments,
- [Map<Symbol, dynamic> namedArguments]) {
- return _reflect(
- Function.apply(reflectee, positionalArguments, namedArguments));
- }
-
- Future<InstanceMirror> applyAsync(List positionalArguments,
- [Map<Symbol, dynamic> namedArguments]) {
- return new Future<InstanceMirror>(
- () => apply(positionalArguments, namedArguments));
- }
-}
-
-class _MethodMirror implements MethodMirror {
- final Symbol simpleName;
- final _jsFunction;
- final int _parameterCount;
- DeclarationMirror _owner;
-
- _MethodMirror(this.simpleName, this._jsFunction, this._parameterCount);
-
- List<ParameterMirror> get parameters {
- // TODO(ahe): Fill the list with parameter mirrors.
- return new List<ParameterMirror>(_parameterCount);
- }
-
- DeclarationMirror get owner => _owner;
-
- Symbol get qualifiedName => _computeQualifiedName(owner, simpleName);
-}
-
-Symbol _computeQualifiedName(DeclarationMirror owner, Symbol simpleName) {
- if (owner == null) return simpleName;
- String ownerName = _n(owner.qualifiedName);
- if (ownerName == '') return simpleName;
- return _s('$ownerName.${_n(simpleName)}');
-}
+patch ClassMirror reflectClass(Type key) => js.reflectType(key);
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/members.dart b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
index ae787be..6e2eb36 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/members.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
@@ -106,10 +106,10 @@
return selectors[node.assignmentOperator];
}
- // The following methods set selectors on the "for in" node. Since
- // we're using three selectors, we need to use children of the node,
- // and we arbitrarily choose which ones.
-
+ // The following methods set selectors on the "for in" node. Since
+ // we're using three selectors, we need to use children of the node,
+ // and we arbitrarily choose which ones.
+
Selector setIteratorSelector(ForIn node, Selector selector) {
selectors[node] = selector;
}
@@ -121,7 +121,7 @@
Selector setMoveNextSelector(ForIn node, Selector selector) {
selectors[node.forToken] = selector;
}
-
+
Selector getMoveNextSelector(ForIn node) {
return selectors[node.forToken];
}
@@ -602,6 +602,14 @@
ClassElement mixin = mixinApplication.mixin;
if (mixin == null) return;
+ // Check that we're not trying to use Object as a mixin.
+ if (mixin.superclass == null) {
+ compiler.reportErrorCode(mixinApplication,
+ MessageKind.ILLEGAL_MIXIN_OBJECT);
+ // Avoid reporting additional errors for the Object class.
+ return;
+ }
+
// Check that the mixed in class has Object as its superclass.
if (!mixin.superclass.isObject(compiler)) {
compiler.reportErrorCode(mixin, MessageKind.ILLEGAL_MIXIN_SUPERCLASS);
@@ -962,8 +970,12 @@
annotation.resolutionState = STATE_STARTED;
Node node = annotation.parseNode(compiler);
- ResolverVisitor visitor =
- visitorFor(annotation.annotatedElement.enclosingElement);
+ Element annotatedElement = annotation.annotatedElement;
+ Element context = annotatedElement.enclosingElement;
+ if (context == null) {
+ context = annotatedElement;
+ }
+ ResolverVisitor visitor = visitorFor(context);
node.accept(visitor);
annotation.value = compiler.metadataHandler.compileNodeWithDefinitions(
node, visitor.mapping, isConst: true);
@@ -2307,9 +2319,8 @@
// unqualified.
useElement(node, target);
registerSend(selector, target);
- if (node.isPropertyAccess) {
- // It might be the closurization of a method.
- world.registerInstantiatedClass(compiler.functionClass, mapping);
+ if (node.isPropertyAccess && Elements.isStaticOrTopLevelFunction(target)) {
+ world.registerGetOfStaticFunction(target.declaration);
}
return node.isPropertyAccess ? target : null;
}
@@ -2491,11 +2502,7 @@
compiler.reportErrorCode(
enclosingElement, MessageKind.MISSING_FACTORY_KEYWORD);
}
- Element redirectionTarget = resolveRedirectingFactory(node);
- var type = mapping.getType(node.expression);
- if (type is InterfaceType && !type.isRaw) {
- unimplemented(node.expression, 'type arguments on redirecting factory');
- }
+ FunctionElement redirectionTarget = resolveRedirectingFactory(node);
useElement(node.expression, redirectionTarget);
FunctionElement constructor = enclosingElement;
if (constructor.modifiers.isConst() &&
@@ -2503,7 +2510,36 @@
error(node, MessageKind.CONSTRUCTOR_IS_NOT_CONST);
}
constructor.defaultImplementation = redirectionTarget;
- if (Elements.isUnresolved(redirectionTarget)) return;
+ if (Elements.isUnresolved(redirectionTarget)) {
+ compiler.backend.registerThrowNoSuchMethod(mapping);
+ return;
+ }
+
+ // Compute the signature of the target method taking into account the
+ // type arguments that are specified in the redirection, and store it on
+ // the return node.
+ ClassElement targetClass = redirectionTarget.getEnclosingClass();
+ InterfaceType type = mapping.getType(node.expression)
+ .subst(currentClass.typeVariables, targetClass.typeVariables);
+ mapping.setType(node, type);
+
+ // Check that the target constructor is type compatible with the
+ // redirecting constructor.
+ FunctionType targetType = redirectionTarget.computeType(compiler)
+ .subst(type.typeArguments, targetClass.typeVariables);
+ FunctionType constructorType = constructor.computeType(compiler);
+ if (!compiler.types.isSubtype(targetType, constructorType)) {
+ warning(node, MessageKind.NOT_ASSIGNABLE,
+ {'fromType': targetType, 'toType': constructorType});
+ }
+
+ FunctionSignature targetSignature =
+ redirectionTarget.computeSignature(compiler);
+ FunctionSignature constructorSignature =
+ constructor.computeSignature(compiler);
+ if (!targetSignature.isCompatibleWith(constructorSignature)) {
+ compiler.backend.registerThrowNoSuchMethod(mapping);
+ }
// TODO(ahe): Check that this doesn't lead to a cycle. For now,
// just make sure that the redirection target isn't itself a
@@ -2513,7 +2549,7 @@
FunctionExpression function = targetImplementation.parseNode(compiler);
if (function.body != null && function.body.asReturn() != null
&& function.body.asReturn().isRedirectingFactoryBody) {
- unimplemented(node.expression, 'redirecing to redirecting factory');
+ unimplemented(node.expression, 'redirecting to redirecting factory');
}
}
world.registerStaticUse(redirectionTarget);
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/listener.dart b/sdk/lib/_internal/compiler/implementation/scanner/listener.dart
index 5c3243a..17f790c 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/listener.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/listener.dart
@@ -1033,9 +1033,11 @@
}
Link<MetadataAnnotation> popMetadata(Element element) {
- var result = metadata;
+ var result = const Link<MetadataAnnotation>();
for (Link link = metadata; !link.isEmpty; link = link.tail) {
element.addMetadata(link.head);
+ // Reverse the list as is implicitly done by addMetadata.
+ result = result.prepend(link.head);
}
metadata = const Link<MetadataAnnotation>();
return result;
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/bailout.dart b/sdk/lib/_internal/compiler/implementation/ssa/bailout.dart
index c22a52c..b9db4c4 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/bailout.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/bailout.dart
@@ -181,7 +181,7 @@
bool isIndexOperatorOnIndexablePrimitive(instruction) {
return instruction is HIndex
|| (instruction is HInvokeDynamicMethod
- && instruction.isIndexOperatorOnIndexablePrimitive());
+ && instruction.isIndexOperatorOnIndexablePrimitive(compiler));
}
// To speed up computations on values loaded from arrays, we
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
index 6f4cd16..76e92c0 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
@@ -67,8 +67,7 @@
index++;
});
} else {
- // TODO(ahe): I have disabled type optimizations for
- // optional arguments as the types are stored in the wrong
+ // BUG(10938): the types are stored in the wrong order.
// order.
HTypeList parameterTypes =
backend.optimisticParameterTypes(element.declaration,
@@ -2632,7 +2631,8 @@
// creating an [HStatic].
push(new HStatic(element.declaration));
// TODO(ahe): This should be registered in codegen.
- compiler.enqueuer.codegen.registerGetOfStaticFunction(element);
+ compiler.enqueuer.codegen.registerGetOfStaticFunction(
+ element.declaration);
} else if (Elements.isErroneousElement(element)) {
// An erroneous element indicates an unresolved static getter.
generateThrowNoSuchMethod(send,
@@ -2973,10 +2973,10 @@
return;
}
- void handleForeignJsCurrentIsolate(Send node) {
+ void handleForeignJsCurrentIsolateContext(Send node) {
if (!node.arguments.isEmpty) {
compiler.cancel(
- 'Too many arguments to JS_CURRENT_ISOLATE', node: node);
+ 'Too many arguments to JS_CURRENT_ISOLATE_CONTEXT', node: node);
}
if (!compiler.hasIsolateSupport()) {
@@ -3095,13 +3095,22 @@
<HInstruction>[]));
}
+ void handleForeignJsCurrentIsolate(Send node) {
+ if (!node.arguments.isEmpty) {
+ compiler.cancel('Too many arguments', node: node.argumentsNode);
+ }
+ push(new HForeign(new js.LiteralString(backend.namer.CURRENT_ISOLATE),
+ HType.UNKNOWN,
+ <HInstruction>[]));
+ }
+
visitForeignSend(Send node) {
Selector selector = elements.getSelector(node);
SourceString name = selector.name;
if (name == const SourceString('JS')) {
handleForeignJs(node);
- } else if (name == const SourceString('JS_CURRENT_ISOLATE')) {
- handleForeignJsCurrentIsolate(node);
+ } else if (name == const SourceString('JS_CURRENT_ISOLATE_CONTEXT')) {
+ handleForeignJsCurrentIsolateContext(node);
} else if (name == const SourceString('JS_CALL_IN_ISOLATE')) {
handleForeignJsCallInIsolate(node);
} else if (name == const SourceString('DART_CLOSURE_TO_JS')) {
@@ -3114,6 +3123,9 @@
handleForeignCreateIsolate(node);
} else if (name == const SourceString('JS_OPERATOR_IS_PREFIX')) {
stack.add(addConstantString(node, backend.namer.operatorIsPrefix()));
+ } else if (name == const SourceString('JS_OBJECT_CLASS_NAME')) {
+ String name = backend.namer.getRuntimeTypeName(compiler.objectClass);
+ stack.add(addConstantString(node, name));
} else if (name == const SourceString('JS_OPERATOR_AS_PREFIX')) {
stack.add(addConstantString(node, backend.namer.operatorAsPrefix()));
} else if (name == const SourceString('JS_DART_OBJECT_CONSTRUCTOR')) {
@@ -3122,6 +3134,8 @@
Element element = compiler.findHelper(
const SourceString('JavaScriptIndexingBehavior'));
stack.add(addConstantString(node, backend.namer.operatorIs(element)));
+ } else if (name == const SourceString('JS_CURRENT_ISOLATE')) {
+ handleForeignJsCurrentIsolate(node);
} else {
throw "Unknown foreign: ${selector}";
}
@@ -3376,6 +3390,7 @@
}
FunctionElement functionElement = constructor;
constructor = functionElement.redirectionTarget;
+
final bool isSymbolConstructor =
functionElement == compiler.symbolConstructor;
@@ -3388,6 +3403,23 @@
message: 'Constructor Symbol.validated is missing'));
}
+ bool isRedirected = functionElement.isRedirectingFactory;
+ DartType expectedType = type;
+ if (isRedirected) {
+ FunctionExpression functionNode = functionElement.parseNode(compiler);
+ if (functionNode.isRedirectingFactory) {
+ // Lookup the type used in the redirection.
+ Return redirectionNode = functionNode.body;
+ TreeElements treeElements =
+ compiler.enqueuer.resolution.getCachedElements(
+ functionElement.declaration);
+ ClassElement targetClass = functionElement.getEnclosingClass();
+ type = treeElements.getType(redirectionNode)
+ .subst(type.typeArguments, targetClass.typeVariables);
+ }
+ functionElement = functionElement.redirectionTarget;
+ }
+
var inputs = <HInstruction>[];
// TODO(5347): Try to avoid the need for calling [implementation] before
// calling [addStaticSendArgumentsToList].
@@ -3432,6 +3464,15 @@
if (isListConstructor && backend.needsRti(compiler.listClass)) {
handleListConstructor(type, send, newInstance);
}
+
+ // Finally, if we called a redirecting factory constructor, check the type.
+ if (isRedirected) {
+ HInstruction checked = potentiallyCheckType(newInstance, expectedType);
+ if (checked != newInstance) {
+ pop();
+ stack.add(checked);
+ }
+ }
}
visitStaticSend(Send node) {
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
index 120f91c..797bc85 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
@@ -2462,7 +2462,7 @@
// input is !string
checkString(input, '!==');
test = pop();
- } else if (node.isExtendableArray()) {
+ } else if (node.isExtendableArray(compiler)) {
// input is !Object || input is !Array || input.isFixed
checkObject(input, '!==');
js.Expression objectTest = pop();
@@ -2471,7 +2471,7 @@
checkFixedArray(input);
test = new js.Binary('||', objectTest, arrayTest);
test = new js.Binary('||', test, pop());
- } else if (node.isMutableArray()) {
+ } else if (node.isMutableArray(compiler)) {
// input is !Object
// || ((input is !Array || input.isImmutable)
// && input is !JsIndexingBehavior)
@@ -2484,7 +2484,7 @@
checkIndexingBehavior(input, negative: true);
js.Binary notIndexing = new js.Binary('&&', notArrayOrImmutable, pop());
test = new js.Binary('||', objectTest, notIndexing);
- } else if (node.isReadableArray()) {
+ } else if (node.isReadableArray(compiler)) {
// input is !Object
// || (input is !Array && input is !JsIndexingBehavior)
checkObject(input, '!==');
@@ -2494,7 +2494,7 @@
checkIndexingBehavior(input, negative: true);
js.Expression notIndexing = new js.Binary('&&', arrayTest, pop());
test = new js.Binary('||', objectTest, notIndexing);
- } else if (node.isIndexablePrimitive()) {
+ } else if (node.isIndexablePrimitive(compiler)) {
// input is !String
// && (input is !Object
// || (input is !Array && input is !JsIndexingBehavior))
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/interceptor_simplifier.dart b/sdk/lib/_internal/compiler/implementation/ssa/interceptor_simplifier.dart
index e3f7a46..9c7de35 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/interceptor_simplifier.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/interceptor_simplifier.dart
@@ -99,7 +99,7 @@
constantInterceptor = backend.jsBoolClass;
} else if (type.isString()) {
constantInterceptor = backend.jsStringClass;
- } else if (type.isArray()) {
+ } else if (type.isArray(compiler)) {
constantInterceptor = backend.jsArrayClass;
} else if (type.isNull()) {
constantInterceptor = backend.jsNullClass;
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 426332e..e27ae59 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/invoke_dynamic_specializers.dart
@@ -21,7 +21,18 @@
HType computeTypeFromInputTypes(HInvokeDynamic instruction,
Compiler compiler) {
- return HType.UNKNOWN;
+ HType receiverType = instruction.getDartReceiver(compiler).instructionType;
+ Selector refined = receiverType.refine(instruction.selector, compiler);
+ HType type = new HType.inferredTypeForSelector(refined, compiler);
+ // TODO(ngeoffray): Because we don't know yet the side effects of
+ // a JS call, we sometimes know more in the compiler about the
+ // side effects of an element (for example operator% on the int
+ // class). We should remove this check once we analyze JS calls.
+ if (!instruction.useGvn()) {
+ instruction.sideEffects =
+ compiler.world.getSideEffectsOfSelector(refined);
+ }
+ return type;
}
HInstruction tryConvertToBuiltin(HInvokeDynamic instruction,
@@ -171,8 +182,8 @@
Compiler compiler) {
// All bitwise operations on primitive types either produce an
// integer or throw an error.
- if (instruction.inputs[1].isPrimitive()) return HType.INTEGER;
- return HType.UNKNOWN;
+ if (instruction.inputs[1].isPrimitiveOrNull()) return HType.INTEGER;
+ return super.computeTypeFromInputTypes(instruction, compiler);
}
HInstruction tryConvertToBuiltin(HInvokeDynamic instruction,
@@ -207,8 +218,8 @@
HType computeTypeFromInputTypes(HInvokeDynamic instruction,
Compiler compiler) {
HType operandType = instruction.inputs[1].instructionType;
- if (operandType.isNumber()) return operandType;
- return HType.UNKNOWN;
+ if (operandType.isNumberOrNull()) return operandType;
+ return super.computeTypeFromInputTypes(instruction, compiler);
}
HInstruction tryConvertToBuiltin(HInvokeDynamic instruction,
@@ -226,12 +237,12 @@
Compiler compiler) {
HInstruction left = instruction.inputs[1];
HInstruction right = instruction.inputs[2];
- if (left.isInteger() && right.isInteger()) return HType.INTEGER;
- if (left.isNumber()) {
- if (left.isDouble() || right.isDouble()) return HType.DOUBLE;
+ if (left.isIntegerOrNull() && right.isIntegerOrNull()) return HType.INTEGER;
+ if (left.isNumberOrNull()) {
+ if (left.isDoubleOrNull() || right.isDoubleOrNull()) return HType.DOUBLE;
return HType.NUMBER;
}
- return HType.UNKNOWN;
+ return super.computeTypeFromInputTypes(instruction, compiler);
}
HType computeDesiredTypeForInput(HInvokeDynamic instruction,
@@ -308,8 +319,8 @@
HType computeTypeFromInputTypes(HInstruction instruction,
Compiler compiler) {
HInstruction left = instruction.inputs[1];
- if (left.isNumber()) return HType.DOUBLE;
- return HType.UNKNOWN;
+ if (left.isNumberOrNull()) return HType.DOUBLE;
+ return super.computeTypeFromInputTypes(instruction, compiler);
}
HType computeDesiredTypeForInput(HInstruction instruction,
@@ -388,8 +399,8 @@
// All bitwise operations on primitive types either produce an
// integer or throw an error.
HInstruction left = instruction.inputs[1];
- if (left.isPrimitive()) return HType.INTEGER;
- return HType.UNKNOWN;
+ if (left.isPrimitiveOrNull()) return HType.INTEGER;
+ return super.computeTypeFromInputTypes(instruction, compiler);
}
HType computeDesiredTypeForInput(HInvokeDynamic instruction,
@@ -494,7 +505,7 @@
if (instruction.inputs[1].instructionType.isPrimitiveOrNull()) {
return HType.BOOLEAN;
}
- return HType.UNKNOWN;
+ return super.computeTypeFromInputTypes(instruction, compiler);
}
HType computeDesiredTypeForInput(HInvokeDynamic instruction,
@@ -546,11 +557,11 @@
return right.instructionType;
}
// String equality testing is much more common than array equality testing.
- if (input == left && left.isIndexablePrimitive()) {
+ if (input == left && left.isIndexablePrimitive(compiler)) {
return HType.READABLE_ARRAY;
}
// String equality testing is much more common than array equality testing.
- if (input == right && right.isIndexablePrimitive()) {
+ if (input == right && right.isIndexablePrimitive(compiler)) {
return HType.STRING;
}
return HType.UNKNOWN;
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
index 757230d..4236ba1 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
@@ -826,18 +826,26 @@
bool isControlFlow() => false;
// All isFunctions work on the propagated types.
- bool isArray() => instructionType.isArray();
- bool isReadableArray() => instructionType.isReadableArray();
- bool isMutableArray() => instructionType.isMutableArray();
- bool isExtendableArray() => instructionType.isExtendableArray();
- bool isFixedArray() => instructionType.isFixedArray();
+ bool isArray(Compiler compiler) =>
+ instructionType.isArray(compiler);
+ bool isReadableArray(Compiler compiler) =>
+ instructionType.isReadableArray(compiler);
+ bool isMutableArray(Compiler compiler) =>
+ instructionType.isMutableArray(compiler);
+ bool isExtendableArray(Compiler compiler) =>
+ instructionType.isExtendableArray(compiler);
+ bool isFixedArray(Compiler compiler) =>
+ instructionType.isFixedArray(compiler);
bool isBoolean() => instructionType.isBoolean();
bool isInteger() => instructionType.isInteger();
+ bool isIntegerOrNull() => instructionType.isIntegerOrNull();
bool isDouble() => instructionType.isDouble();
+ bool isDoubleOrNull() => instructionType.isDoubleOrNull();
bool isNumber() => instructionType.isNumber();
bool isNumberOrNull() => instructionType.isNumberOrNull();
bool isString() => instructionType.isString();
bool isPrimitive() => instructionType.isPrimitive();
+ bool isPrimitiveOrNull() => instructionType.isPrimitiveOrNull();
bool isNull() => instructionType.isNull();
bool canBeNull() => instructionType.canBeNull();
bool canBePrimitive(Compiler compiler) =>
@@ -851,7 +859,8 @@
instructionType.isMutableIndexable(compiler);
// TODO(kasperl): Get rid of this one.
- bool isIndexablePrimitive() => instructionType.isIndexablePrimitive();
+ bool isIndexablePrimitive(Compiler compiler) =>
+ instructionType.isIndexablePrimitive(compiler);
/**
* Type of the unstruction.
@@ -1332,11 +1341,11 @@
String toString() => 'invoke dynamic method: $selector';
accept(HVisitor visitor) => visitor.visitInvokeDynamicMethod(this);
- bool isIndexOperatorOnIndexablePrimitive() {
+ bool isIndexOperatorOnIndexablePrimitive(Compiler compiler) {
return isInterceptedCall
&& selector.kind == SelectorKind.INDEX
&& selector.name == const SourceString('[]')
- && inputs[1].isIndexablePrimitive();
+ && inputs[1].isIndexablePrimitive(compiler);
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
index c803976..ffcab4d 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
@@ -245,7 +245,7 @@
return graph.addConstantInt(constant.length, constantSystem);
}
Element element = backend.jsIndexableLength;
- bool isAssignable = !actualReceiver.isFixedArray() &&
+ bool isAssignable = !actualReceiver.isFixedArray(compiler) &&
!actualReceiver.isString();
HFieldGet result = new HFieldGet(
element, actualReceiver, isAssignable: isAssignable);
@@ -279,7 +279,7 @@
if (selector.isCall()) {
Element target;
- if (input.isExtendableArray()) {
+ if (input.isExtendableArray(compiler)) {
if (selector.applies(backend.jsArrayRemoveLast, compiler)) {
target = backend.jsArrayRemoveLast;
} else if (selector.applies(backend.jsArrayAdd, compiler)) {
@@ -826,7 +826,8 @@
HBoundsCheck insertBoundsCheck(HInstruction indexNode,
HInstruction array,
HInstruction indexArgument) {
- bool isAssignable = !array.isFixedArray() && !array.isString();
+ bool isAssignable =
+ !array.isFixedArray(backend.compiler) && !array.isString();
HFieldGet length = new HFieldGet(
backend.jsIndexableLength, array, isAssignable: isAssignable);
length.instructionType = HType.INTEGER;
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/types.dart b/sdk/lib/_internal/compiler/implementation/ssa/types.dart
index d1d22bf..faf1f08 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/types.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/types.dart
@@ -180,12 +180,13 @@
bool isInteger() => false;
bool isDouble() => false;
bool isString() => false;
- bool isFixedArray() => false;
- bool isReadableArray() => false;
- bool isMutableArray() => false;
- bool isExtendableArray() => false;
- bool isPrimitive() => false;
+ bool isFixedArray(Compiler compiler) => false;
+ bool isReadableArray(Compiler compiler) => false;
+ bool isMutableArray(Compiler compiler) => false;
+ bool isExtendableArray(Compiler compiler) => false;
+
+ bool isPrimitive() => false;
bool isBooleanOrNull() => false;
bool isNumberOrNull() => false;
bool isIntegerOrNull() => false;
@@ -194,7 +195,7 @@
bool isPrimitiveOrNull() => false;
// TODO(kasperl): Get rid of this one.
- bool isIndexablePrimitive() => false;
+ bool isIndexablePrimitive(Compiler compiler) => false;
bool isIndexable(Compiler compiler) {
JavaScriptBackend backend = compiler.backend;
@@ -222,7 +223,7 @@
/** A type is useful it is not unknown, not conflicting, and not null. */
bool isUseful() => !isUnknown() && !isConflicting() && !isNull();
/** Alias for isReadableArray. */
- bool isArray() => isReadableArray();
+ bool isArray(Compiler compiler) => isReadableArray(compiler);
TypeMask computeMask(Compiler compiler);
@@ -457,7 +458,7 @@
class HIndexablePrimitiveType extends HPrimitiveType {
const HIndexablePrimitiveType();
- bool isIndexablePrimitive() => true;
+ bool isIndexablePrimitive(Compiler compiler) => true;
String toString() => "indexable";
TypeMask computeMask(Compiler compiler) {
@@ -497,7 +498,7 @@
class HReadableArrayType extends HIndexablePrimitiveType {
const HReadableArrayType();
- bool isReadableArray() => true;
+ bool isReadableArray(Compiler compiler) => true;
String toString() => "readable array";
bool canBePrimitiveArray(Compiler compiler) => true;
@@ -510,7 +511,7 @@
class HMutableArrayType extends HReadableArrayType {
const HMutableArrayType();
- bool isMutableArray() => true;
+ bool isMutableArray(Compiler compiler) => true;
String toString() => "mutable array";
TypeMask computeMask(Compiler compiler) {
@@ -522,7 +523,7 @@
class HFixedArrayType extends HMutableArrayType {
const HFixedArrayType();
- bool isFixedArray() => true;
+ bool isFixedArray(Compiler compiler) => true;
String toString() => "fixed array";
bool isExact() => true;
@@ -535,7 +536,7 @@
class HExtendableArrayType extends HMutableArrayType {
const HExtendableArrayType();
- bool isExtendableArray() => true;
+ bool isExtendableArray(Compiler compiler) => true;
String toString() => "extendable array";
bool isExact() => true;
@@ -587,6 +588,32 @@
|| mask.contains(jsExtendableArrayType, compiler);
}
+ bool isIndexablePrimitive(Compiler compiler) {
+ JavaScriptBackend backend = compiler.backend;
+ return mask.containsOnlyString(compiler)
+ || mask.satisfies(backend.jsIndexableClass, compiler);
+ }
+
+ bool isFixedArray(Compiler compiler) {
+ JavaScriptBackend backend = compiler.backend;
+ return mask.containsOnly(backend.jsFixedArrayClass);
+ }
+
+ bool isExtendableArray(Compiler compiler) {
+ JavaScriptBackend backend = compiler.backend;
+ return mask.containsOnly(backend.jsExtendableArrayClass);
+ }
+
+ bool isMutableArray(Compiler compiler) {
+ JavaScriptBackend backend = compiler.backend;
+ return mask.satisfies(backend.jsMutableArrayClass, compiler);
+ }
+
+ bool isReadableArray(Compiler compiler) {
+ JavaScriptBackend backend = compiler.backend;
+ return mask.satisfies(backend.jsArrayClass, compiler);
+ }
+
bool canBePrimitiveString(Compiler compiler) {
JavaScriptBackend backend = compiler.backend;
DartType jsStringType = backend.jsStringClass.computeType(compiler);
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart b/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart
index 9e85957..ab3ec41 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart
@@ -126,18 +126,6 @@
}
HType visitInvokeDynamic(HInvokeDynamic instruction) {
- HType receiverType = instruction.getDartReceiver(compiler).instructionType;
- Selector refined = receiverType.refine(instruction.selector, compiler);
- HType type = new HType.inferredTypeForSelector(refined, compiler);
- // TODO(ngeoffray): Because we don't know yet the side effects of
- // a JS call, we sometimes know more in the compiler about the
- // side effects of an element (for example operator% on the int
- // class). We should remove this check once we analyze JS calls.
- if (!instruction.useGvn()) {
- instruction.sideEffects =
- compiler.world.getSideEffectsOfSelector(refined);
- }
- if (type.isUseful()) return type;
return instruction.specializer.computeTypeFromInputTypes(
instruction, compiler);
}
diff --git a/sdk/lib/_internal/compiler/implementation/tree/nodes.dart b/sdk/lib/_internal/compiler/implementation/tree/nodes.dart
index a2216cd..9a3c43c 100644
--- a/sdk/lib/_internal/compiler/implementation/tree/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/tree/nodes.dart
@@ -702,6 +702,11 @@
accept(Visitor visitor) => visitor.visitFunctionExpression(this);
+ bool get isRedirectingFactory {
+ return body != null && body.asReturn() != null &&
+ body.asReturn().isRedirectingFactoryBody;
+ }
+
visitChildren(Visitor visitor) {
if (modifiers != null) modifiers.accept(visitor);
if (returnType != null) returnType.accept(visitor);
diff --git a/sdk/lib/_internal/compiler/implementation/typechecker.dart b/sdk/lib/_internal/compiler/implementation/typechecker.dart
index 6ab80fd..cdd5f8c 100644
--- a/sdk/lib/_internal/compiler/implementation/typechecker.dart
+++ b/sdk/lib/_internal/compiler/implementation/typechecker.dart
@@ -8,11 +8,15 @@
TypeCheckerTask(Compiler compiler) : super(compiler);
String get name => "Type checker";
- void check(Node tree, TreeElements elements) {
- measure(() {
- Visitor visitor =
- new TypeCheckerVisitor(compiler, elements, compiler.types);
- tree.accept(visitor);
+ void check(TreeElements elements) {
+ Element element = elements.currentElement;
+ compiler.withCurrentElement(element, () {
+ measure(() {
+ Node tree = element.parseNode(compiler);
+ Visitor visitor =
+ new TypeCheckerVisitor(compiler, elements, compiler.types);
+ tree.accept(visitor);
+ });
});
}
}
@@ -140,7 +144,7 @@
String toString() => 'TypeLiteralAccess($element)';
}
-class TypeCheckerVisitor implements Visitor<DartType> {
+class TypeCheckerVisitor extends Visitor<DartType> {
final Compiler compiler;
final TreeElements elements;
final Types types;
@@ -170,6 +174,8 @@
listType = compiler.listClass.computeType(compiler);
}
+ LibraryElement get currentLibrary => elements.currentElement.getLibrary();
+
reportTypeWarning(Node node, MessageKind kind, [Map arguments = const {}]) {
compiler.reportWarning(node, new TypeWarning(kind, arguments));
}
@@ -260,18 +266,6 @@
return type;
}
- DartType visitClassNode(ClassNode node) {
- compiler.internalError('unexpected node type', node: node);
- }
-
- DartType visitMixinApplication(MixinApplication node) {
- compiler.internalError('unexpected node type', node: node);
- }
-
- DartType visitNamedMixinApplication(NamedMixinApplication node) {
- compiler.internalError('unexpected node type', node: node);
- }
-
DartType visitDoWhile(DoWhile node) {
StatementType bodyType = analyze(node.body);
checkCondition(node.condition);
@@ -337,8 +331,19 @@
DartType visitIdentifier(Identifier node) {
if (node.isThis()) {
return currentClass.computeType(compiler);
+ } else if (node.isSuper()) {
+ return currentClass.supertype;
} else {
- // This is an identifier of a formal parameter.
+ Element element = elements[node];
+ if (element != null) {
+ assert(invariant(node, element.isVariable() || element.isParameter(),
+ message: 'Unexpected context element ${element}'));
+ return element.computeType(compiler);
+ }
+
+ assert(invariant(node, elements.currentElement.isField(),
+ message: 'Unexpected context element ${elements.currentElement}'));
+ // This is an identifier of a field declaration.
return types.dynamicType;
}
}
@@ -351,8 +356,17 @@
return thenType.join(elseType);
}
- DartType visitLoop(Loop node) {
- return unhandledStatement();
+ void checkPrivateAccess(Node node, Element element, SourceString name) {
+ if (name != null &&
+ name.isPrivate() &&
+ element.getLibrary() != currentLibrary) {
+ reportTypeWarning(
+ node,
+ MessageKind.PRIVATE_ACCESS,
+ {'name': name,
+ 'libraryName': element.getLibrary().getLibraryOrScriptName()});
+ }
+
}
ElementAccess lookupMember(Node node, DartType type, SourceString name,
@@ -362,6 +376,7 @@
}
Member member = type.lookupMember(name);
if (member != null) {
+ checkPrivateAccess(node, member.element, name);
return new MemberAccess(member);
}
switch (memberKind) {
@@ -547,12 +562,12 @@
name, memberKind);
} else if (element.isFunction()) {
// foo() where foo is a method in the same class.
- return new ResolvedAccess(element);
+ return createResolvedAccess(node, name, element);
} else if (element.isVariable() ||
element.isParameter() ||
element.isField()) {
// foo() where foo is a field in the same class.
- return new ResolvedAccess(element);
+ return createResolvedAccess(node, name, element);
} else if (element.impliesType()) {
// The literal `Foo` where Foo is a class, a typedef, or a type variable.
if (elements.getType(node) != null) {
@@ -562,15 +577,21 @@
'${elements.getType(node)}'));
return new TypeLiteralAccess(element);
}
- return new ResolvedAccess(element);
+ return createResolvedAccess(node, name, element);
} else if (element.isGetter() || element.isSetter()) {
- return new ResolvedAccess(element);
+ return createResolvedAccess(node, name, element);
} else {
compiler.internalErrorOnElement(
element, 'unexpected element kind ${element.kind}');
}
}
+ ElementAccess createResolvedAccess(Send node, SourceString name,
+ Element element) {
+ checkPrivateAccess(node, element, name);
+ return new ResolvedAccess(element);
+ }
+
/**
* Computes the type of the access of [name] on the [node] possibly using the
* [element] provided for [node] by the resolver.
@@ -896,6 +917,12 @@
DartType visitNewExpression(NewExpression node) {
Element element = elements[node.send];
+ if (Elements.isUnresolved(element)) return types.dynamicType;
+
+ ClassElement enclosingClass = element.getEnclosingClass();
+ SourceString name = Elements.deconstructConstructorName(
+ element.name, enclosingClass);
+ checkPrivateAccess(node, element, name);
DartType constructorType = computeType(element);
DartType newType = elements.getType(node);
// TODO(johnniwinther): Use [:lookupMember:] to account for type variable
@@ -944,10 +971,6 @@
return type;
}
- DartType visitOperator(Operator node) {
- compiler.internalError('unexpected node type', node: node);
- }
-
DartType visitRethrow(Rethrow node) {
return StatementType.RETURNING;
}
@@ -991,6 +1014,7 @@
}
DartType visitThrow(Throw node) {
+ // TODO(johnniwinther): Handle reachability.
analyze(node.expression);
return types.dynamicType;
}
@@ -1006,10 +1030,6 @@
return elements.getType(node);
}
- visitTypeVariable(TypeVariable node) {
- return types.dynamicType;
- }
-
DartType visitVariableDefinitions(VariableDefinitions node) {
DartType type = analyzeWithDefault(node.type, types.dynamicType);
if (type == types.voidType) {
@@ -1020,7 +1040,7 @@
link = link.tail) {
Node definition = link.head;
compiler.ensure(definition is Identifier || definition is SendSet);
- if (definition is Send) {
+ if (definition is SendSet) {
SendSet initialization = definition;
DartType initializer = analyzeNonVoid(initialization.arguments.head);
checkAssignable(initialization.assignmentOperator, initializer, type);
@@ -1062,8 +1082,6 @@
}
}
- DartType visitModifiers(Modifiers node) {}
-
visitStringInterpolation(StringInterpolation node) {
node.visitChildren(this);
return stringType;
@@ -1092,10 +1110,8 @@
return bodyType.join(StatementType.NOT_RETURNING);
}
- visitLabel(Label node) { }
-
visitLabeledStatement(LabeledStatement node) {
- return node.statement.accept(this);
+ return analyze(node.statement);
}
visitLiteralMap(LiteralMap node) {
@@ -1114,10 +1130,6 @@
return mapType;
}
- visitLiteralMapEntry(LiteralMapEntry node) {
- return unhandledExpression();
- }
-
visitNamedArgument(NamedArgument node) {
// Named arguments are visited as part of analyzing invocations of
// unresolved methods. For instance [: foo(a: 42); :] where 'foo' is neither
@@ -1128,15 +1140,25 @@
}
visitSwitchStatement(SwitchStatement node) {
- return unhandledStatement();
+ // TODO(johnniwinther): Handle reachability based on reachability of
+ // switch cases.
+ // TODO(johnniwinther): Check assignability to constants.
+ DartType expressionType = analyze(node.expression);
+ for (SwitchCase switchCase in node.cases) {
+ for (Node labelOrCase in switchCase.labelsAndCases) {
+ CaseMatch caseMatch = labelOrCase.asCaseMatch();
+ if (caseMatch == null) continue;
+
+ DartType caseType = analyze(caseMatch.expression);
+ checkAssignable(caseMatch, expressionType, caseType);
+ }
+ analyze(switchCase);
+ }
+ return StatementType.NOT_RETURNING;
}
visitSwitchCase(SwitchCase node) {
- return unhandledStatement();
- }
-
- visitCaseMatch(CaseMatch node) {
- return unhandledStatement();
+ return analyze(node.statements);
}
visitTryStatement(TryStatement node) {
@@ -1151,79 +1173,17 @@
return StatementType.NOT_RETURNING;
}
- visitScriptTag(ScriptTag node) {
- return unhandledExpression();
- }
-
visitCatchBlock(CatchBlock node) {
return analyze(node.block);
}
visitTypedef(Typedef node) {
- return unhandledStatement();
+ // Do not typecheck [Typedef] nodes.
}
- DartType visitNode(Node node) {
- compiler.unimplemented('visitNode', node: node);
- }
-
- DartType visitCombinator(Combinator node) {
- compiler.unimplemented('visitNode', node: node);
- }
-
- DartType visitExport(Export node) {
- compiler.unimplemented('visitNode', node: node);
- }
-
- DartType visitExpression(Expression node) {
- compiler.unimplemented('visitNode', node: node);
- }
-
- DartType visitGotoStatement(GotoStatement node) {
- compiler.unimplemented('visitNode', node: node);
- }
-
- DartType visitImport(Import node) {
- compiler.unimplemented('visitNode', node: node);
- }
-
- DartType visitLibraryName(LibraryName node) {
- compiler.unimplemented('visitNode', node: node);
- }
-
- DartType visitLibraryTag(LibraryTag node) {
- compiler.unimplemented('visitNode', node: node);
- }
-
- DartType visitLiteral(Literal node) {
- compiler.unimplemented('visitNode', node: node);
- }
-
- DartType visitPart(Part node) {
- compiler.unimplemented('visitNode', node: node);
- }
-
- DartType visitPartOf(PartOf node) {
- compiler.unimplemented('visitNode', node: node);
- }
-
- DartType visitPostfix(Postfix node) {
- compiler.unimplemented('visitNode', node: node);
- }
-
- DartType visitPrefix(Prefix node) {
- compiler.unimplemented('visitNode', node: node);
- }
-
- DartType visitStatement(Statement node) {
- compiler.unimplemented('visitNode', node: node);
- }
-
- DartType visitStringNode(StringNode node) {
- compiler.unimplemented('visitNode', node: node);
- }
-
- DartType visitLibraryDependency(LibraryDependency node) {
- compiler.unimplemented('visitNode', node: node);
+ visitNode(Node node) {
+ compiler.internalError(
+ 'Unexpected node ${node.getObjectDescription()} in the type checker.',
+ node: node);
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
index 9241edc..accc506 100644
--- a/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
@@ -2053,7 +2053,8 @@
sideEffects.add(nativeBehavior.sideEffects);
return inferrer.typeOfNativeBehavior(nativeBehavior);
} else if (name == const SourceString('JS_OPERATOR_IS_PREFIX')
- || name == const SourceString('JS_OPERATOR_AS_PREFIX')) {
+ || name == const SourceString('JS_OPERATOR_AS_PREFIX')
+ || name == const SourceString('JS_OBJECT_CLASS_NAME')) {
return inferrer.stringType;
} else {
sideEffects.setAllSideEffects();
diff --git a/sdk/lib/_internal/compiler/implementation/warnings.dart b/sdk/lib/_internal/compiler/implementation/warnings.dart
index c609c17..97b7cfa 100644
--- a/sdk/lib/_internal/compiler/implementation/warnings.dart
+++ b/sdk/lib/_internal/compiler/implementation/warnings.dart
@@ -38,6 +38,9 @@
'#{className}.#{memberName} is not static');
static const NO_INSTANCE_AVAILABLE = const MessageKind(
'#{name} is only available in instance methods');
+ static const PRIVATE_ACCESS = const MessageKind(
+ "'#{name}' is declared private within library #{libraryName} and "
+ "is therefore not accessible.");
static const THIS_IS_THE_METHOD = const MessageKind(
"This is the method declaration.");
@@ -327,6 +330,9 @@
static const ILLEGAL_MIXIN_SUPERCLASS = const MessageKind(
"Error: class used as mixin must have Object as superclass.");
+ static const ILLEGAL_MIXIN_OBJECT = const MessageKind(
+ "Error: cannot use Object as mixin.");
+
static const ILLEGAL_MIXIN_CONSTRUCTOR = const MessageKind(
"Error: class used as mixin cannot have non-factory constructor.");
diff --git a/sdk/lib/_internal/libraries.dart b/sdk/lib/_internal/libraries.dart
index 2e8efef..5c20d17 100644
--- a/sdk/lib/_internal/libraries.dart
+++ b/sdk/lib/_internal/libraries.dart
@@ -146,6 +146,12 @@
category: "Internal",
documented: false,
platforms: DART2JS_PLATFORM),
+
+ "_js_mirrors": const LibraryInfo(
+ "_internal/compiler/implementation/lib/js_mirrors.dart",
+ category: "Internal",
+ documented: false,
+ platforms: DART2JS_PLATFORM),
};
/**
diff --git a/sdk/lib/_internal/pub/lib/src/error_group.dart b/sdk/lib/_internal/pub/lib/src/error_group.dart
index a6f9e86..51fb27d 100644
--- a/sdk/lib/_internal/pub/lib/src/error_group.dart
+++ b/sdk/lib/_internal/pub/lib/src/error_group.dart
@@ -239,7 +239,7 @@
/// Creates a new [_ErrorGroupFuture] that's a child of [_group] and wraps
/// [inner].
_ErrorGroupStream(this._group, Stream inner)
- : _controller = new StreamController() {
+ : _controller = new StreamController(sync: true) {
this._stream = inner.isBroadcast
? _controller.stream.asBroadcastStream()
: _controller.stream;
diff --git a/sdk/lib/_internal/pub/lib/src/io.dart b/sdk/lib/_internal/pub/lib/src/io.dart
index e9a1316..e9d803b 100644
--- a/sdk/lib/_internal/pub/lib/src/io.dart
+++ b/sdk/lib/_internal/pub/lib/src/io.dart
@@ -422,7 +422,7 @@
/// will succeed when [EventSink] is closed or fail with any errors that occur
/// while writing.
Pair<EventSink, Future> consumerToSink(StreamConsumer consumer) {
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
var done = controller.stream.pipe(consumer);
return new Pair<EventSink, Future>(controller.sink, done);
}
@@ -739,7 +739,7 @@
contents.forEach((file) => buffer.write('$file\n'));
log.fine(buffer.toString());
- var controller = new StreamController<List<int>>();
+ var controller = new StreamController<List<int>>(sync: true);
if (baseDir == null) baseDir = path.current;
baseDir = path.absolute(baseDir);
diff --git a/sdk/lib/_internal/pub/lib/src/safe_http_server.dart b/sdk/lib/_internal/pub/lib/src/safe_http_server.dart
index c9885f1..a580770b 100644
--- a/sdk/lib/_internal/pub/lib/src/safe_http_server.dart
+++ b/sdk/lib/_internal/pub/lib/src/safe_http_server.dart
@@ -76,7 +76,6 @@
int get contentLength => _inner.contentLength;
String get method => _inner.method;
Uri get uri => _inner.uri;
- Map<String, String> get queryParameters => _inner.queryParameters;
HttpHeaders get headers => _inner.headers;
List<Cookie> get cookies => _inner.cookies;
bool get persistentConnection => _inner.persistentConnection;
diff --git a/sdk/lib/_internal/pub/lib/src/utils.dart b/sdk/lib/_internal/pub/lib/src/utils.dart
index b3ae863..aceec1c 100644
--- a/sdk/lib/_internal/pub/lib/src/utils.dart
+++ b/sdk/lib/_internal/pub/lib/src/utils.dart
@@ -183,7 +183,7 @@
/// Returns a wrapped version of [stream] along with a [StreamSubscription] that
/// can be used to control the wrapped stream.
Pair<Stream, StreamSubscription> streamWithSubscription(Stream stream) {
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
var controllerStream = stream.isBroadcast ?
controller.stream.asBroadcastStream() :
controller.stream;
@@ -198,8 +198,8 @@
/// errors from [stream]. This is useful if [stream] is single-subscription but
/// multiple subscribers are necessary.
Pair<Stream, Stream> tee(Stream stream) {
- var controller1 = new StreamController();
- var controller2 = new StreamController();
+ var controller1 = new StreamController(sync: true);
+ var controller2 = new StreamController(sync: true);
stream.listen((value) {
controller1.add(value);
controller2.add(value);
@@ -217,7 +217,7 @@
/// both sources.
Stream mergeStreams(Stream stream1, Stream stream2) {
var doneCount = 0;
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
for (var stream in [stream1, stream2]) {
stream.listen((value) {
diff --git a/sdk/lib/_internal/pub/test/error_group_test.dart b/sdk/lib/_internal/pub/test/error_group_test.dart
index d22f12c..7cad9be 100644
--- a/sdk/lib/_internal/pub/test/error_group_test.dart
+++ b/sdk/lib/_internal/pub/test/error_group_test.dart
@@ -38,7 +38,8 @@
expect(() => errorGroup.registerFuture(new Future.value()),
throwsStateError);
- expect(() => errorGroup.registerStream(new StreamController().stream),
+ expect(() => errorGroup.registerStream(
+ new StreamController(sync: true).stream),
throwsStateError);
});
});
@@ -66,7 +67,8 @@
completer.future.then(expectAsync1((_) {
expect(() => errorGroup.registerFuture(new Future.value()),
throwsStateError);
- expect(() => errorGroup.registerStream(new StreamController().stream),
+ expect(() => errorGroup.registerStream(
+ new StreamController(sync: true).stream),
throwsStateError);
}));
});
@@ -205,7 +207,7 @@
setUp(() {
errorGroup = new ErrorGroup();
- controller = new StreamController();
+ controller = new StreamController(sync: true);
stream = errorGroup.registerStream(controller.stream.asBroadcastStream());
});
@@ -277,7 +279,7 @@
setUp(() {
errorGroup = new ErrorGroup();
- controller = new StreamController();
+ controller = new StreamController(sync: true);
stream = errorGroup.registerStream(controller.stream);
});
@@ -326,8 +328,8 @@
setUp(() {
errorGroup = new ErrorGroup();
- controller1 = new StreamController();
- controller2 = new StreamController();
+ controller1 = new StreamController(sync: true);
+ controller2 = new StreamController(sync: true);
stream1 = errorGroup.registerStream(controller1.stream.asBroadcastStream());
stream2 = errorGroup.registerStream(controller2.stream.asBroadcastStream());
});
@@ -385,7 +387,7 @@
setUp(() {
errorGroup = new ErrorGroup();
- controller = new StreamController();
+ controller = new StreamController(sync: true);
stream = errorGroup.registerStream(controller.stream.asBroadcastStream());
completer = new Completer();
future = errorGroup.registerFuture(completer.future);
diff --git a/sdk/lib/async/stream.dart b/sdk/lib/async/stream.dart
index 07378b5..43697ec 100644
--- a/sdk/lib/async/stream.dart
+++ b/sdk/lib/async/stream.dart
@@ -62,7 +62,7 @@
* data or error, and then close with a done-event.
*/
factory Stream.fromFuture(Future<T> future) {
- StreamController<T> controller = new StreamController<T>();
+ StreamController<T> controller = new StreamController<T>(sync: true);
future.then((value) {
controller.add(value);
controller.close();
@@ -114,7 +114,7 @@
});
}
- controller = new StreamController<T>(
+ controller = new StreamController<T>(sync: true,
onListen: () {
watch.start();
startPeriodicTimer();
diff --git a/sdk/lib/async/stream_controller.dart b/sdk/lib/async/stream_controller.dart
index b057565..abfd648 100644
--- a/sdk/lib/async/stream_controller.dart
+++ b/sdk/lib/async/stream_controller.dart
@@ -53,6 +53,11 @@
/**
* A controller with a [stream] that supports only one single subscriber.
*
+ * If [sync] is true, events may be passed directly to the stream's listener
+ * during an [add], [addError] or [close] call. If [sync] is false, the event
+ * will be passed to the listener at a later time, after the code creating
+ * the event has returned.
+ *
* The controller will buffer all incoming events until the subscriber is
* registered.
*
@@ -69,8 +74,11 @@
factory StreamController({void onListen(),
void onPause(),
void onResume(),
- void onCancel()})
- => new _StreamControllerImpl<T>(onListen, onPause, onResume, onCancel);
+ void onCancel(),
+ bool sync: false})
+ => sync
+ ? new _SyncStreamController<T>(onListen, onPause, onResume, onCancel)
+ : new _AsyncStreamController<T>(onListen, onPause, onResume, onCancel);
/**
* A controller where [stream] can be listened to more than once.
@@ -83,17 +91,35 @@
* It is not allowed to call [add], [addError], or [close] before a previous
* call has returned.
*
+ * If [sync] is true, events may be passed directly to the stream's listener
+ * during an [add], [addError] or [close] call. If [sync] is false, the event
+ * will be passed to the listener at a later time, after the code creating
+ * the event has returned.
+ *
* Each listener is handled independently, and if they pause, only the pausing
* listener is affected. A paused listener will buffer events internally until
* unpaused or canceled.
*
+ * If [sync] is false, no guarantees are given with regard to when
+ * multiple listeners get the events, except that each listener will get
+ * all events in the correct order. If two events are sent on an async
+ * controller with two listeners, one of the listeners may get both events
+ * before the other listener gets any.
+ * A listener must be subscribed both when the event is initiated (that is,
+ * when [add] is called) and when the event is later delivered, in order to
+ * get the event.
+ *
* The [onListen] callback is called when the first listener is subscribed,
* and the [onCancel] is called when there are no longer any active listeners.
* If a listener is added again later, after the [onCancel] was called,
* the [onListen] will be called again.
*/
- factory StreamController.broadcast({void onListen(), void onCancel()}) {
- return new _MultiplexStreamController<T>(onListen, onCancel);
+ factory StreamController.broadcast({void onListen(),
+ void onCancel(),
+ bool sync: false}) {
+ return sync
+ ? new _SyncBroadcastStreamController<T>(onListen, onCancel)
+ : new _AsyncBroadcastStreamController<T>(onListen, onCancel);
}
/**
@@ -147,8 +173,9 @@
*
* Controls a stream that only supports a single controller.
*/
-class _StreamControllerImpl<T> implements StreamController<T>,
- _StreamControllerLifecycle<T> {
+abstract class _StreamController<T> implements StreamController<T>,
+ _StreamControllerLifecycle<T>,
+ _EventDispatch<T> {
static const int _STATE_OPEN = 0;
static const int _STATE_CANCELLED = 1;
static const int _STATE_CLOSED = 2;
@@ -168,10 +195,10 @@
// Events added to the stream before it has an active subscription.
_PendingEvents _pendingEvents = null;
- _StreamControllerImpl(this._onListen,
- this._onPause,
- this._onResume,
- this._onCancel) {
+ _StreamController(this._onListen,
+ this._onPause,
+ this._onResume,
+ this._onCancel) {
_stream = new _ControllerStream<T>(this);
}
@@ -202,7 +229,7 @@
void add(T value) {
if (isClosed) throw new StateError("Adding event after close");
if (_subscription != null) {
- _subscription._add(value);
+ _sendData(value);
} else if (!_isCancelled) {
_addPendingEvent(new _DelayedData<T>(value));
}
@@ -219,7 +246,7 @@
_attachStackTrace(error, stackTrace);
}
if (_subscription != null) {
- _subscription._addError(error);
+ _sendError(error);
} else if (!_isCancelled) {
_addPendingEvent(new _DelayedError(error));
}
@@ -240,12 +267,14 @@
if (isClosed) return;
_state |= _STATE_CLOSED;
if (_subscription != null) {
- _subscription._close();
+ _sendDone();
} else if (!_isCancelled) {
_addPendingEvent(const _DelayedDone());
}
}
+ // EventDispatch interface
+
void _addPendingEvent(_DelayedEvent event) {
if (_isCancelled) return;
_StreamImplEvents events = _pendingEvents;
@@ -281,6 +310,46 @@
}
}
+class _SyncStreamController<T> extends _StreamController<T> {
+ _SyncStreamController(void onListen(),
+ void onPause(),
+ void onResume(),
+ void onCancel())
+ : super(onListen, onPause, onResume, onCancel);
+
+ void _sendData(T data) {
+ _subscription._add(data);
+ }
+
+ void _sendError(Object error) {
+ _subscription._addError(error);
+ }
+
+ void _sendDone() {
+ _subscription._close();
+ }
+}
+
+class _AsyncStreamController<T> extends _StreamController<T> {
+ _AsyncStreamController(void onListen(),
+ void onPause(),
+ void onResume(),
+ void onCancel())
+ : super(onListen, onPause, onResume, onCancel);
+
+ void _sendData(T data) {
+ _subscription._addPending(new _DelayedData(data));
+ }
+
+ void _sendError(Object error) {
+ _subscription._addPending(new _DelayedError(error));
+ }
+
+ void _sendDone() {
+ _subscription._addPending(const _DelayedDone());
+ }
+}
+
typedef void _NotificationHandler();
void _runGuarded(_NotificationHandler notificationHandler) {
@@ -339,10 +408,10 @@
}
}
-class _MultiplexStream<T> extends _StreamImpl<T> {
- _MultiplexStreamController _controller;
+class _BroadcastStream<T> extends _StreamImpl<T> {
+ _BroadcastStreamController _controller;
- _MultiplexStream(this._controller);
+ _BroadcastStream(this._controller);
bool get isBroadcast => true;
@@ -351,7 +420,7 @@
void onError(Object error),
void onDone(),
bool cancelOnError) {
- return new _MultiplexSubscription<T>(
+ return new _BroadcastSubscription<T>(
_controller, onData, onError, onDone, cancelOnError);
}
@@ -360,22 +429,22 @@
}
}
-abstract class _MultiplexSubscriptionLink {
- _MultiplexSubscriptionLink _next;
- _MultiplexSubscriptionLink _previous;
+abstract class _BroadcastSubscriptionLink {
+ _BroadcastSubscriptionLink _next;
+ _BroadcastSubscriptionLink _previous;
}
-class _MultiplexSubscription<T> extends _ControllerSubscription<T>
- implements _MultiplexSubscriptionLink {
+class _BroadcastSubscription<T> extends _ControllerSubscription<T>
+ implements _BroadcastSubscriptionLink {
static const int _STATE_EVENT_ID = 1;
static const int _STATE_FIRING = 2;
static const int _STATE_REMOVE_AFTER_FIRING = 4;
int _eventState;
- _MultiplexSubscriptionLink _next;
- _MultiplexSubscriptionLink _previous;
+ _BroadcastSubscriptionLink _next;
+ _BroadcastSubscriptionLink _previous;
- _MultiplexSubscription(_StreamControllerLifecycle controller,
+ _BroadcastSubscription(_StreamControllerLifecycle controller,
void onData(T data),
void onError(Object error),
void onDone(),
@@ -384,7 +453,7 @@
_next = _previous = this;
}
- _MultiplexStreamController get _controller => super._controller;
+ _BroadcastStreamController get _controller => super._controller;
bool _expectsEvent(int eventId) {
return (_eventState & _STATE_EVENT_ID) == eventId;
@@ -406,9 +475,11 @@
}
-class _MultiplexStreamController<T> implements StreamController<T>,
- _StreamControllerLifecycle<T>,
- _MultiplexSubscriptionLink {
+abstract class _BroadcastStreamController<T>
+ implements StreamController<T>,
+ _StreamControllerLifecycle<T>,
+ _BroadcastSubscriptionLink,
+ _EventDispatch<T> {
static const int _STATE_INITIAL = 0;
static const int _STATE_EVENT_ID = 1;
static const int _STATE_FIRING = 2;
@@ -421,24 +492,24 @@
int _state;
// Double-linked list of active listeners.
- _MultiplexSubscriptionLink _next;
- _MultiplexSubscriptionLink _previous;
+ _BroadcastSubscriptionLink _next;
+ _BroadcastSubscriptionLink _previous;
- _MultiplexStreamController(this._onListen, this._onCancel)
+ _BroadcastStreamController(this._onListen, this._onCancel)
: _state = _STATE_INITIAL {
_next = _previous = this;
}
// StreamController interface.
- Stream<T> get stream => new _MultiplexStream<T>(this);
+ Stream<T> get stream => new _BroadcastStream<T>(this);
EventSink<T> get sink => new _EventSinkView<T>(this);
bool get isClosed => (_state & _STATE_CLOSED) != 0;
/**
- * A multiplex controller is never paused.
+ * A broadcast controller is never paused.
*
* Each receiving stream may be paused individually, and they handle their
* own buffering.
@@ -456,8 +527,8 @@
bool get _isEmpty => identical(_next, this);
/** Adds subscription to linked list of active listeners. */
- void _addListener(_MultiplexSubscription<T> subscription) {
- _MultiplexSubscriptionLink previous = _previous;
+ void _addListener(_BroadcastSubscription<T> subscription) {
+ _BroadcastSubscriptionLink previous = _previous;
previous._next = subscription;
_previous = subscription._previous;
subscription._previous._next = this;
@@ -465,7 +536,7 @@
subscription._eventState = (_state & _STATE_EVENT_ID);
}
- void _removeListener(_MultiplexSubscription<T> subscription) {
+ void _removeListener(_BroadcastSubscription<T> subscription) {
assert(identical(subscription._controller, this));
assert(!identical(subscription._next, subscription));
subscription._previous._next = subscription._next;
@@ -475,7 +546,7 @@
// _StreamControllerLifecycle interface.
- void _recordListen(_MultiplexSubscription<T> subscription) {
+ void _recordListen(_BroadcastSubscription<T> subscription) {
_addListener(subscription);
if (identical(_next, _previous)) {
// Only one listener, so it must be the first listener.
@@ -483,7 +554,7 @@
}
}
- void _recordCancel(_MultiplexSubscription<T> subscription) {
+ void _recordCancel(_BroadcastSubscription<T> subscription) {
if (subscription._isFiring) {
subscription._setRemoveAfterFiring();
} else {
@@ -524,6 +595,55 @@
_sendDone();
}
+ void _forEachListener(
+ void action(_BufferingStreamSubscription<T> subscription)) {
+ if (_isFiring) {
+ throw new StateError(
+ "Cannot fire new event. Controller is already firing an event");
+ }
+ if (_isEmpty) return;
+
+ // Get event id of this event.
+ int id = (_state & _STATE_EVENT_ID);
+ // Start firing (set the _STATE_FIRING bit). We don't do [_onCancel]
+ // callbacks while firing, and we prevent reentrancy of this function.
+ //
+ // Set [_state]'s event id to the next event's id.
+ // Any listeners added while firing this event will expect the next event,
+ // not this one, and won't get notified.
+ _state ^= _STATE_EVENT_ID | _STATE_FIRING;
+ _BroadcastSubscriptionLink link = _next;
+ while (!identical(link, this)) {
+ _BroadcastSubscription<T> subscription = link;
+ if (subscription._expectsEvent(id)) {
+ subscription._eventState |= _BroadcastSubscription._STATE_FIRING;
+ action(subscription);
+ subscription._toggleEventId();
+ link = subscription._next;
+ if (subscription._removeAfterFiring) {
+ _removeListener(subscription);
+ }
+ subscription._eventState &= ~_BroadcastSubscription._STATE_FIRING;
+ } else {
+ link = subscription._next;
+ }
+ }
+ _state &= ~_STATE_FIRING;
+
+ if (_isEmpty) {
+ _callOnCancel();
+ }
+ }
+
+ void _callOnCancel() {
+ _runGuarded(_onCancel);
+ }
+}
+
+class _SyncBroadcastStreamController<T> extends _BroadcastStreamController<T> {
+ _SyncBroadcastStreamController(void onListen(), void onCancel())
+ : super(onListen, onCancel);
+
// EventDispatch interface.
void _sendData(T data) {
@@ -542,64 +662,65 @@
void _sendDone() {
if (_isEmpty) return;
- _forEachListener((_MultiplexSubscription<T> subscription) {
+ _forEachListener((_BroadcastSubscription<T> subscription) {
subscription._close();
subscription._eventState |=
- _MultiplexSubscription._STATE_REMOVE_AFTER_FIRING;
+ _BroadcastSubscription._STATE_REMOVE_AFTER_FIRING;
});
}
-
- void _forEachListener(
- void action(_BufferingStreamSubscription<T> subscription)) {
- if (_isFiring) {
- throw new StateError(
- "Cannot fire new event. Controller is already firing an event");
- }
- if (_isEmpty) return;
-
- // Get event id of this event.
- int id = (_state & _STATE_EVENT_ID);
- // Start firing (set the _STATE_FIRING bit). We don't do [_onCancel]
- // callbacks while firing, and we prevent reentrancy of this function.
- //
- // Set [_state]'s event id to the next event's id.
- // Any listeners added while firing this event will expect the next event,
- // not this one, and won't get notified.
- _state ^= _STATE_EVENT_ID | _STATE_FIRING;
- _MultiplexSubscriptionLink link = _next;
- while (!identical(link, this)) {
- _MultiplexSubscription<T> subscription = link;
- if (subscription._expectsEvent(id)) {
- subscription._eventState |= _MultiplexSubscription._STATE_FIRING;
- action(subscription);
- subscription._toggleEventId();
- link = subscription._next;
- if (subscription._removeAfterFiring) {
- _removeListener(subscription);
- }
- subscription._eventState &= ~_MultiplexSubscription._STATE_FIRING;
- } else {
- link = subscription._next;
- }
- }
- _state &= ~_STATE_FIRING;
-
- if (_isEmpty) {
- _callOnCancel();
- }
- }
-
- void _callOnCancel() {
- _runGuarded(_onCancel);
- }
}
-class _BufferingMultiplexStreamController<T>
- extends _MultiplexStreamController<T>
+class _AsyncBroadcastStreamController<T> extends _BroadcastStreamController<T> {
+ _AsyncBroadcastStreamController(void onListen(), void onCancel())
+ : super(onListen, onCancel);
+
+ // EventDispatch interface.
+
+ void _sendData(T data) {
+ for (_BroadcastSubscriptionLink link = _next;
+ !identical(link, this);
+ link = link._next) {
+ _BroadcastSubscription<T> subscription = link;
+ subscription._addPending(new _DelayedData(data));
+ }
+ }
+
+ void _sendError(Object error) {
+ for (_BroadcastSubscriptionLink link = _next;
+ !identical(link, this);
+ link = link._next) {
+ _BroadcastSubscription<T> subscription = link;
+ subscription._addPending(new _DelayedError(error));
+ }
+ }
+
+ void _sendDone() {
+ for (_BroadcastSubscriptionLink link = _next;
+ !identical(link, this);
+ link = link._next) {
+ _BroadcastSubscription<T> subscription = link;
+ subscription._addPending(const _DelayedDone());
+ }
+ }
+}
+
+/**
+ * Stream controller that is used by [Stream.asBroadcastStream].
+ *
+ * This stream controller allows incoming events while it is firing
+ * other events. This is handled by delaying the events until the
+ * current event is done firing, and then fire the pending events.
+ *
+ * This class extends [_SyncBroadcastStreamController]. Events of
+ * an "asBroadcastStream" stream are always initiated by events
+ * on another stream, and it is fine to forward them synchronously.
+ */
+class _AsBroadcastStreamController<T>
+ extends _SyncBroadcastStreamController<T>
implements _EventDispatch<T> {
_StreamImplEvents _pending;
- _BufferingMultiplexStreamController(void onListen(), void onCancel())
+ _AsBroadcastStreamController(void onListen(), void onCancel())
: super(onListen, onCancel);
bool get _hasPending => _pending != null && ! _pending.isEmpty;
@@ -649,6 +770,5 @@
_pending = null;
}
super._callOnCancel();
-
}
}
diff --git a/sdk/lib/async/stream_impl.dart b/sdk/lib/async/stream_impl.dart
index 375844c..e46ba50 100644
--- a/sdk/lib/async/stream_impl.dart
+++ b/sdk/lib/async/stream_impl.dart
@@ -694,9 +694,9 @@
}
}
-class _MultiplexerLinkedList {
- _MultiplexerLinkedList _next;
- _MultiplexerLinkedList _previous;
+class _BroadcastLinkedList {
+ _BroadcastLinkedList _next;
+ _BroadcastLinkedList _previous;
void _unlink() {
_previous._next = _next;
@@ -704,8 +704,8 @@
_next = _previous = this;
}
- void _insertBefore(_MultiplexerLinkedList newNext) {
- _MultiplexerLinkedList newPrevious = newNext._previous;
+ void _insertBefore(_BroadcastLinkedList newNext) {
+ _BroadcastLinkedList newPrevious = newNext._previous;
newPrevious._next = this;
newNext._previous = _previous;
_previous._next = newNext;
@@ -715,11 +715,11 @@
class _AsBroadcastStream<T> extends Stream<T> {
final Stream<T> _source;
- _BufferingMultiplexStreamController<T> _controller;
+ _AsBroadcastStreamController<T> _controller;
StreamSubscription<T> _subscription;
_AsBroadcastStream(this._source) {
- _controller = new _BufferingMultiplexStreamController<T>(null, _onCancel);
+ _controller = new _AsBroadcastStreamController<T>(null, _onCancel);
}
bool get isBroadcast => true;
diff --git a/sdk/lib/core/iterable.dart b/sdk/lib/core/iterable.dart
index 03127c8..41972b9 100644
--- a/sdk/lib/core/iterable.dart
+++ b/sdk/lib/core/iterable.dart
@@ -198,13 +198,13 @@
* Returns an [Iterable] that skips elements while [test] is satisfied.
*
* The filtering happens lazily. Every new [Iterator] of the returned
- * [Iterable] will iterate over all elements of `this`.
+ * [Iterable] iterates over all elements of `this`.
*
- * As long as the iterator's elements do not satisfy [test] they are
- * discarded. Once an element satisfies the [test] the iterator stops testing
- * and uses every element unconditionally. That is, the elements of the
- * returned [Iterable] are the elements of `this` starting from the first
- * element that doesn't satisfy [test].
+ * As long as the iterator's elements satisfy [test] they are
+ * discarded. Once an element does not satisfy the [test] the iterator stops
+ * testing and uses every later element unconditionally. That is, the elements
+ * of the returned [Iterable] are the elements of `this` starting from the
+ * first element that does not satisfy [test].
*/
Iterable<E> skipWhile(bool test(E value));
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 021a3ca..084abb2 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -249,7 +249,7 @@
@DomName('DOMApplicationCache.progressEvent')
@DocsEditable
- static const EventStreamProvider<Event> progressEvent = const EventStreamProvider<Event>('progress');
+ static const EventStreamProvider<ProgressEvent> progressEvent = const EventStreamProvider<ProgressEvent>('progress');
@DomName('DOMApplicationCache.updatereadyEvent')
@DocsEditable
@@ -338,7 +338,7 @@
@DomName('DOMApplicationCache.onprogress')
@DocsEditable
- Stream<Event> get onProgress => progressEvent.forTarget(this);
+ Stream<ProgressEvent> get onProgress => progressEvent.forTarget(this);
@DomName('DOMApplicationCache.onupdateready')
@DocsEditable
@@ -427,15 +427,6 @@
@DocsEditable
-@DomName('Attr')
-class Attr extends Node native "Attr" {
-}
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-
-@DocsEditable
@DomName('HTMLAudioElement')
class AudioElement extends MediaElement native "HTMLAudioElement" {
@@ -5573,7 +5564,7 @@
@DocsEditable
@DomName('CustomElementConstructor')
// https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html#dfn-custom-element-constructor-generation
-@Experimental
+@deprecated // experimental
class CustomElementConstructor native "CustomElementConstructor" {
}
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
@@ -7251,6 +7242,24 @@
throw new UnsupportedError('Cannot sort element lists');
}
+ void removeWhere(bool test(Element element)) {
+ _filter(test, false);
+ }
+
+ void retainWhere(bool test(Element element)) {
+ _filter(test, true);
+ }
+
+ void _filter(bool test(var element), bool retainMatching) {
+ var removed;
+ if (retainMatching) {
+ removed = _element.children.where((e) => !test(e));
+ } else {
+ removed = _element.children.where(test);
+ }
+ for (var e in removed) e.remove();
+ }
+
void setRange(int start, int end, Iterable<Element> iterable,
[int skipCount = 0]) {
throw new UnimplementedError();
@@ -7642,6 +7651,16 @@
_xtag = value;
}
+ @DomName('Element.localName')
+ @DocsEditable
+ String get localName => $dom_localName;
+
+ @DomName('Element.namespaceUri')
+ @DocsEditable
+ String get namespaceUri => $dom_namespaceUri;
+
+ String toString() => localName;
+
/**
* Scrolls this element into view.
*
@@ -7696,7 +7715,7 @@
}
}
- @DomName('Element.webkitTransitionEndEvent')
+ @DomName('Element.transitionEndEvent')
static const EventStreamProvider<TransitionEvent> transitionEndEvent =
const _CustomEventStreamProvider<TransitionEvent>(
Element._determineTransitionEventType);
@@ -8854,13 +8873,12 @@
@Experimental
Stream<TouchEvent> get onTouchStart => touchStartEvent.forTarget(this);
- @DomName('Element.onwebkitTransitionEnd')
+ @DomName('Element.ontransitionend')
@DocsEditable
@SupportedBrowser(SupportedBrowser.CHROME)
@SupportedBrowser(SupportedBrowser.FIREFOX)
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
- @deprecated
Stream<TransitionEvent> get onTransitionEnd => transitionEndEvent.forTarget(this);
@DomName('Element.onwebkitfullscreenchange')
@@ -10630,7 +10648,7 @@
int watchId;
var controller;
- controller = new StreamController<Geoposition>(
+ controller = new StreamController<Geoposition>(sync: true,
onListen: () {
assert(watchId == null);
watchId = $dom_watchPosition(
@@ -15810,14 +15828,15 @@
*/
Node insertAllBefore(Iterable<Node> newNodes, Node refChild) {
if (newNodes is _ChildNodeListLazy) {
- if (identical(newNodes._this, this)) {
+ _ChildNodeListLazy otherList = newNodes;
+ if (identical(otherList._this, this)) {
throw new ArgumentError(newNodes);
}
// Optimized route for copying between nodes.
- for (var i = 0, len = newNodes.length; i < len; ++i) {
+ for (var i = 0, len = otherList.length; i < len; ++i) {
// Should use $dom_firstChild, Bug 8886.
- this.insertBefore(newNodes[0], refChild);
+ this.insertBefore(otherList[0], refChild);
}
} else {
for (var node in newNodes) {
@@ -15829,8 +15848,7 @@
/**
* Print out a String representation of this Node.
*/
- String toString() => localName == null ?
- (nodeValue == null ? super.toString() : nodeValue) : localName;
+ String toString() => nodeValue == null ? super.toString() : nodeValue;
/**
* Binds the attribute [name] to the [path] of the [model].
@@ -15925,11 +15943,12 @@
@DocsEditable
final Node $dom_lastChild;
+ @JSName('localName')
@DomName('Node.localName')
@DocsEditable
// http://dom.spec.whatwg.org/#dom-node-localname
@deprecated // deprecated
- final String localName;
+ final String $dom_localName;
@JSName('namespaceURI')
@DomName('Node.namespaceURI')
@@ -20367,7 +20386,7 @@
@Experimental
static Stream<DocumentFragment> get instanceCreated {
if (_instanceCreated == null) {
- _instanceCreated = new StreamController<DocumentFragment>();
+ _instanceCreated = new StreamController<DocumentFragment>(sync: true);
}
return _instanceCreated.stream;
}
@@ -22027,7 +22046,7 @@
var axis = 0;
var detail = 0;
if (deltaX != 0 && deltaY != 0) {
- throw UnsupportedError(
+ throw new UnsupportedError(
'Cannot modify deltaX and deltaY simultaneously');
}
if (deltaY != 0) {
@@ -23220,6 +23239,10 @@
@Experimental
Stream<TouchEvent> get onTouchStart => Element.touchStartEvent.forTarget(this);
+ @DomName('Window.ontransitionend')
+ @DocsEditable
+ Stream<TransitionEvent> get onTransitionEnd => Element.transitionEndEvent.forTarget(this);
+
@DomName('Window.onunload')
@DocsEditable
Stream<Event> get onUnload => unloadEvent.forTarget(this);
@@ -23239,11 +23262,6 @@
@Experimental // untriaged
Stream<AnimationEvent> get onAnimationStart => animationStartEvent.forTarget(this);
- @DomName('Window.onwebkitTransitionEnd')
- @DocsEditable
- @deprecated
- Stream<TransitionEvent> get onTransitionEnd => Element.transitionEndEvent.forTarget(this);
-
@DomName('DOMWindow.beforeunloadEvent')
@DocsEditable
@@ -23294,7 +23312,7 @@
const _BeforeUnloadEventStreamProvider(this._eventType);
Stream<BeforeUnloadEvent> forTarget(EventTarget e, {bool useCapture: false}) {
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
var stream = new _EventStream(e, _eventType, useCapture);
stream.listen((event) {
var wrapped = new _BeforeUnloadEvent(event);
@@ -23618,6 +23636,37 @@
@DocsEditable
+@DomName('Attr')
+class _Attr extends Node native "Attr" {
+
+ @DomName('Attr.isId')
+ @DocsEditable
+ final bool isId;
+
+ @DomName('Attr.name')
+ @DocsEditable
+ final String name;
+
+ @DomName('Attr.ownerElement')
+ @DocsEditable
+ @deprecated // deprecated
+ final Element ownerElement;
+
+ @DomName('Attr.specified')
+ @DocsEditable
+ @deprecated // deprecated
+ final bool specified;
+
+ @DomName('Attr.value')
+ @DocsEditable
+ String value;
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+
+@DocsEditable
@DomName('CSSPrimitiveValue')
// http://dev.w3.org/csswg/cssom/#the-cssstyledeclaration-interface
@deprecated // deprecated
@@ -24857,7 +24906,7 @@
var keys = new List<String>();
for (int i = 0, len = attributes.length; i < len; i++) {
if (_matches(attributes[i])) {
- keys.add(attributes[i].localName);
+ keys.add(attributes[i].name);
}
}
return keys;
@@ -25635,7 +25684,7 @@
static final int _ROMAN_ALPHABET_OFFSET = "a".codeUnits[0] - "A".codeUnits[0];
/** Controller to produce KeyEvents for the stream. */
- final StreamController _controller = new StreamController();
+ final StreamController _controller = new StreamController(sync: true);
static const _EVENT_TYPE = 'KeyEvent';
@@ -25704,7 +25753,7 @@
* Hook up all event listeners under the covers so we can estimate keycodes
* and charcodes when they are not provided.
*/
- _KeyboardEventHandler.initializeAllEventListeners(this._type, this._target) :
+ _KeyboardEventHandler.initializeAllEventListeners(this._type, this._target) :
super(_EVENT_TYPE) {
Element.keyDownEvent.forTarget(_target, useCapture: true).listen(
processKeyDown);
@@ -26849,7 +26898,8 @@
// TODO(jmesserly): if the path is empty, or the object is! Observable, we
// can optimize the PathObserver to be more lightweight.
- _values = new StreamController.broadcast(onListen: _observe,
+ _values = new StreamController.broadcast(sync: true,
+ onListen: _observe,
onCancel: _unobserve);
if (_isValid) {
@@ -27896,11 +27946,12 @@
static void _removeChild(Node parent, Node child) {
child._templateInstance = null;
if (child is Element && (child as Element).isTemplate) {
+ Element childElement = child;
// Make sure we stop observing when we remove an element.
- var templateIterator = child._templateIterator;
+ var templateIterator = childElement._templateIterator;
if (templateIterator != null) {
templateIterator.abandon();
- child._templateIterator = null;
+ childElement._templateIterator = null;
}
}
child.remove();
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index 0d36c93..0821628 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -332,7 +332,7 @@
@DomName('DOMApplicationCache.progressEvent')
@DocsEditable
- static const EventStreamProvider<Event> progressEvent = const EventStreamProvider<Event>('progress');
+ static const EventStreamProvider<ProgressEvent> progressEvent = const EventStreamProvider<ProgressEvent>('progress');
@DomName('DOMApplicationCache.updatereadyEvent')
@DocsEditable
@@ -419,7 +419,7 @@
@DomName('DOMApplicationCache.onprogress')
@DocsEditable
- Stream<Event> get onProgress => progressEvent.forTarget(this);
+ Stream<ProgressEvent> get onProgress => progressEvent.forTarget(this);
@DomName('DOMApplicationCache.onupdateready')
@DocsEditable
@@ -541,19 +541,6 @@
@DocsEditable
-@DomName('Attr')
-class Attr extends Node {
- Attr.internal() : super.internal();
-
-}
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-// WARNING: Do not edit - generated code.
-
-
-@DocsEditable
@DomName('HTMLAudioElement')
class AudioElement extends MediaElement {
AudioElement.internal() : super.internal();
@@ -6060,7 +6047,7 @@
@DocsEditable
@DomName('CustomElementConstructor')
// https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html#dfn-custom-element-constructor-generation
-@Experimental
+@deprecated // experimental
class CustomElementConstructor extends NativeFieldWrapperClass1 {
CustomElementConstructor.internal();
@@ -7725,6 +7712,24 @@
throw new UnsupportedError('Cannot sort element lists');
}
+ void removeWhere(bool test(Element element)) {
+ _filter(test, false);
+ }
+
+ void retainWhere(bool test(Element element)) {
+ _filter(test, true);
+ }
+
+ void _filter(bool test(var element), bool retainMatching) {
+ var removed;
+ if (retainMatching) {
+ removed = _element.children.where((e) => !test(e));
+ } else {
+ removed = _element.children.where(test);
+ }
+ for (var e in removed) e.remove();
+ }
+
void setRange(int start, int end, Iterable<Element> iterable,
[int skipCount = 0]) {
throw new UnimplementedError();
@@ -8115,6 +8120,16 @@
_xtag = value;
}
+ @DomName('Element.localName')
+ @DocsEditable
+ String get localName => $dom_localName;
+
+ @DomName('Element.namespaceUri')
+ @DocsEditable
+ String get namespaceUri => $dom_namespaceUri;
+
+ String toString() => localName;
+
/**
* Scrolls this element into view.
*
@@ -8594,13 +8609,9 @@
@Experimental
static const EventStreamProvider<TouchEvent> touchStartEvent = const EventStreamProvider<TouchEvent>('touchstart');
- @DomName('Element.webkitTransitionEndEvent')
+ @DomName('Element.transitionendEvent')
@DocsEditable
- @SupportedBrowser(SupportedBrowser.CHROME)
- @SupportedBrowser(SupportedBrowser.SAFARI)
- @Experimental
- @deprecated
- static const EventStreamProvider<TransitionEvent> transitionEndEvent = const EventStreamProvider<TransitionEvent>('webkitTransitionEnd');
+ static const EventStreamProvider<TransitionEvent> transitionEndEvent = const EventStreamProvider<TransitionEvent>('transitionend');
@DomName('Element.webkitfullscreenchangeEvent')
@DocsEditable
@@ -9165,13 +9176,12 @@
@Experimental
Stream<TouchEvent> get onTouchStart => touchStartEvent.forTarget(this);
- @DomName('Element.onwebkitTransitionEnd')
+ @DomName('Element.ontransitionend')
@DocsEditable
@SupportedBrowser(SupportedBrowser.CHROME)
@SupportedBrowser(SupportedBrowser.FIREFOX)
@SupportedBrowser(SupportedBrowser.IE, '10')
@SupportedBrowser(SupportedBrowser.SAFARI)
- @deprecated
Stream<TransitionEvent> get onTransitionEnd => transitionEndEvent.forTarget(this);
@DomName('Element.onwebkitfullscreenchange')
@@ -11067,7 +11077,7 @@
int watchId;
var controller;
- controller = new StreamController<Geoposition>(
+ controller = new StreamController<Geoposition>(sync: true,
onListen: () {
assert(watchId == null);
watchId = $dom_watchPosition(
@@ -16863,14 +16873,15 @@
*/
Node insertAllBefore(Iterable<Node> newNodes, Node refChild) {
if (newNodes is _ChildNodeListLazy) {
- if (identical(newNodes._this, this)) {
+ _ChildNodeListLazy otherList = newNodes;
+ if (identical(otherList._this, this)) {
throw new ArgumentError(newNodes);
}
// Optimized route for copying between nodes.
- for (var i = 0, len = newNodes.length; i < len; ++i) {
+ for (var i = 0, len = otherList.length; i < len; ++i) {
// Should use $dom_firstChild, Bug 8886.
- this.insertBefore(newNodes[0], refChild);
+ this.insertBefore(otherList[0], refChild);
}
} else {
for (var node in newNodes) {
@@ -16882,8 +16893,7 @@
/**
* Print out a String representation of this Node.
*/
- String toString() => localName == null ?
- (nodeValue == null ? super.toString() : nodeValue) : localName;
+ String toString() => nodeValue == null ? super.toString() : nodeValue;
/**
* Binds the attribute [name] to the [path] of the [model].
@@ -16978,7 +16988,7 @@
@DocsEditable
// http://dom.spec.whatwg.org/#dom-node-localname
@deprecated // deprecated
- String get localName native "Node_localName_Getter";
+ String get $dom_localName native "Node_localName_Getter";
@DomName('Node.namespaceURI')
@DocsEditable
@@ -21916,7 +21926,7 @@
@Experimental
static Stream<DocumentFragment> get instanceCreated {
if (_instanceCreated == null) {
- _instanceCreated = new StreamController<DocumentFragment>();
+ _instanceCreated = new StreamController<DocumentFragment>(sync: true);
}
return _instanceCreated.stream;
}
@@ -24719,6 +24729,10 @@
@Experimental
Stream<TouchEvent> get onTouchStart => Element.touchStartEvent.forTarget(this);
+ @DomName('Window.ontransitionend')
+ @DocsEditable
+ Stream<TransitionEvent> get onTransitionEnd => Element.transitionEndEvent.forTarget(this);
+
@DomName('Window.onunload')
@DocsEditable
Stream<Event> get onUnload => unloadEvent.forTarget(this);
@@ -24738,11 +24752,6 @@
@Experimental // untriaged
Stream<AnimationEvent> get onAnimationStart => animationStartEvent.forTarget(this);
- @DomName('Window.onwebkitTransitionEnd')
- @DocsEditable
- @deprecated
- Stream<TransitionEvent> get onTransitionEnd => Element.transitionEndEvent.forTarget(this);
-
@DomName('DOMWindow.beforeunloadEvent')
@DocsEditable
@@ -24788,7 +24797,7 @@
const _BeforeUnloadEventStreamProvider(this._eventType);
Stream<BeforeUnloadEvent> forTarget(EventTarget e, {bool useCapture: false}) {
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
var stream = new _EventStream(e, _eventType, useCapture);
stream.listen((event) {
var wrapped = new _BeforeUnloadEvent(event);
@@ -25153,6 +25162,45 @@
@DocsEditable
+@DomName('Attr')
+class _Attr extends Node {
+ _Attr.internal() : super.internal();
+
+ @DomName('Attr.isId')
+ @DocsEditable
+ bool get isId native "Attr_isId_Getter";
+
+ @DomName('Attr.name')
+ @DocsEditable
+ String get name native "Attr_name_Getter";
+
+ @DomName('Attr.ownerElement')
+ @DocsEditable
+ @deprecated // deprecated
+ Element get ownerElement native "Attr_ownerElement_Getter";
+
+ @DomName('Attr.specified')
+ @DocsEditable
+ @deprecated // deprecated
+ bool get specified native "Attr_specified_Getter";
+
+ @DomName('Attr.value')
+ @DocsEditable
+ String get value native "Attr_value_Getter";
+
+ @DomName('Attr.value')
+ @DocsEditable
+ void set value(String value) native "Attr_value_Setter";
+
+}
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// WARNING: Do not edit - generated code.
+
+
+@DocsEditable
@DomName('CSSPrimitiveValue')
// http://dev.w3.org/csswg/cssom/#the-cssstyledeclaration-interface
@deprecated // deprecated
@@ -26731,7 +26779,7 @@
var keys = new List<String>();
for (int i = 0, len = attributes.length; i < len; i++) {
if (_matches(attributes[i])) {
- keys.add(attributes[i].localName);
+ keys.add(attributes[i].name);
}
}
return keys;
@@ -27509,7 +27557,7 @@
static final int _ROMAN_ALPHABET_OFFSET = "a".codeUnits[0] - "A".codeUnits[0];
/** Controller to produce KeyEvents for the stream. */
- final StreamController _controller = new StreamController();
+ final StreamController _controller = new StreamController(sync: true);
static const _EVENT_TYPE = 'KeyEvent';
@@ -27578,7 +27626,7 @@
* Hook up all event listeners under the covers so we can estimate keycodes
* and charcodes when they are not provided.
*/
- _KeyboardEventHandler.initializeAllEventListeners(this._type, this._target) :
+ _KeyboardEventHandler.initializeAllEventListeners(this._type, this._target) :
super(_EVENT_TYPE) {
Element.keyDownEvent.forTarget(_target, useCapture: true).listen(
processKeyDown);
@@ -28723,7 +28771,8 @@
// TODO(jmesserly): if the path is empty, or the object is! Observable, we
// can optimize the PathObserver to be more lightweight.
- _values = new StreamController.broadcast(onListen: _observe,
+ _values = new StreamController.broadcast(sync: true,
+ onListen: _observe,
onCancel: _unobserve);
if (_isValid) {
@@ -29770,11 +29819,12 @@
static void _removeChild(Node parent, Node child) {
child._templateInstance = null;
if (child is Element && (child as Element).isTemplate) {
+ Element childElement = child;
// Make sure we stop observing when we remove an element.
- var templateIterator = child._templateIterator;
+ var templateIterator = childElement._templateIterator;
if (templateIterator != null) {
templateIterator.abandon();
- child._templateIterator = null;
+ childElement._templateIterator = null;
}
}
child.remove();
diff --git a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
index 99346e1..22634d5 100644
--- a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
+++ b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
@@ -1016,7 +1016,7 @@
// TODO: need to guarantee that the controller provides the values
// immediately as waiting until the next tick will cause the transaction to
// close.
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
request.onError.listen((e) {
//TODO: Report stacktrace once issue 4061 is resolved.
diff --git a/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart b/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
index 1a539d9..745303e 100644
--- a/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
+++ b/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
@@ -877,7 +877,7 @@
// TODO: need to guarantee that the controller provides the values
// immediately as waiting until the next tick will cause the transaction to
// close.
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
request.onError.listen((e) {
//TODO: Report stacktrace once issue 4061 is resolved.
diff --git a/sdk/lib/io/directory.dart b/sdk/lib/io/directory.dart
index 59dc529..cd77600 100644
--- a/sdk/lib/io/directory.dart
+++ b/sdk/lib/io/directory.dart
@@ -51,17 +51,6 @@
}
/**
- * Check whether a directory with this name already exists. Returns
- * a [:Future<bool>:] that completes with the result.
- */
- Future<bool> exists();
-
- /**
- * Synchronously check whether a directory with this name already exists.
- */
- bool existsSync();
-
- /**
* Creates the directory with this name.
*
* If [recursive] is false, only the last directory in the path is
diff --git a/sdk/lib/io/directory_impl.dart b/sdk/lib/io/directory_impl.dart
index 0157a19..b9935ca 100644
--- a/sdk/lib/io/directory_impl.dart
+++ b/sdk/lib/io/directory_impl.dart
@@ -247,7 +247,7 @@
const int RESPONSE_COMPLETE = 1;
const int RESPONSE_ERROR = 2;
- var controller = new StreamController<FileSystemEntity>();
+ var controller = new StreamController<FileSystemEntity>(sync: true);
List request = [ _Directory.LIST_REQUEST, path, recursive, followLinks ];
ReceivePort responsePort = new ReceivePort();
diff --git a/sdk/lib/io/file.dart b/sdk/lib/io/file.dart
index eb3dcd7..2eea723 100644
--- a/sdk/lib/io/file.dart
+++ b/sdk/lib/io/file.dart
@@ -46,19 +46,6 @@
factory File.fromPath(Path path) => new _File.fromPath(path);
/**
- * Check if the file exists. Returns a
- * [:Future<bool>:] that completes when the answer is known.
- */
- Future<bool> exists();
-
- /**
- * Synchronously check if the file exists.
- *
- * Throws a [FileIOException] if the operation fails.
- */
- bool existsSync();
-
- /**
* Create the file. Returns a [:Future<File>:] that completes with
* the file when it has been created.
*
@@ -94,18 +81,9 @@
/**
* Get a [Directory] object for the directory containing this
- * file. Returns a [:Future<Directory>:] that completes with the
- * directory.
+ * file.
*/
- Future<Directory> directory();
-
- /**
- * Synchronously get a [Directory] object for the directory containing
- * this file.
- *
- * Throws a [FileIOException] if the operation fails.
- */
- Directory directorySync();
+ Directory get directory;
/**
* Get the length of the file. Returns a [:Future<int>:] that
diff --git a/sdk/lib/io/file_impl.dart b/sdk/lib/io/file_impl.dart
index 29b93dc..53a0f50 100644
--- a/sdk/lib/io/file_impl.dart
+++ b/sdk/lib/io/file_impl.dart
@@ -47,7 +47,7 @@
}
void _setupController() {
- _controller = new StreamController<List<int>>(
+ _controller = new StreamController<List<int>>(sync: true,
onListen: _start,
onPause: () => _paused = true,
onResume: _resume,
@@ -204,26 +204,25 @@
const int _DELETE_REQUEST = 2;
const int _OPEN_REQUEST = 3;
const int _FULL_PATH_REQUEST = 4;
-const int _DIRECTORY_REQUEST = 5;
-const int _CLOSE_REQUEST = 6;
-const int _POSITION_REQUEST = 7;
-const int _SET_POSITION_REQUEST = 8;
-const int _TRUNCATE_REQUEST = 9;
-const int _LENGTH_REQUEST = 10;
-const int _LENGTH_FROM_PATH_REQUEST = 11;
-const int _LAST_MODIFIED_REQUEST = 12;
-const int _FLUSH_REQUEST = 13;
-const int _READ_BYTE_REQUEST = 14;
-const int _WRITE_BYTE_REQUEST = 15;
-const int _READ_REQUEST = 16;
-const int _READ_LIST_REQUEST = 17;
-const int _WRITE_LIST_REQUEST = 18;
-const int _CREATE_LINK_REQUEST = 19;
-const int _DELETE_LINK_REQUEST = 20;
-const int _LINK_TARGET_REQUEST = 21;
-const int _TYPE_REQUEST = 22;
-const int _IDENTICAL_REQUEST = 23;
-const int _STAT_REQUEST = 24;
+const int _CLOSE_REQUEST = 5;
+const int _POSITION_REQUEST = 6;
+const int _SET_POSITION_REQUEST = 7;
+const int _TRUNCATE_REQUEST = 8;
+const int _LENGTH_REQUEST = 9;
+const int _LENGTH_FROM_PATH_REQUEST = 10;
+const int _LAST_MODIFIED_REQUEST = 11;
+const int _FLUSH_REQUEST = 12;
+const int _READ_BYTE_REQUEST = 13;
+const int _WRITE_BYTE_REQUEST = 14;
+const int _READ_REQUEST = 15;
+const int _READ_LIST_REQUEST = 16;
+const int _WRITE_LIST_REQUEST = 17;
+const int _CREATE_LINK_REQUEST = 18;
+const int _DELETE_LINK_REQUEST = 19;
+const int _LINK_TARGET_REQUEST = 20;
+const int _TYPE_REQUEST = 21;
+const int _IDENTICAL_REQUEST = 22;
+const int _STAT_REQUEST = 23;
// TODO(ager): The only reason for this class is that the patching
// mechanism doesn't seem to like patching a private top level
@@ -313,27 +312,9 @@
throwIfError(result, "Cannot delete file '$_path'");
}
- Future<Directory> directory() {
- _ensureFileService();
- List request = new List(2);
- request[0] = _DIRECTORY_REQUEST;
- request[1] = _path;
- return _fileService.call(request).then((response) {
- if (_isErrorResponse(response)) {
- throw _exceptionFromResponse(response,
- "Cannot retrieve directory for "
- "file '$_path'");
- }
- return new Directory(response);
- });
- }
-
- external static _directory(String path);
-
- Directory directorySync() {
- var result = _directory(path);
- throwIfError(result, "Cannot retrieve directory for file '$_path'");
- return new Directory(result);
+ Directory get directory {
+ Path path = new Path(_path).directoryPath;
+ return new Directory.fromPath(path);
}
Future<RandomAccessFile> open({FileMode mode: FileMode.READ}) {
@@ -507,7 +488,7 @@
static List<String> _decodeLines(List<int> bytes, Encoding encoding) {
if (bytes.length == 0) return [];
var list = [];
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
controller.stream
.transform(new StringDecoder(encoding))
.transform(new LineTransformer())
diff --git a/sdk/lib/io/file_system_entity.dart b/sdk/lib/io/file_system_entity.dart
index 4347f2c..ce84e35 100644
--- a/sdk/lib/io/file_system_entity.dart
+++ b/sdk/lib/io/file_system_entity.dart
@@ -235,6 +235,37 @@
return result;
}
+ /**
+ * Check whether the file system entity with this path exists. Returns
+ * a [:Future<bool>:] that completes with the result.
+ *
+ * Since FileSystemEntity is abstract, every FileSystemEntity object
+ * is actually an instance of one of the subclasses [File],
+ * [Directory], and [Link]. Calling [exists] on an instance of one
+ * of these subclasses checks whether the object exists in the file
+ * system object exists and is of the correct type (file, directory,
+ * or link). To check whether a path points to an object on the
+ * file system, regardless of the object's type, use the [type]
+ * static method.
+ *
+ */
+ Future<bool> exists();
+
+ /**
+ * Synchronously check whether the file system entity with this path
+ * exists.
+ *
+ * Since FileSystemEntity is abstract, every FileSystemEntity object
+ * is actually an instance of one of the subclasses [File],
+ * [Directory], and [Link]. Calling [existsSync] on an instance of
+ * one of these subclasses checks whether the object exists in the
+ * file system object exists and is of the correct type (file,
+ * directory, or link). To check whether a path points to an object
+ * on the file system, regardless of the object's type, use the
+ * [typeSync] static method.
+ */
+ bool existsSync();
+
static Future<FileSystemEntityType> type(String path,
{bool followLinks: true})
=> _getTypeAsync(path, followLinks).then(FileSystemEntityType._lookup);
diff --git a/sdk/lib/io/http.dart b/sdk/lib/io/http.dart
index 913ab8f..4ea77f7 100644
--- a/sdk/lib/io/http.dart
+++ b/sdk/lib/io/http.dart
@@ -666,16 +666,12 @@
String get method;
/**
- * Returns the URI for the request.
+ * Returns the URI for the request. This provides access to the
+ * path, query string and fragment identifier for the request.
*/
Uri get uri;
/**
- * Returns the parsed query string.
- */
- Map<String, String> get queryParameters;
-
- /**
* Returns the request headers.
*/
HttpHeaders get headers;
diff --git a/sdk/lib/io/http_impl.dart b/sdk/lib/io/http_impl.dart
index b27441b..0a16be9 100644
--- a/sdk/lib/io/http_impl.dart
+++ b/sdk/lib/io/http_impl.dart
@@ -78,9 +78,6 @@
class _HttpRequest extends _HttpInboundMessage implements HttpRequest {
final HttpResponse response;
- // Lazy initialized parsed query parameters.
- Map<String, String> _queryParameters;
-
final _HttpServer _httpServer;
final _HttpConnection _httpConnection;
@@ -119,13 +116,6 @@
cancelOnError: cancelOnError);
}
- Map<String, String> get queryParameters {
- if (_queryParameters == null) {
- _queryParameters = _HttpUtils.splitQueryString(uri.query);
- }
- return _queryParameters;
- }
-
Uri get uri => _incoming.uri;
String get method => _incoming.method;
@@ -570,7 +560,8 @@
_ensureController() {
if (_controller != null) return;
- _controller = new StreamController(onPause: () => _subscription.pause(),
+ _controller = new StreamController(sync: true,
+ onPause: () => _subscription.pause(),
onResume: () => _subscription.resume(),
onListen: () => _subscription.resume(),
onCancel: _cancel);
@@ -1939,7 +1930,7 @@
// Set of currently connected clients.
final Set<_HttpConnection> _connections = new Set<_HttpConnection>();
final StreamController<HttpRequest> _controller
- = new StreamController<HttpRequest>();
+ = new StreamController<HttpRequest>(sync: true);
// TODO(ajohnsen): Use close queue?
}
diff --git a/sdk/lib/io/http_parser.dart b/sdk/lib/io/http_parser.dart
index b7aabd2..8edaa0c 100644
--- a/sdk/lib/io/http_parser.dart
+++ b/sdk/lib/io/http_parser.dart
@@ -107,6 +107,7 @@
_HttpDetachedIncoming(StreamSubscription this.subscription,
List<int> this.carryOverData) {
controller = new StreamController<List<int>>(
+ sync: true,
onListen: resume,
onPause: pause,
onResume: resume,
@@ -195,24 +196,25 @@
_HttpParser._(this._requestParser) {
_controller = new StreamController<_HttpIncoming>(
- onListen: () {
- _socketSubscription.resume();
- _paused = false;
- },
- onPause: () {
- _paused = true;
- _pauseStateChanged();
- },
- onResume: () {
- _paused = false;
- _pauseStateChanged();
- },
- onCancel: () {
- try {
- _socketSubscription.cancel();
- } catch (e) {
- }
- });
+ sync: true,
+ onListen: () {
+ _socketSubscription.resume();
+ _paused = false;
+ },
+ onPause: () {
+ _paused = true;
+ _pauseStateChanged();
+ },
+ onResume: () {
+ _paused = false;
+ _pauseStateChanged();
+ },
+ onCancel: () {
+ try {
+ _socketSubscription.cancel();
+ } catch (e) {
+ }
+ });
_reset();
}
@@ -883,6 +885,7 @@
assert(!_bodyPaused);
var incoming;
_bodyController = new StreamController<List<int>>(
+ sync: true,
onListen: () {
if (incoming != _incoming) return;
assert(_bodyPaused);
diff --git a/sdk/lib/io/io_sink.dart b/sdk/lib/io/io_sink.dart
index 8e8b71f..4dab40f 100644
--- a/sdk/lib/io/io_sink.dart
+++ b/sdk/lib/io/io_sink.dart
@@ -132,7 +132,7 @@
throw new StateError("StreamSink is closed");
}
if (_controllerInstance == null) {
- _controllerInstance = new StreamController<T>();
+ _controllerInstance = new StreamController<T>(sync: true);
_controllerCompleter = new Completer();
_target.addStream(_controller.stream)
.then(
diff --git a/sdk/lib/io/link.dart b/sdk/lib/io/link.dart
index bb64fe9..a179f66 100644
--- a/sdk/lib/io/link.dart
+++ b/sdk/lib/io/link.dart
@@ -20,19 +20,6 @@
factory Link.fromPath(Path path) => new _Link.fromPath(path);
/**
- * Checks if the link exists. The link may exist, even if its target
- * is missing or deleted.
- * Returns a [:Future<bool>:] that completes when the answer is known.
- */
- Future<bool> exists();
-
- /**
- * Synchronously checks if the link exists. The link may exist, even if
- * its target is missing or deleted.
- */
- bool existsSync();
-
- /**
* Creates a symbolic link. Returns a [:Future<Link>:] that completes with
* the link when it has been created. If the link exists,
* the future will complete with an error.
diff --git a/sdk/lib/io/mime_multipart_parser.dart b/sdk/lib/io/mime_multipart_parser.dart
index dc3f206..1e3c548 100644
--- a/sdk/lib/io/mime_multipart_parser.dart
+++ b/sdk/lib/io/mime_multipart_parser.dart
@@ -101,6 +101,7 @@
Stream<MimeMultipart> bind(Stream<List<int>> stream) {
_controller = new StreamController(
+ sync: true,
onPause: _pauseStream,
onResume:_resumeStream,
onCancel: () {
@@ -293,6 +294,7 @@
case _HEADER_ENDING:
_expect(byte, _CharCode.LF);
_multipartController = new StreamController(
+ sync: true,
onPause: () {
_pauseStream();
},
diff --git a/sdk/lib/io/secure_server_socket.dart b/sdk/lib/io/secure_server_socket.dart
index 7d7dfd1..18966a3 100644
--- a/sdk/lib/io/secure_server_socket.dart
+++ b/sdk/lib/io/secure_server_socket.dart
@@ -122,6 +122,7 @@
bool this.requireClientCertificate) {
_socket = serverSocket;
_controller = new StreamController<RawSecureSocket>(
+ sync: true,
onListen: _onSubscriptionStateChange,
onPause: _onPauseStateChange,
onResume: _onPauseStateChange,
diff --git a/sdk/lib/io/secure_socket.dart b/sdk/lib/io/secure_socket.dart
index 4ed4da4..0db4e46 100644
--- a/sdk/lib/io/secure_socket.dart
+++ b/sdk/lib/io/secure_socket.dart
@@ -149,23 +149,30 @@
* arguments.
*
* The optional argument [database] is the path to a certificate database
- * containing root certificates for verifying certificate paths on
+ * directory containing root certificates for verifying certificate paths on
* client connections, and server certificates to provide on server
* connections. The argument [password] should be used when creating
* secure server sockets, to allow the private key of the server
* certificate to be fetched. If [useBuiltinRoots] is true (the default),
* then a built-in set of root certificates for trusted certificate
* authorities is merged with the certificates in the database.
+ * The list of built-in root certificates, and documentation about this
+ * default database, is available at
+ * http://www.mozilla.org/projects/security/certs/included/ .
+ *
+ * If the [database] argument is omitted, then only the
+ * builtin root certificates are used. If [useBuiltinRoots] is also false,
+ * then no certificates are available.
*
* Examples:
* 1) Use only the builtin root certificates:
* SecureSocket.initialize(); or
*
- * 2) Use a specified database and the builtin roots:
+ * 2) Use a specified database directory and the builtin roots:
* SecureSocket.initialize(database: 'path/to/my/database',
* password: 'my_password');
*
- * 3) Use a specified database, without builtin roots:
+ * 3) Use a specified database directory, without builtin roots:
* SecureSocket.initialize(database: 'path/to/my/database',
* password: 'my_password'.
* useBuiltinRoots: false);
@@ -424,6 +431,7 @@
bool this.sendClientCertificate,
bool this.onBadCertificate(X509Certificate certificate)) {
_controller = new StreamController<RawSocketEvent>(
+ sync: true,
onListen: _onSubscriptionStateChange,
onPause: _onPauseStateChange,
onResume: _onPauseStateChange,
diff --git a/sdk/lib/io/string_transformer.dart b/sdk/lib/io/string_transformer.dart
index ec6d0e2..f127b38 100644
--- a/sdk/lib/io/string_transformer.dart
+++ b/sdk/lib/io/string_transformer.dart
@@ -186,7 +186,7 @@
if (bytes.length == 0) return "";
var string;
var error;
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
controller.stream
.transform(new StringDecoder(encoding))
.listen((data) => string = data,
@@ -205,7 +205,7 @@
if (bytes.length == 0) return "";
var string;
var error;
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
controller.stream
.transform(new Utf8DecoderTransformer(null))
.listen((data) => string = data,
@@ -223,7 +223,7 @@
List<int> _encodeString(String string, [Encoding encoding = Encoding.UTF_8]) {
if (string.length == 0) return [];
var bytes;
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
controller.stream
.transform(new StringEncoder(encoding))
.listen((data) => bytes = data);
diff --git a/sdk/lib/io/websocket_impl.dart b/sdk/lib/io/websocket_impl.dart
index 77c3456..8108084 100644
--- a/sdk/lib/io/websocket_impl.dart
+++ b/sdk/lib/io/websocket_impl.dart
@@ -93,7 +93,7 @@
throw new WebSocketException("Protocol error");
}
_currentMessageType = _WebSocketMessageType.TEXT;
- _controller = new StreamController();
+ _controller = new StreamController(sync: true);
_controller.stream
.transform(new Utf8DecoderTransformer(null))
.fold(new StringBuffer(), (buffer, str) => buffer..write(str))
@@ -109,7 +109,7 @@
throw new WebSocketException("Protocol error");
}
_currentMessageType = _WebSocketMessageType.BINARY;
- _controller = new StreamController();
+ _controller = new StreamController(sync: true);
_controller.stream
.fold(new _BufferList(), (buffer, data) => buffer..add(data))
.then((buffer) {
@@ -376,7 +376,7 @@
class _WebSocketTransformerImpl implements WebSocketTransformer {
final StreamController<WebSocket> _controller =
- new StreamController<WebSocket>();
+ new StreamController<WebSocket>(sync: true);
Stream<WebSocket> bind(Stream<HttpRequest> stream) {
stream.listen((request) {
@@ -566,7 +566,8 @@
_ensureController() {
if (_controller != null) return;
- _controller = new StreamController(onPause: () => _subscription.pause(),
+ _controller = new StreamController(sync: true,
+ onPause: () => _subscription.pause(),
onResume: () => _subscription.resume(),
onCancel: _onListen);
var stream = _controller.stream.transform(
@@ -628,7 +629,7 @@
class _WebSocketImpl extends Stream implements WebSocket {
- final StreamController _controller = new StreamController();
+ final StreamController _controller = new StreamController(sync: true);
StreamSink _sink;
final Socket _socket;
diff --git a/sdk/lib/isolate/isolate_stream.dart b/sdk/lib/isolate/isolate_stream.dart
index 0f0f63f..f16271e 100644
--- a/sdk/lib/isolate/isolate_stream.dart
+++ b/sdk/lib/isolate/isolate_stream.dart
@@ -38,7 +38,7 @@
class IsolateStream extends Stream<dynamic> {
bool _isClosed = false;
final ReceivePort _port;
- StreamController _controller = new StreamController();
+ StreamController _controller = new StreamController(sync: true);
IsolateStream._fromOriginalReceivePort(this._port) {
_port.receive((message, replyTo) {
diff --git a/sdk/lib/mdv_observe_impl/mdv_observe_impl.dart b/sdk/lib/mdv_observe_impl/mdv_observe_impl.dart
index 577f0b8..e83a15d 100644
--- a/sdk/lib/mdv_observe_impl/mdv_observe_impl.dart
+++ b/sdk/lib/mdv_observe_impl/mdv_observe_impl.dart
@@ -63,15 +63,15 @@
* call [notifyPropertyChange]. See that method for an example.
*/
abstract class ObservableMixin implements Observable {
- StreamController _multiplexController;
+ StreamController _broadcastController;
List<ChangeRecord> _changes;
Stream<List<ChangeRecord>> get changes {
- if (_multiplexController == null) {
- _multiplexController =
- new StreamController<List<ChangeRecord>>.broadcast();
+ if (_broadcastController == null) {
+ _broadcastController =
+ new StreamController<List<ChangeRecord>>.broadcast(sync: true);
}
- return _multiplexController.stream;
+ return _broadcastController.stream;
}
void _deliverChanges() {
@@ -79,7 +79,7 @@
_changes = null;
if (hasObservers && changes != null) {
// TODO(jmesserly): make "changes" immutable
- _multiplexController.add(changes);
+ _broadcastController.add(changes);
}
}
@@ -87,8 +87,8 @@
* True if this object has any observers, and should call
* [notifyPropertyChange] for changes.
*/
- bool get hasObservers => _multiplexController != null &&
- _multiplexController.hasListener;
+ bool get hasObservers => _broadcastController != null &&
+ _broadcastController.hasListener;
/**
* Notify that the field [name] of this object has been changed.
diff --git a/sdk/lib/mirrors/mirrors.dart b/sdk/lib/mirrors/mirrors.dart
index 1e9377e..722be26 100644
--- a/sdk/lib/mirrors/mirrors.dart
+++ b/sdk/lib/mirrors/mirrors.dart
@@ -176,6 +176,11 @@
* The source location of this Dart language entity.
*/
SourceLocation get location;
+
+ /**
+ * A list of the metadata associated with this declaration.
+ */
+ List<InstanceMirror> get metadata;
}
/**
diff --git a/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart b/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart
index d7afeed..1fcecdb 100644
--- a/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart
+++ b/sdk/lib/typed_data/dart2js/typed_data_dart2js.dart
@@ -123,22 +123,12 @@
}
class ByteData extends TypedData native "DataView" {
- factory ByteData(int length) => JS('ByteData', 'new DataView(#)', length);
+ factory ByteData(int length) =>
+ _TypedArrayFactoryProvider.createByteData(length);
- factory ByteData.view(ByteBuffer buffer, [int byteOffset, int byteLength]) {
- if (?byteLength) {
- return ByteData._create_1(buffer, byteOffset, byteLength);
- }
- if (?byteOffset) {
- return ByteData._create_2(buffer, byteOffset);
- }
- return ByteData._create_3(buffer);
- }
-
- static ByteData _create_1(buffer, byteOffset, byteLength) =>
- JS('ByteData', 'new DataView(#,#,#)', buffer, byteOffset, byteLength);
- static ByteData _create_2(buffer, byteOffset) => JS('ByteData', 'new DataView(#,#)', buffer, byteOffset);
- static ByteData _create_3(buffer) => JS('ByteData', 'new DataView(#)', buffer);
+ factory ByteData.view(ByteBuffer buffer, [int byteOffset, int byteLength]) =>
+ _TypedArrayFactoryProvider.createByteData_fromBuffer(
+ buffer, byteOffset, byteLength);
num getFloat32(int byteOffset, [Endianness endian=Endianness.BIG_ENDIAN]) =>
_getFloat32(byteOffset, endian._littleEndian);
@@ -2280,7 +2270,7 @@
}
factory Float32x4List.view(ByteBuffer buffer,
- [int offsetInBytes = 0, int length]) {
+ [int offsetInBytes = 0, int length]) {
throw new UnsupportedError("Float32x4List not supported by dart2js.");
}
diff --git a/sdk/lib/typed_data/typed_data.dart b/sdk/lib/typed_data/typed_data.dart
index 55274b2..043a61e 100644
--- a/sdk/lib/typed_data/typed_data.dart
+++ b/sdk/lib/typed_data/typed_data.dart
@@ -430,7 +430,7 @@
* more space- and time-efficient than the default [List] implementation.
* Indexed store clamps the value to range 0..0xFF.
*/
-abstract class Uint8ClampedList implements List<int>, TypedData {
+abstract class Uint8ClampedList implements Uint8List {
/**
* Creates a [Uint8ClampedList] of the specified length (in elements), all of
* whose elements are initially zero.
diff --git a/sdk/lib/web_audio/dart2js/web_audio_dart2js.dart b/sdk/lib/web_audio/dart2js/web_audio_dart2js.dart
index 83732db..30413ba 100644
--- a/sdk/lib/web_audio/dart2js/web_audio_dart2js.dart
+++ b/sdk/lib/web_audio/dart2js/web_audio_dart2js.dart
@@ -1001,8 +1001,8 @@
*/
Stream<AudioProcessingEvent> get onAudioProcess {
if (_eventStream == null) {
- var controller = new StreamController();
- var callback = (audioData) {
+ var controller = new StreamController(sync: true);
+ var callback = (audioData) {
if (controller.hasListener) {
// This stream is a strange combination of broadcast and single
// subscriber streams. We only allow one listener, but if there is
diff --git a/sdk/lib/web_audio/dartium/web_audio_dartium.dart b/sdk/lib/web_audio/dartium/web_audio_dartium.dart
index 786b08d..2eefb8c 100644
--- a/sdk/lib/web_audio/dartium/web_audio_dartium.dart
+++ b/sdk/lib/web_audio/dartium/web_audio_dartium.dart
@@ -1258,8 +1258,8 @@
*/
Stream<AudioProcessingEvent> get onAudioProcess {
if (_eventStream == null) {
- var controller = new StreamController();
- var callback = (audioData) {
+ var controller = new StreamController(sync: true);
+ var callback = (audioData) {
if (controller.hasListener) {
// This stream is a strange combination of broadcast and single
// subscriber streams. We only allow one listener, but if there is
diff --git a/tests/co19/co19-analyzer.status b/tests/co19/co19-analyzer.status
index f037e57..ba2d15e 100644
--- a/tests/co19/co19-analyzer.status
+++ b/tests/co19/co19-analyzer.status
@@ -38,11 +38,6 @@
Language/07_Classes/6_Constructors/3_Constant_Constructors_A05_t02: fail
Language/07_Classes/6_Constructors/3_Constant_Constructors_A05_t03: fail
Language/07_Classes/7_Static_Methods_A01_t01: fail
-Language/07_Classes/9_Superclasses_A03_t01: fail
-Language/07_Classes/9_Superclasses_A03_t02: fail
-Language/08_Interfaces/5_Superinterfaces_A01_t03: fail
-Language/08_Interfaces/5_Superinterfaces_A01_t04: fail
-Language/08_Interfaces/5_Superinterfaces_A04_t03: fail
Language/09_Generics/09_Generics_A04_t07: fail
Language/11_Expressions/01_Constants_A01_t01: fail
Language/11_Expressions/01_Constants_A08_t02: fail
@@ -70,7 +65,6 @@
Language/11_Expressions/07_Maps_A02_t02: fail
Language/11_Expressions/11_Instance_Creation/1_New_A13_t02: fail
Language/11_Expressions/11_Instance_Creation/2_Const_A06_t01: fail
-Language/11_Expressions/11_Instance_Creation/2_Const_A06_t02: fail
Language/11_Expressions/11_Instance_Creation/2_Const_A10_t01: fail
Language/11_Expressions/11_Instance_Creation_A05_t02: fail
Language/11_Expressions/14_Function_Invocation/1_Actual_Argument_List_Evaluation_A02_t01: fail
diff --git a/tests/co19/co19-dart2dart.status b/tests/co19/co19-dart2dart.status
index e639cac..69035a4 100644
--- a/tests/co19/co19-dart2dart.status
+++ b/tests/co19/co19-dart2dart.status
@@ -9,7 +9,6 @@
Language/11_Expressions/11_Instance_Creation/2_Const_A03_t01: Fail # TODO(dart2dart-team): Please triage this failure.
Language/11_Expressions/11_Instance_Creation_A05_t02: Fail # TODO(dart2dart-team): Please triage this failure.
Language/11_Expressions/14_Function_Invocation/3_Unqualified_Invocation_A01_t10: Fail # TODO(dart2dart-team): Please triage this failure.
-Language/11_Expressions/33_Argument_Definition_Test_A02_t01: Fail # TODO(dart2dart-team): Please triage this failure.
Language/11_Expressions/33_Argument_Definition_Test_A02_t02: Fail # TODO(dart2dart-team): Please triage this failure.
Language/12_Statements/03_Variable_Declaration_A04_t07: Fail # TODO(dart2dart-team): Please triage this failure.
Language/12_Statements/03_Variable_Declaration_A04_t08: Fail # TODO(dart2dart-team): Please triage this failure.
@@ -405,9 +404,6 @@
[ $compiler == dart2dart && $minified ]
-Language/11_Expressions/33_Argument_Definition_Test_A03_t01: Fail # TODO(dart2dart-team): Please triage this failure.
-Language/11_Expressions/33_Argument_Definition_Test_A03_t02: Fail # TODO(dart2dart-team): Please triage this failure.
-
Language/11_Expressions/14_Function_Invocation/4_Function_Expression_Invocation_A01_t02: Fail, OK # co19 issue 396
Language/11_Expressions/17_Getter_Invocation_A02_t01: Fail, OK # co19 issue 396
Language/11_Expressions/18_Assignment_A05_t02: Fail, OK # co19 issue 396
diff --git a/tests/co19/co19-runtime.status b/tests/co19/co19-runtime.status
index 79111bd..544150d 100644
--- a/tests/co19/co19-runtime.status
+++ b/tests/co19/co19-runtime.status
@@ -510,13 +510,29 @@
[ $compiler == none && $runtime == vm && $unchecked ]
LibTest/core/List/setRange_A05_t01: Fail # setRange now takes end-argument. Issue 402
-[ $compiler == none && $arch == simarm ]
+[ $compiler == none && $runtime == vm && $arch == arm ]
*: Skip
+[ $compiler == none && $runtime == vm && $arch == simarm]
+LibTest/math/tan_A01_t01: Fail
+LibTest/math/Random/nextDouble_A01_t01.dart: Pass, Fail
+LibTest/core/int/operator_left_shift_A01_t02: Fail
+LibTest/core/int/operator_unary_minus_A01_t01: Fail
-[ $compiler == none && $arch == simmips ]
+[ $compiler == none && $runtime == vm && $arch == simarm && $mode == debug]
+LibTest/core/Expect/throws_A01_t04: Crash
+LibTest/core/List/sort_A01_t04: Crash
+LibTest/core/List/sort_A01_t05: Crash
+LibTest/core/List/sort_A01_t06: Crash
+LibTest/core/double/ceil_A01_t02: Fail
+LibTest/core/double/floor_A01_t02: Fail
+LibTest/core/double/truncate_A01_t01: Fail
+LibTest/core/int/operator_left_shift_A01_t02: Fail
+LibTest/core/int/operator_unary_minus_A01_t01: Fail
+
+[ $compiler == none && $runtime == vm && $arch == mips ]
*: Skip
-
-[ $compiler == none && $arch == mips ]
+[ $compiler == none && $runtime == vm && $arch == simmips ]
*: Skip
+
diff --git a/tests/compiler/dart2js/analyze_api_test.dart b/tests/compiler/dart2js/analyze_api_test.dart
index a4cca28..29ad0ef 100644
--- a/tests/compiler/dart2js/analyze_api_test.dart
+++ b/tests/compiler/dart2js/analyze_api_test.dart
@@ -22,10 +22,7 @@
const Map<String, List<String>> WHITE_LIST = const {
'html_dart2js.dart':
const ['Warning: Using "new Symbol"', // Issue 10565.
- // Issue 10688:
- 'Warning: no property named',
- "Warning: 'UnsupportedError' is not callable",
- "Warning: no operator [] in class Iterable"],
+ ],
};
void main() {
diff --git a/tests/compiler/dart2js/class_codegen_test.dart b/tests/compiler/dart2js/class_codegen_test.dart
index 3380a43..24d8c63 100644
--- a/tests/compiler/dart2js/class_codegen_test.dart
+++ b/tests/compiler/dart2js/class_codegen_test.dart
@@ -86,7 +86,7 @@
constructor1() {
String generated = compileAll(TEST_FIVE);
- Expect.isTrue(generated.contains(r"new $.A(a);"));
+ Expect.isTrue(generated.contains(new RegExp(r"new [$a-z]+\.A\(a\);")));
}
main() {
diff --git a/tests/compiler/dart2js/dart_backend_test.dart b/tests/compiler/dart2js/dart_backend_test.dart
index 59fe13f..112f0fa 100644
--- a/tests/compiler/dart2js/dart_backend_test.dart
+++ b/tests/compiler/dart2js/dart_backend_test.dart
@@ -23,6 +23,7 @@
class Function {}
class List<T> {}
class Map<K,V> {}
+class BoundClosure {}
class Closure {}
class Dynamic_ {}
class Null {}
@@ -611,7 +612,7 @@
}
}
-fooglobal(arg,[optionalarg = 7]) {
+fooglobal(arg,{optionalarg: 7}) {
arg = 6;
}
@@ -622,7 +623,7 @@
}
''';
var expectedResult =
- 'class B{var E;static C(A){A=5;}}D(A,[optionalarg=7]){A=6;}'
+ 'class B{var E;static C(A){A=5;}}D(A,{optionalarg: 7}){A=6;}'
'main(){new B().E;B.C(8);D(8);}';
testDart2Dart(src, continuation:
(String result) { Expect.equals(expectedResult, result); }, minify: true);
diff --git a/tests/compiler/dart2js/interceptor_test.dart b/tests/compiler/dart2js/interceptor_test.dart
index 5f7caa6..e0f544d 100644
--- a/tests/compiler/dart2js/interceptor_test.dart
+++ b/tests/compiler/dart2js/interceptor_test.dart
@@ -42,7 +42,7 @@
// Check that one-shot interceptors preserve variable names, see
// https://code.google.com/p/dart/issues/detail?id=8106.
generated = compile(TEST_TWO, entry: 'foo');
- Expect.isTrue(generated.contains(r'$.$add$n(a, 42)'));
+ Expect.isTrue(generated.contains(new RegExp(r'[$a-z]+\.\$add\$n\(a, 42\)')));
Expect.isTrue(generated.contains('myVariableName'));
// Check that an intercepted getter that does not need to be
@@ -50,6 +50,7 @@
// access.
generated = compile(TEST_THREE, entry: 'foo');
Expect.isFalse(generated.contains(r'a.get$length()'));
- Expect.isTrue(generated.contains(r'$.A$().length'));
- Expect.isTrue(generated.contains(r'$.get$length$a(a)'));
+ Expect.isTrue(generated.contains(new RegExp(r'[$a-z]+\.A\$\(\)\.length')));
+ Expect.isTrue(
+ generated.contains(new RegExp(r'[$a-z]+\.get\$length\$a\(a\)')));
}
diff --git a/tests/compiler/dart2js/mock_compiler.dart b/tests/compiler/dart2js/mock_compiler.dart
index d0c1089..a9fa9de 100644
--- a/tests/compiler/dart2js/mock_compiler.dart
+++ b/tests/compiler/dart2js/mock_compiler.dart
@@ -53,6 +53,11 @@
boolConversionCheck(x) {}
abstract class JavaScriptIndexingBehavior {}
class JSInvocationMirror {}
+ class BoundClosure {
+ var self;
+ var target;
+ var receiver;
+ }
class Closure {}
class Null {}
class Dynamic_ {}
diff --git a/tests/compiler/dart2js/patch_test.dart b/tests/compiler/dart2js/patch_test.dart
index 3cf4b46..b0cec7d 100644
--- a/tests/compiler/dart2js/patch_test.dart
+++ b/tests/compiler/dart2js/patch_test.dart
@@ -10,9 +10,12 @@
import "mock_compiler.dart";
import "parser_helper.dart";
-Compiler applyPatch(String script, String patch) {
+Compiler applyPatch(String script, String patch,
+ {bool analyzeAll: false, bool analyzeOnly: false}) {
String core = "$DEFAULT_CORELIB\n$script";
- MockCompiler compiler = new MockCompiler(coreSource: core);
+ MockCompiler compiler = new MockCompiler(coreSource: core,
+ analyzeAll: analyzeAll,
+ analyzeOnly: analyzeOnly);
var uri = Uri.parse("core.dartp");
compiler.sourceFiles[uri.toString()] = new MockFile(patch);
var handler = new LibraryDependencyHandler(compiler);
@@ -715,6 +718,34 @@
Expect.isTrue(typedSelector.applies(method, compiler));
}
+void testAnalyzeAllInjectedMembers() {
+ String patchText = """
+ void method() {
+ String s = 0;
+ }
+ """;
+ var compiler = applyPatch('', patchText, analyzeAll: true, analyzeOnly: true);
+ compiler.librariesToAnalyzeWhenRun = [Uri.parse('dart:core')];
+ compiler.runCompiler(null);
+ compareWarningKinds(patchText,
+ [MessageKind.NOT_ASSIGNABLE], compiler.warnings);
+}
+
+void testTypecheckPatchedMembers() {
+ String originText = "external void method();";
+ String patchText = """
+ patch void method() {
+ String s = 0;
+ }
+ """;
+ var compiler = applyPatch(originText, patchText,
+ analyzeAll: true, analyzeOnly: true);
+ compiler.librariesToAnalyzeWhenRun = [Uri.parse('dart:core')];
+ compiler.runCompiler(null);
+ compareWarningKinds(patchText,
+ [MessageKind.NOT_ASSIGNABLE], compiler.warnings);
+}
+
main() {
testPatchConstructor();
testPatchFunction();
@@ -744,4 +775,7 @@
testPatchNonFunction();
testPatchAndSelector();
+
+ testAnalyzeAllInjectedMembers();
+ testTypecheckPatchedMembers();
}
diff --git a/tests/compiler/dart2js/private_test.dart b/tests/compiler/dart2js/private_test.dart
new file mode 100644
index 0000000..3390c9f
--- /dev/null
+++ b/tests/compiler/dart2js/private_test.dart
@@ -0,0 +1,165 @@
+// 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.
+
+import "package:expect/expect.dart";
+import 'mock_compiler.dart';
+
+import '../../../sdk/lib/_internal/compiler/implementation/source_file.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart'
+ hide SourceString;
+
+const String PRIVATE_SOURCE_URI = 'src:private';
+const String PRIVATE_SOURCE = '''
+
+var _privateVariable;
+void _privateFunction() {}
+
+class _PrivateClass {
+ _PrivateClass();
+ _PrivateClass.publicConstructor();
+ _PrivateClass._privateConstructor();
+
+ var _privateField;
+ get _privateGetter => null;
+ void set _privateSetter(var value) {}
+ void _privateMethod() {}
+
+ var publicField;
+ get publicGetter => null;
+ void set publicSetter(var value) {}
+ void publicMethod() {}
+}
+
+class PublicClass extends _PrivateClass {
+ PublicClass() : super();
+ PublicClass.publicConstructor() : super.publicConstructor();
+ PublicClass._privateConstructor() : super._privateConstructor();
+
+ _PrivateClass get private => this;
+}
+''';
+
+
+void analyze(String text, [expectedWarnings]) {
+ if (expectedWarnings == null) expectedWarnings = [];
+ if (expectedWarnings is !List) expectedWarnings = [expectedWarnings];
+
+ MockCompiler compiler = new MockCompiler(analyzeOnly: true);
+ compiler.registerSource(Uri.parse(PRIVATE_SOURCE_URI), PRIVATE_SOURCE);
+ compiler.diagnosticHandler = (uri, int begin, int end, String message, kind) {
+ SourceFile sourceFile = compiler.sourceFiles[uri.toString()];
+ if (sourceFile != null) {
+ print(sourceFile.getLocationMessage(message, begin, end, true, (x) => x));
+ } else {
+ print(message);
+ }
+ };
+
+ String source = '''
+ library public;
+
+ import '$PRIVATE_SOURCE_URI';
+
+ void main() {
+ PublicClass publicClass;
+ $text
+ }
+ ''';
+ Uri uri = Uri.parse('src:public');
+ compiler.registerSource(uri, source);
+ compiler.runCompiler(uri);
+ compareWarningKinds(text, expectedWarnings, compiler.warnings);
+}
+
+void main() {
+ // Read from private variable.
+ analyze('var value = _privateVariable;', MessageKind.CANNOT_RESOLVE);
+ // Write to private variable.
+ analyze('_privateVariable = 0;', MessageKind.CANNOT_RESOLVE);
+ // Access private function.
+ analyze('var value = _privateFunction;', MessageKind.CANNOT_RESOLVE);
+ // Call private function.
+ analyze('_privateFunction();', MessageKind.CANNOT_RESOLVE);
+
+ // Call unnamed (public) constructor on private class.
+ analyze('new _PrivateClass();', MessageKind.CANNOT_RESOLVE);
+ // Call public constructor on private class.
+ analyze('new _PrivateClass.publicConstructor();', MessageKind.CANNOT_RESOLVE);
+ // Call private constructor on private class.
+ analyze('new _PrivateClass._privateConstructor();',
+ MessageKind.CANNOT_RESOLVE);
+ // Call public getter of private type.
+ analyze('var value = publicClass.private;');
+ // Read from private field on private class.
+ analyze('var value = publicClass.private._privateField;',
+ MessageKind.PRIVATE_ACCESS);
+ // Write to private field on private class.
+ analyze('publicClass.private._privateField = 0;',
+ MessageKind.PRIVATE_ACCESS);
+ // Call private getter on private class.
+ analyze('var value = publicClass.private._privateGetter;',
+ MessageKind.PRIVATE_ACCESS);
+ // Call private setter on private class.
+ analyze('publicClass.private._privateSetter = 0;',
+ MessageKind.PRIVATE_ACCESS);
+ // Access private method on private class.
+ analyze('var value = publicClass.private._privateMethod;',
+ MessageKind.PRIVATE_ACCESS);
+ // Call private method on private class.
+ analyze('publicClass.private._privateMethod();',
+ MessageKind.PRIVATE_ACCESS);
+
+ // Read from public field on private class.
+ analyze('var value = publicClass.private.publicField;');
+ // Write to public field on private class.
+ analyze('publicClass.private.publicField = 0;');
+ // Call public getter on private class.
+ analyze('var value = publicClass.private.publicGetter;');
+ // Call public setter on private class.
+ analyze('publicClass.private.publicSetter = 0;');
+ // Access public method on private class.
+ analyze('var value = publicClass.private.publicMethod;');
+ // Call public method on private class.
+ analyze('publicClass.private.publicMethod();');
+
+ // Call unnamed (public) constructor on public class.
+ analyze('publicClass = new PublicClass();');
+ // Call public constructor on public class.
+ analyze('publicClass = new PublicClass.publicConstructor();');
+ // Call private constructor on public class.
+ analyze('publicClass = new PublicClass._privateConstructor();',
+ MessageKind.CANNOT_FIND_CONSTRUCTOR);
+ // Read from private field on public class.
+ analyze('var value = publicClass._privateField;',
+ MessageKind.PRIVATE_ACCESS);
+ // Write to private field on public class.
+ analyze('publicClass._privateField = 0;',
+ MessageKind.PRIVATE_ACCESS);
+ // Call private getter on public class.
+ analyze('var value = publicClass._privateGetter;',
+ MessageKind.PRIVATE_ACCESS);
+ // Call private setter on public class.
+ analyze('publicClass._privateSetter = 0;',
+ MessageKind.PRIVATE_ACCESS);
+ // Access private method on public class.
+ analyze('var value = publicClass._privateMethod;',
+ MessageKind.PRIVATE_ACCESS);
+ // Call private method on public class.
+ analyze('publicClass._privateMethod();',
+ MessageKind.PRIVATE_ACCESS);
+
+ // Read from public field on public class.
+ analyze('var value = publicClass.publicField;');
+ // Write to public field on public class.
+ analyze('publicClass.publicField = 0;');
+ // Call public getter on public class.
+ analyze('var value = publicClass.publicGetter;');
+ // Call public setter on public class.
+ analyze('publicClass.publicSetter = 0;');
+ // Access public method on public class.
+ analyze('var value = publicClass.publicMethod;');
+ // Call public method on public class.
+ analyze('publicClass.publicMethod();');
+}
+
diff --git a/tests/compiler/dart2js/simple_inferrer_test.dart b/tests/compiler/dart2js/simple_inferrer_test.dart
index c9776bb..19be754 100644
--- a/tests/compiler/dart2js/simple_inferrer_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_test.dart
@@ -386,6 +386,8 @@
}
main() {
+ // Ensure a function class is being instantiated.
+ () => 42;
returnNum1(true);
returnNum2(true);
returnInt1(true);
diff --git a/tests/compiler/dart2js/static_closure_test.dart b/tests/compiler/dart2js/static_closure_test.dart
index e6aff7a..4003c61 100644
--- a/tests/compiler/dart2js/static_closure_test.dart
+++ b/tests/compiler/dart2js/static_closure_test.dart
@@ -17,5 +17,5 @@
// If this test fail, please take a look at the use of
// toStringWrapper in captureStackTrace in js_helper.dart.
- Expect.isTrue(code.contains(r'print($.main$closure);'));
+ Expect.isTrue(code.contains(new RegExp(r'print\([$a-z]+\.main\$closure\);')));
}
diff --git a/tests/compiler/dart2js/type_checker_test.dart b/tests/compiler/dart2js/type_checker_test.dart
index 1a6bc16..c9c0221 100644
--- a/tests/compiler/dart2js/type_checker_test.dart
+++ b/tests/compiler/dart2js/type_checker_test.dart
@@ -32,6 +32,7 @@
testFor,
testWhile,
testTry,
+ testSwitch,
testOperators,
testConstructorInvocationArgumentCount,
testConstructorInvocationArgumentTypes,
@@ -42,6 +43,7 @@
testConditionalExpression,
testIfStatement,
testThis,
+ testSuper,
testOperatorsAssignability];
for (Function test in tests) {
setup();
@@ -123,6 +125,17 @@
[MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]);
}
+
+testSwitch() {
+ analyze("switch (0) { case 1: break; case 2: break; }");
+ analyze("switch (0) { case 1: int i = ''; break; case 2: break; }",
+ MessageKind.NOT_ASSIGNABLE);
+ analyze("switch (0) { case '': break; case 2: break; }",
+ MessageKind.NOT_ASSIGNABLE);
+ analyze("switch ('') { case 1: break; case 2: break; }",
+ [MessageKind.NOT_ASSIGNABLE, MessageKind.NOT_ASSIGNABLE]);
+}
+
testOperators() {
// TODO(karlklose): add the DartC tests for operators when we can parse
// classes with operators.
@@ -540,6 +553,24 @@
analyzeIn(foo, "{ Foo f = this; }");
}
+testSuper() {
+ String script = r'''
+ class A {
+ String field = "42";
+ }
+
+ class B extends A {
+ Object field = 42;
+ }
+ ''';
+ LibraryElement library = mockLibrary(compiler, script);
+ compiler.parseScript(script, library);
+ ClassElement B = library.find(const SourceString("B"));
+ analyzeIn(B, "{ int i = super.field; }", MessageKind.NOT_ASSIGNABLE);
+ analyzeIn(B, "{ Object o = super.field; }");
+ analyzeIn(B, "{ String s = super.field; }");
+}
+
const String CLASSES_WITH_OPERATORS = '''
class Operators {
Operators operator +(Operators other) => this;
diff --git a/tests/compiler/dart2js/type_guard_unuser_test.dart b/tests/compiler/dart2js/type_guard_unuser_test.dart
index d26d8c6..4cad5fd 100644
--- a/tests/compiler/dart2js/type_guard_unuser_test.dart
+++ b/tests/compiler/dart2js/type_guard_unuser_test.dart
@@ -45,7 +45,9 @@
RegExp regexp = new RegExp(getIntTypeCheck(anyIdentifier));
Iterator<Match> matches = regexp.allMatches(generated).iterator;
checkNumberOfMatches(matches, 0);
- Expect.isTrue(generated.contains(r'return a === true ? $.foo(2) : b;'));
+ Expect.isTrue(
+ generated.contains(
+ new RegExp(r'return a === true \? [$a-z]+\.foo\(2\) : b;')));
generated = compile(TEST_TWO, entry: 'foo');
regexp = new RegExp("foo\\(1\\)");
diff --git a/tests/corelib/corelib.status b/tests/corelib/corelib.status
index 7e3010d..3008f2e 100644
--- a/tests/corelib/corelib.status
+++ b/tests/corelib/corelib.status
@@ -4,9 +4,6 @@
reg_exp_unicode_2_test: Fail # Bug 6592
-[ $compiler == dart2js && $checked ]
-list_test: Fail, OK # dartbug.com/10708
-
[ $compiler == none ]
unicode_test: Fail # Bug 6706
*dartc_test: Skip
@@ -97,6 +94,9 @@
list_insert_test: fail
list_removeat_test: fail
+[ $arch == arm ]
+*: Skip
+
[ $arch == simarm ]
*: Skip
diff --git a/tests/corelib/list_test.dart b/tests/corelib/list_test.dart
index 395cc57..8883e49 100644
--- a/tests/corelib/list_test.dart
+++ b/tests/corelib/list_test.dart
@@ -14,6 +14,12 @@
testTypedList(new Int16List(4));
testTypedList(new Uint32List(4));
testTypedList(new Int32List(4));
+ testTypedList(new Uint8List(4).toList(growable: false));
+ testTypedList(new Int8List(4).toList(growable: false));
+ testTypedList(new Uint16List(4).toList(growable: false));
+ testTypedList(new Int16List(4).toList(growable: false));
+ testTypedList(new Uint32List(4).toList(growable: false));
+ testTypedList(new Int32List(4).toList(growable: false));
// Fixed length lists, length 4.
testFixedLengthList(new List(4));
@@ -23,13 +29,6 @@
testFixedLengthList(new MyFixedList(new List(4)));
testFixedLengthList(new MyFixedList(new List(4)).toList(growable: false));
- testFixedLengthList(new Uint8List(4).toList(growable: false));
- testFixedLengthList(new Int8List(4).toList(growable: false));
- testFixedLengthList(new Uint16List(4).toList(growable: false));
- testFixedLengthList(new Int16List(4).toList(growable: false));
- testFixedLengthList(new Uint32List(4).toList(growable: false));
- testFixedLengthList(new Int32List(4).toList(growable: false));
-
// Growable lists. Initial length 0.
testGrowableList(new List());
testGrowableList(new List().toList());
@@ -38,12 +37,13 @@
testGrowableList((const []).toList());
testGrowableList(new MyList([]));
testGrowableList(new MyList([]).toList());
- testGrowableList(new Uint8List(0).toList());
- testGrowableList(new Int8List(0).toList());
- testGrowableList(new Uint16List(0).toList());
- testGrowableList(new Int16List(0).toList());
- testGrowableList(new Uint32List(0).toList());
- testGrowableList(new Int32List(0).toList());
+
+ testTypedGrowableList(new Uint8List(0).toList());
+ testTypedGrowableList(new Int8List(0).toList());
+ testTypedGrowableList(new Uint16List(0).toList());
+ testTypedGrowableList(new Int16List(0).toList());
+ testTypedGrowableList(new Uint32List(0).toList());
+ testTypedGrowableList(new Int32List(0).toList());
}
void testLength(int length, List list) {
@@ -237,6 +237,17 @@
isUnsupported(() => list.replaceRange(0, 1, []));
}
+void testTypedGrowableList(List list) {
+ testLength(0, list);
+ // set length.
+ list.length = 4;
+ testLength(4, list);
+
+ testTypedLengthInvariantOperations(list);
+
+ testGrowableListOperations(list);
+}
+
void testGrowableList(List list) {
testLength(0, list);
// set length.
@@ -245,6 +256,10 @@
testLengthInvariantOperations(list);
+ testGrowableListOperations(list);
+}
+
+void testGrowableListOperations(List list) {
// add, removeLast.
list.clear();
testLength(0, list);
diff --git a/tests/html/element_test.dart b/tests/html/element_test.dart
index aae4dda..3537335 100644
--- a/tests/html/element_test.dart
+++ b/tests/html/element_test.dart
@@ -500,6 +500,50 @@
expect(el.children.getRange(1, 2).length, 1);
});
+ test('retainWhere', () {
+ var el = makeElementWithChildren();
+ expect(el.children.length, 3);
+ el.children.retainWhere((e) => true);
+ expect(el.children.length, 3);
+
+ el = makeElementWithChildren();
+ expect(el.children.length, 3);
+ el.children.retainWhere((e) => false);
+ expect(el.children.length, 0);
+
+ el = makeElementWithChildren();
+ expect(el.children.length, 3);
+ el.children.retainWhere((e) => e.localName == 'input');
+ expect(el.children.length, 1);
+
+ el = makeElementWithChildren();
+ expect(el.children.length, 3);
+ el.children.retainWhere((e) => e.localName == 'br');
+ expect(el.children.length, 1);
+ });
+
+ test('removeWhere', () {
+ var el = makeElementWithChildren();
+ expect(el.children.length, 3);
+ el.children.removeWhere((e) => true);
+ expect(el.children.length, 0);
+
+ el = makeElementWithChildren();
+ expect(el.children.length, 3);
+ el.children.removeWhere((e) => false);
+ expect(el.children.length, 3);
+
+ el = makeElementWithChildren();
+ expect(el.children.length, 3);
+ el.children.removeWhere((e) => e.localName == 'input');
+ expect(el.children.length, 2);
+
+ el = makeElementWithChildren();
+ expect(el.children.length, 3);
+ el.children.removeWhere((e) => e.localName == 'br');
+ expect(el.children.length, 2);
+ });
+
testUnsupported('sort', () {
var l = makeElementWithChildren().children;
l.sort();
diff --git a/tests/html/html.status b/tests/html/html.status
index 40625a0..5e34364 100644
--- a/tests/html/html.status
+++ b/tests/html/html.status
@@ -41,7 +41,7 @@
[ $runtime == chrome ]
touchevent_test/supported: Fail
-[ $runtime == chrome || $runtime == chromeOnAndroid || $runtime == drt ]
+[ $runtime == chrome || $runtime == chromeOnAndroid || $runtime == drt || $runtime == safari ]
audiocontext_test: Skip # Issue 9322
[$runtime == drt || $runtime == dartium || $runtime == chrome || $runtime == chromeOnAndroid]
diff --git a/tests/html/shadow_dom_test.dart b/tests/html/shadow_dom_test.dart
index 78b62b5..d9ec86a 100644
--- a/tests/html/shadow_dom_test.dart
+++ b/tests/html/shadow_dom_test.dart
@@ -66,5 +66,30 @@
expect(shadowRoot.queryAll('.foo'), equals([paragraph1]));
}, expectation);
});
+
+ if (ShadowRoot.supported) {
+ test('Shadowroot contents are distributed', () {
+
+ var div = new DivElement();
+
+ var box1 = new DivElement()
+ ..classes.add('foo');
+ div.append(box1);
+
+ var box2 = new DivElement();
+ div.append(box2);
+
+ var sRoot = div.createShadowRoot();
+ var content1 = new ContentElement()
+ ..select = ".foo";
+ sRoot.append(content1);
+
+ var content2 = new ContentElement();
+ sRoot.append(content2);
+
+ expect(content1.getDistributedNodes(), [box1]);
+ expect(content2.getDistributedNodes(), [box2]);
+ });
+ }
});
}
diff --git a/tests/isolate/isolate.status b/tests/isolate/isolate.status
index 1937b48..b5f430c 100644
--- a/tests/isolate/isolate.status
+++ b/tests/isolate/isolate.status
@@ -129,6 +129,9 @@
[ $compiler == dart2js && ( $runtime == ff || $runtime == safari ) ]
isolate_stress_test: Pass, Timeout # http://dartbug.com/10697
+[ $arch == arm ]
+*: Skip
+
[ $arch == simarm ]
*: Skip
diff --git a/tests/language/bound_closure_equality_test.dart b/tests/language/bound_closure_equality_test.dart
new file mode 100644
index 0000000..fc645ce
--- /dev/null
+++ b/tests/language/bound_closure_equality_test.dart
@@ -0,0 +1,76 @@
+// 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";
+
+class A {
+ const A();
+ foo() => 42;
+}
+
+class B {
+ foo() => 42;
+}
+
+main() {
+ // Use an array to defeat type inferencing.
+ var array = [new A(), new A(), new B(), new B()];
+ var set = new Set.from(array.map((a) => a.foo));
+ Expect.equals(array.length, set.length);
+ set.addAll(array.map((a) => a.foo));
+ Expect.equals(array.length, set.length);
+
+ for (int i = 0; i < array.length; i += 2) {
+ Expect.isTrue(set.contains(array[i].foo));
+ Expect.equals(array[i], array[i]);
+ Expect.equals(array[i].foo, array[i].foo);
+ Expect.equals(array[i].foo.hashCode, array[i].foo.hashCode);
+ for (int j = 0; j < array.length; j++) {
+ if (i == j) continue;
+ Expect.notEquals(array[i].foo, array[j].foo);
+ }
+ }
+
+ // Try with dart2js intercepted types.
+ array = ['foo', 'bar', [], [], const []];
+ set = new Set.from(array.map((a) => a.indexOf));
+ Expect.equals(array.length, set.length);
+ set.addAll(array.map((a) => a.indexOf));
+ Expect.equals(array.length, set.length);
+
+ for (int i = 0; i < array.length; i += 2) {
+ Expect.isTrue(set.contains(array[i].indexOf));
+ Expect.equals(array[i], array[i]);
+ Expect.equals(array[i].indexOf, array[i].indexOf);
+ Expect.equals(array[i].indexOf.hashCode, array[i].indexOf.hashCode);
+ for (int j = 0; j < array.length; j++) {
+ if (i == j) continue;
+ Expect.notEquals(array[i].indexOf, array[j].indexOf);
+ }
+ }
+
+ array = [const A(), const A()];
+ set = new Set.from(array.map((a) => a.foo));
+ Expect.equals(1, set.length);
+ set.addAll(array.map((a) => a.foo));
+ Expect.equals(1, set.length);
+
+ Expect.isTrue(set.contains(array[0].foo));
+ Expect.equals(array[0].foo, array[0].foo);
+ Expect.equals(array[0].foo.hashCode, array[0].foo.hashCode);
+ Expect.equals(array[0].foo, array[1].foo);
+ Expect.equals(array[0].foo.hashCode, array[1].foo.hashCode);
+
+ array = [const [], const []];
+ set = new Set.from(array.map((a) => a.indexOf));
+ Expect.equals(1, set.length);
+ set.addAll(array.map((a) => a.indexOf));
+ Expect.equals(1, set.length);
+
+ Expect.isTrue(set.contains(array[0].indexOf));
+ Expect.equals(array[0].indexOf, array[0].indexOf);
+ Expect.equals(array[0].indexOf.hashCode, array[0].indexOf.hashCode);
+ Expect.equals(array[0].indexOf, array[1].indexOf);
+ Expect.equals(array[0].indexOf.hashCode, array[1].indexOf.hashCode);
+}
diff --git a/tests/language/bound_closure_primitives_test.dart b/tests/language/bound_closure_primitives_test.dart
new file mode 100644
index 0000000..83ffe79
--- /dev/null
+++ b/tests/language/bound_closure_primitives_test.dart
@@ -0,0 +1,27 @@
+// 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 dart2js does not try to use the same
+// BoundClosureClass between an intercepted method and a
+// non-intercepted method.
+
+import "package:expect/expect.dart";
+
+class A {
+ // Make dart2js try to share a bound closure for [foo] with a bound
+ // closure for [List.add], by having same number of arguments.
+ foo(a) => a;
+}
+
+main() {
+ var array = [[], new A()];
+ var method = array[0].add;
+ method(42);
+
+ method = array[1].foo;
+ Expect.equals(42, method(42));
+
+ Expect.equals(1, array[0].length);
+ Expect.isTrue(array[0].contains(42));
+}
diff --git a/tests/language/language.status b/tests/language/language.status
index bd59fc9..1b35b74 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -38,6 +38,7 @@
method_override2_test/00: Fail # Issue 7076.
method_override2_test/02: Fail # Issue 7076.
method_override2_test/03: Fail # Issue 7076.
+bound_closure_equality_test: Fail # Issue 10849
# These bugs refer currently ongoing language discussions.
constructor5_test: Fail # (Discussion ongoing)
@@ -77,11 +78,12 @@
mixin_mixin_test: Fail
mixin_issue10216_2_test: Fail
+mixin_illegal_object_test/01: Crash # Issue 10952
+mixin_illegal_object_test/02: Crash # Issue 10952
type_variable_field_initializer_closure_test: Crash # issue 8847
super_getter_setter_test: Fail # Issue 8917
-super_operator_index7_test: Fail # Issue 8918
execute_finally10_test: Fail # Issue 430
execute_finally11_test: Fail # Issue 430
@@ -330,16 +332,8 @@
built_in_identifier_prefix_test: Fail # Inherited from dart2js.
constructor_redirect2_test/03: Fail
constructor_initializer_test: Fail # VM issue
-factory2_test: Fail
factory3_test: Fail
-factory5_test/none: Fail
-factory5_test/00: Fail
type_checks_in_factory_method_test: Fail
-default_factory2_test/01: Fail # type arguments on redirecting factory not implemented
-default_factory3_test: Fail # type arguments on redirecting factory not implemented
-non_parameterized_factory_test: Fail # type arguments on redirecting factory not implemented
-non_parameterized_factory2_test: Fail # type arguments on redirecting factory not implemented
-type_variable_scope_test: Fail # type arguments on redirecting factory not implemented
many_overridden_no_such_method_test: Fail, Pass, OK # Fails in minified mode, test depends on method names.
overridden_no_such_method_test: Fail, Pass, OK # Fails in minified mode, test depends on method names.
@@ -515,11 +509,12 @@
type_variable_field_initializer_closure_test: Crash # VM bug: issue 8847
super_getter_setter_test: Fail # VM bug: issue 8917
-super_operator_index7_test: Fail # VM bug: issue 8918
execute_finally10_test: Fail # VM bug: issue 430
execute_finally11_test: Fail # VM bug: issue 430
+bound_closure_equality_test: Fail # Issue 10849
+
[ $compiler == dart2dart && $minified ]
# TODO(tball): Assign proper bug numbers.
@@ -557,18 +552,10 @@
callable_test/none: fail
cast_test/04: fail
cast_test/05: fail
-class_cycle_negative_test: fail
-class_cycle_test/00: fail
-class_cycle_test/01: fail
class_cycle_test/03: fail
closure_call_wrong_argument_count_negative_test: fail
compile_time_constant10_test/none: fail
compile_time_constant8_test: fail
-compile_time_constant_arguments_test/01: fail
-compile_time_constant_arguments_test/02: fail
-compile_time_constant_arguments_test/03: fail
-compile_time_constant_arguments_test/05: fail
-compile_time_constant_arguments_test/06: fail
compile_time_constant_b_test: fail
compile_time_constant_c_test/01: fail
compile_time_constant_c_test/02: fail
@@ -606,7 +593,6 @@
factory5_test/00: fail
factory_implementation_test/none: fail
factory_redirection2_test/01: fail
-factory_redirection_test/07: fail
fauxverride_test/03: fail
fauxverride_test/05: fail
field_method4_negative_test: fail
@@ -633,13 +619,11 @@
implicit_this_test/04: fail
implicit_this_test/none: fail
import_combinators_negative_test: fail
-infinite_switch_label_test: fail
inst_field_initializer1_negative_test: fail
instance_call_wrong_argument_count_negative_test: fail
instance_method2_negative_test: fail
instance_method_negative_test: fail
instantiate_type_variable_negative_test: fail
-interface_cycle_negative_test: fail
interface_inherit_field_test: fail
interface_static_non_final_fields_negative_test: fail
interface_test/00: fail
@@ -673,7 +657,6 @@
new_expression_type_args_test/00: fail
new_expression_type_args_test/01: fail
new_expression_type_args_test/02: fail
-nested_switch_label_test: fail
no_such_method_negative_test: fail
non_const_super_negative_test: fail
number_identifier_negative_test: fail
@@ -717,7 +700,6 @@
static_field_test/03: fail
static_final_field2_negative_test: fail
static_final_field_negative_test: fail
-switch_label2_test: fail
syntax_test/28: fail
syntax_test/29: fail
syntax_test/30: fail
@@ -817,9 +799,25 @@
type_variable_scope_test/05: fail
-[ $arch == simarm ]
+[ $arch == arm ]
*: Skip
+[ $arch == simarm ]
+arithmetic_test: Crash
+bit_operations_test: Crash
+char_escape_test: Pass, Crash
+deopt_smi_op_test: Fail
+div_with_power_of_two_test: Fail
+double_modulo_test: Crash
+gc_test: Crash
+invocation_mirror_test: Fail
+large_implicit_getter_test: Crash
+load_to_load_forwarding_test: Fail
+math_vm_test: Crash
+named_parameters_with_conversions_test: Pass, Crash
+stack_overflow_stacktrace_test: Crash
+stack_overflow_test: Crash
+
[ $arch == mips ]
*: Skip
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 0b6a3c9..cab3e41 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -42,9 +42,7 @@
function_type_alias6_test: Crash # dartbug.com/9792
prefix16_test: Fail # dartbug.com/7354
-default_factory2_test/01: Pass # For the wrong reasons.
-type_variable_scope_test/none: Fail
-redirecting_factory_infinite_steps_test/01: Fail
+default_factory2_test/01: Fail
type_variable_bounds_test/01: Fail
type_variable_bounds_test/02: Fail
type_variable_bounds_test/04: Fail
@@ -62,17 +60,11 @@
local_function2_test: Fail # Issue 5022
[ $compiler == dart2js && $unchecked ]
-default_factory2_test/01: Fail # type arguments on redirecting factory not implemented
-type_variable_scope_test: Fail # type arguments on redirecting factory not implemented
+factory_redirection_test/14: Fail # redirecting to redirecting factory
+type_checks_in_factory_method_test: Fail # Expect.equals(expected: <true>, actual: <false>) fails. -- checked mode test.
+
assertion_test: Fail
type_variable_bounds_test/07: Fail # Wrongly reports compile-time error.
-factory_redirection_test/08: Fail
-factory_redirection_test/09: Fail
-factory_redirection_test/10: Fail
-factory_redirection_test/11: Fail
-factory_redirection_test/12: Fail
-factory_redirection_test/13: Fail
-factory_redirection_test/14: Fail
double_to_string_as_exponential2_test: Fail # toStringAsExponential doesn't check if argument is an integer.
double_to_string_as_fixed2_test: Fail # toStringAsFixed doesn't check if argument is an integer.
@@ -108,7 +100,6 @@
mint_arithmetic_test: Fail # Issue 1533 (big integer arithmetic).
left_shift_test: Fail # Issue 1533
factory_redirection_test/01: Fail
-factory_redirection_test/05: Fail
factory_redirection_test/07: Fail
final_variable_assignment_test/01: Fail
final_variable_assignment_test/02: Fail
@@ -141,17 +132,12 @@
positional_parameters_type_test: Fail
# Compilation errors.
-default_factory3_test: Fail # type arguments on redirecting factory not implemented
-non_parameterized_factory_test: Fail # type arguments on redirecting factory not implemented
-non_parameterized_factory2_test: Fail # type arguments on redirecting factory not implemented
const_var_test: Fail # Map literals take 2 type arguments.
map_literal3_test: Fail # Map literals take 2 type arguments.
ct_const_test: Fail # We don't take the generic type into account yet.
dynamic_test: Fail # cannot resolve type F1
constructor_redirect2_test/03: Fail # redirecting ctor with initializing formal
-factory2_test: Fail # internal error: visitIs for type variables not implemented
factory3_test: Fail # internal error: visitIs for type variables not implemented
-factory5_test: Fail # internal error: visitIs for type variables not implemented
function_type_alias2_test: Fail # cannot resolve type f1
function_type_alias3_test: Fail # cannot resolve type F
function_type_alias4_test: Fail # cannot resolve type F
@@ -221,7 +207,6 @@
list_literal4_test: Fail # Illegal argument(s): 0 -- checked mode test.
map_literal4_test: Fail # Attempt to modify an immutable object -- checked mode test.
named_parameters_type_test: Fail # Expect.equals(expected: <111>, actual: <0>) fails. -- checked mode test.
-type_checks_in_factory_method_test: Fail # Expect.equals(expected: <true>, actual: <false>) fails. -- checked mode test.
type_dartc_test: Fail # Expect.equals(expected: <1>, actual: <0>) -- checked mode test.
class_cycle_negative_test: Fail, OK # Bad test: assumes eager loading.
@@ -321,7 +306,6 @@
factory3_test: Fail
stack_overflow_test: Fail
stack_overflow_stacktrace_test: Fail
-type_checks_in_factory_method_test: Fail
[ $compiler == dart2js && $runtime == safari ]
diff --git a/tests/language/local_function_non_equal_test.dart b/tests/language/local_function_non_equal_test.dart
new file mode 100644
index 0000000..a64b2cc
--- /dev/null
+++ b/tests/language/local_function_non_equal_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.
+
+import "package:expect/expect.dart";
+
+foo() => () => 42;
+bar() {
+ var c = () => 54;
+ return c;
+}
+baz() {
+ c() => 68;
+ return c;
+}
+
+main() {
+ var first = foo();
+ var second = foo();
+ Expect.isFalse(identical(first, second));
+ Expect.notEquals(first, second);
+
+ first = bar();
+ second = bar();
+ Expect.isFalse(identical(first, second));
+ Expect.notEquals(first, second);
+
+ first = baz();
+ second = baz();
+ Expect.isFalse(identical(first, second));
+ Expect.notEquals(first, second);
+}
diff --git a/tests/language/mixin_illegal_object_test.dart b/tests/language/mixin_illegal_object_test.dart
new file mode 100644
index 0000000..ef11ef1
--- /dev/null
+++ b/tests/language/mixin_illegal_object_test.dart
@@ -0,0 +1,14 @@
+// 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 C0 extends Object
+with Object /// 01: compile-time error
+{ }
+
+typedef C1 = Object with Object; /// 02: compile-time error
+
+main() {
+ new C0();
+ new C1(); /// 02: continued
+}
diff --git a/tests/language/null_is2_test.dart b/tests/language/null_is2_test.dart
new file mode 100644
index 0000000..1edf139
--- /dev/null
+++ b/tests/language/null_is2_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.
+
+import "package:expect/expect.dart";
+
+class Test<T> {
+ foo(a) => a is T;
+}
+
+main() {
+ Expect.isTrue(new Test<Object>().foo(null));
+ Expect.isTrue(new Test<dynamic>().foo(null));
+ Expect.isFalse(new Test<int>().foo(null));
+ Expect.isFalse(null is List<Object>);
+}
diff --git a/tests/language/regress_10996_lib.dart b/tests/language/regress_10996_lib.dart
new file mode 100644
index 0000000..77071a2
--- /dev/null
+++ b/tests/language/regress_10996_lib.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library regress_10996_lib;
+
+var a = 3;
+var b = 4;
+var c = 5;
+var d = 6;
diff --git a/tests/language/regress_10996_test.dart b/tests/language/regress_10996_test.dart
new file mode 100644
index 0000000..4aefa94
--- /dev/null
+++ b/tests/language/regress_10996_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 "package:expect/expect.dart";
+import "regress_10996_lib.dart" as lib;
+
+foo(a, [b]) {
+ return a + b + lib.a + lib.b;
+}
+
+bar(c, {d}) {
+ return c + d + lib.c + lib.d;
+}
+
+main() {
+ Expect.equals(1 + 2 + 3 + 4, foo(1, 2));
+ Expect.equals(7 + 8 + 3 + 4, foo(7, 8));
+ Expect.equals(3 + 4 + 5 + 6, bar(3, d: 4));
+ Expect.equals(7 + 8 + 5 + 6, bar(7, d: 8));
+}
diff --git a/tests/language/static_closure_identical_test.dart b/tests/language/static_closure_identical_test.dart
new file mode 100644
index 0000000..aa176a4
--- /dev/null
+++ b/tests/language/static_closure_identical_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.
+
+import "package:expect/expect.dart";
+
+var foo = main;
+
+main() {
+ Expect.equals(main, main);
+ Expect.identical(main, main);
+ Expect.equals(main.hashCode, main.hashCode);
+
+ Expect.equals(main, foo);
+ Expect.identical(main, foo);
+ Expect.equals(main.hashCode, foo.hashCode);
+}
diff --git a/tests/lib/async/slow_consumer2_test.dart b/tests/lib/async/slow_consumer2_test.dart
index 2108870..0c56f4a 100644
--- a/tests/lib/async/slow_consumer2_test.dart
+++ b/tests/lib/async/slow_consumer2_test.dart
@@ -71,6 +71,7 @@
DataProvider(int this.bytesPerSecond, int this.targetCount, this.chunkSize) {
controller = new StreamController(
+ sync: true,
onPause: onPauseStateChange,
onResume: onPauseStateChange);
Timer.run(send);
diff --git a/tests/lib/async/slow_consumer_test.dart b/tests/lib/async/slow_consumer_test.dart
index a20ad6d..f4f6ef5 100644
--- a/tests/lib/async/slow_consumer_test.dart
+++ b/tests/lib/async/slow_consumer_test.dart
@@ -69,6 +69,7 @@
DataProvider(int this.bytesPerSecond, int this.targetCount, this.chunkSize) {
controller = new StreamController(
+ sync: true,
onPause: onPauseStateChange,
onResume: onPauseStateChange);
Timer.run(send);
diff --git a/tests/lib/async/stream_controller_async_test.dart b/tests/lib/async/stream_controller_async_test.dart
index 65e658f..7c13405 100644
--- a/tests/lib/async/stream_controller_async_test.dart
+++ b/tests/lib/async/stream_controller_async_test.dart
@@ -10,6 +10,7 @@
import 'dart:isolate';
import '../../../pkg/unittest/lib/unittest.dart';
import 'event_helper.dart';
+import 'stream_state_helper.dart';
testController() {
// Test fold
@@ -266,111 +267,91 @@
testPause() {
test("pause event-unpause", () {
- StreamController c = new StreamController();
- Events actualEvents = new Events.capture(c.stream);
- Events expectedEvents = new Events();
- expectedEvents.add(42);
- c.add(42);
- Expect.listEquals(expectedEvents.events, actualEvents.events);
+ StreamProtocolTest test = new StreamProtocolTest();
Completer completer = new Completer();
- actualEvents.pause(completer.future);
- c..add(43)..add(44)..close();
- Expect.listEquals(expectedEvents.events, actualEvents.events);
- completer.complete();
- expectedEvents..add(43)..add(44)..close();
- actualEvents.onDone(expectAsync0(() {
- Expect.listEquals(expectedEvents.events, actualEvents.events);
- }));
+ test..expectListen()
+ ..expectData(42, () { test.pause(completer.future); })
+ ..expectPause(() {
+ completer.complete(null);
+ })
+ ..expectData(43)
+ ..expectData(44)
+ ..expectDone()
+ ..expectCancel();
+ test.listen();
+ test.add(42);
+ test.add(43);
+ test.add(44);
+ test.close();
});
test("pause twice event-unpause", () {
- StreamController c = new StreamController();
- Events actualEvents = new Events.capture(c.stream);
- Events expectedEvents = new Events();
- expectedEvents.add(42);
- c.add(42);
- Expect.listEquals(expectedEvents.events, actualEvents.events);
+ StreamProtocolTest test = new StreamProtocolTest();
Completer completer = new Completer();
Completer completer2 = new Completer();
- actualEvents.pause(completer.future);
- actualEvents.pause(completer2.future);
- c..add(43)..add(44)..close();
- Expect.listEquals(expectedEvents.events, actualEvents.events);
- completer.complete();
- Expect.listEquals(expectedEvents.events, actualEvents.events);
- completer2.complete();
- expectedEvents..add(43)..add(44)..close();
- actualEvents.onDone(expectAsync0((){
- Expect.listEquals(expectedEvents.events, actualEvents.events);
- }));
+ test..expectListen()
+ ..expectData(42, () {
+ test.pause(completer.future);
+ test.pause(completer2.future);
+ })
+ ..expectPause(() {
+ completer.future.then(completer2.complete);
+ completer.complete(null);
+ })
+ ..expectData(43)
+ ..expectData(44)
+ ..expectDone()
+ ..expectCancel();
+ test..listen()
+ ..add(42)
+ ..add(43)
+ ..add(44)
+ ..close();
});
test("pause twice direct-unpause", () {
- StreamController c = new StreamController();
- Events actualEvents = new Events.capture(c.stream);
- Events expectedEvents = new Events();
- expectedEvents.add(42);
- c.add(42);
- Expect.listEquals(expectedEvents.events, actualEvents.events);
- actualEvents.pause();
- actualEvents.pause();
- c.add(43);
- c.add(44);
- c.close();
- Expect.listEquals(expectedEvents.events, actualEvents.events);
- actualEvents.resume();
- Expect.listEquals(expectedEvents.events, actualEvents.events);
- expectedEvents..add(43)..add(44)..close();
- actualEvents.onDone(expectAsync0(() {
- Expect.listEquals(expectedEvents.events, actualEvents.events);
- }));
- actualEvents.resume();
+ StreamProtocolTest test = new StreamProtocolTest();
+ test..expectListen()
+ ..expectData(42, () {
+ test.pause();
+ test.pause();
+ })
+ ..expectPause(() {
+ test.resume();
+ test.resume();
+ })
+ ..expectData(43)
+ ..expectData(44)
+ ..expectDone()
+ ..expectCancel();
+ test..listen()
+ ..add(42)
+ ..add(43)
+ ..add(44)
+ ..close();
});
test("pause twice direct-event-unpause", () {
- StreamController c = new StreamController();
- Events actualEvents = new Events.capture(c.stream);
- Events expectedEvents = new Events();
- expectedEvents.add(42);
- c.add(42);
- Expect.listEquals(expectedEvents.events, actualEvents.events);
+ StreamProtocolTest test = new StreamProtocolTest();
Completer completer = new Completer();
- actualEvents.pause(completer.future);
- actualEvents.pause();
- c.add(43);
- c.add(44);
- c.close();
- Expect.listEquals(expectedEvents.events, actualEvents.events);
- actualEvents.resume();
- Expect.listEquals(expectedEvents.events, actualEvents.events);
- expectedEvents..add(43)..add(44)..close();
- actualEvents.onDone(expectAsync0(() {
- Expect.listEquals(expectedEvents.events, actualEvents.events);
- }));
- completer.complete();
- });
-
- test("pause twice direct-unpause", () {
- StreamController c = new StreamController();
- Events actualEvents = new Events.capture(c.stream);
- Events expectedEvents = new Events();
- expectedEvents.add(42);
- c.add(42);
- Expect.listEquals(expectedEvents.events, actualEvents.events);
- Completer completer = new Completer();
- actualEvents.pause(completer.future);
- actualEvents.pause();
- c.add(43);
- c.add(44);
- c.close();
- Expect.listEquals(expectedEvents.events, actualEvents.events);
- completer.complete();
- Expect.listEquals(expectedEvents.events, actualEvents.events);
- expectedEvents..add(43)..add(44)..close();
- actualEvents.onDone(expectAsync0(() {
- Expect.listEquals(expectedEvents.events, actualEvents.events);
- }));
- actualEvents.resume();
+ test..expectListen()
+ ..expectData(42, () {
+ test.pause();
+ test.pause(completer.future);
+ test.add(43);
+ test.add(44);
+ test.close();
+ })
+ ..expectPause(() {
+ completer.future.then((v) => test.resume());
+ completer.complete(null);
+ })
+ ..expectData(43)
+ ..expectData(44)
+ ..expectDone()
+ ..expectCancel();
+ test..listen()
+ ..add(42);
});
}
@@ -431,75 +412,89 @@
void testBroadcastController() {
test("broadcast-controller-basic", () {
- StreamController<int> c = new StreamController.broadcast(
- onListen: expectAsync0(() {}),
- onCancel: expectAsync0(() {})
- );
- Stream<int> s = c.stream;
- s.listen(expectAsync1((x) { expect(x, equals(42)); }));
- c.add(42);
- c.close();
+ StreamProtocolTest test = new StreamProtocolTest.broadcast();
+ test..expectListen()
+ ..expectData(42)
+ ..expectDone()
+ ..expectCancel(test.terminate);
+ test..listen()
+ ..add(42)
+ ..close();
});
test("broadcast-controller-listen-twice", () {
- StreamController<int> c = new StreamController.broadcast(
- onListen: expectAsync0(() {}),
- onCancel: expectAsync0(() {})
- );
- c.stream.listen(expectAsync1((x) { expect(x, equals(42)); }, count: 2));
- c.add(42);
- c.stream.listen(expectAsync1((x) { expect(x, equals(42)); }));
- c.add(42);
- c.close();
+ StreamProtocolTest test = new StreamProtocolTest.broadcast();
+ test..expectListen()
+ ..expectData(42, () {
+ test.listen();
+ test.add(37);
+ test.close();
+ })
+ // Order is not guaranteed between subscriptions if not sync.
+ ..expectData(37)
+ ..expectData(37)
+ ..expectDone()
+ ..expectDone()
+ ..expectCancel(test.terminate);
+ test.listen();
+ test.add(42);
});
test("broadcast-controller-listen-twice-non-overlap", () {
- StreamController<int> c = new StreamController.broadcast(
- onListen: expectAsync0(() {}, count: 2),
- onCancel: expectAsync0(() {}, count: 2)
- );
- var sub = c.stream.listen(expectAsync1((x) { expect(x, equals(42)); }));
- c.add(42);
- sub.cancel();
- c.stream.listen(expectAsync1((x) { expect(x, equals(42)); }));
- c.add(42);
- c.close();
+ StreamProtocolTest test = new StreamProtocolTest.broadcast();
+ test
+ ..expectListen(() {
+ test.add(42);
+ })
+ ..expectData(42, () {
+ test.cancel();
+ })
+ ..expectCancel(() {
+ test.listen();
+ })..expectListen(() {
+ test.add(37);
+ })
+ ..expectData(37, () {
+ test.close();
+ })
+ ..expectDone()
+ ..expectCancel(test.terminate);
+ test.listen();
});
test("broadcast-controller-individual-pause", () {
- StreamController<int> c = new StreamController.broadcast(
- onListen: expectAsync0(() {}),
- onCancel: expectAsync0(() {})
- );
- var sub1 = c.stream.listen(expectAsync1((x) { expect(x, equals(42)); }));
- var sub2 = c.stream.listen(expectAsync1((x) { expect(x, equals(42)); },
- count: 3));
- c.add(42);
- sub1.pause();
- c.add(42);
- sub1.cancel();
- var sub3 = c.stream.listen(expectAsync1((x) { expect(x, equals(42)); }));
- c.add(42);
- c.close();
+ StreamProtocolTest test = new StreamProtocolTest.broadcast();
+ test.trace = true;
+ var sub1;
+ test..expectListen()
+ ..expectData(42)
+ ..expectData(42, () { sub1.pause(); })
+ ..expectData(43, () {
+ sub1.cancel();
+ test.listen();
+ test.add(44);
+ test.expectData(44);
+ test.expectData(44, test.terminate);
+ });
+ sub1 = test.listen();
+ test.listen();
+ test.add(42);
+ test.add(43);
});
test("broadcast-controller-add-in-callback", () {
- StreamController<int> c;
- c = new StreamController(
- onListen: expectAsync0(() {}),
- onCancel: expectAsync0(() {
- c.add(42);
- })
- );
- var sub;
- sub = c.stream.asBroadcastStream().listen(expectAsync1((v) {
- Expect.equals(37, v);
- c.add(21);
+ StreamProtocolTest test = new StreamProtocolTest.broadcast();
+ test.expectListen();
+ var sub = test.listen();
+ test.add(42);
+ sub.expectData(42, () {
+ test.add(87);
sub.cancel();
- }));
- c.add(37); // Triggers listener, which adds 21 and removes itself.
- // Removing listener triggers onCancel which adds another 42.
- // Both 21 and 42 are lost because there are no listeners.
+ });
+ test.expectCancel(() {
+ test.add(37);
+ test.terminate();
+ });
});
}
diff --git a/tests/lib/async/stream_controller_test.dart b/tests/lib/async/stream_controller_test.dart
index 9990f44..b4aa6aa 100644
--- a/tests/lib/async/stream_controller_test.dart
+++ b/tests/lib/async/stream_controller_test.dart
@@ -11,7 +11,7 @@
testMultiController() {
// Test normal flow.
- var c = new StreamController();
+ var c = new StreamController(sync: true);
Events expectedEvents = new Events()
..add(42)
..add("dibs")
@@ -23,7 +23,7 @@
Expect.listEquals(expectedEvents.events, actualEvents.events);
// Test automatic unsubscription on error.
- c = new StreamController();
+ c = new StreamController(sync: true);
expectedEvents = new Events()..add(42)..error("error");
actualEvents = new Events.capture(c.stream.asBroadcastStream(),
cancelOnError: true);
@@ -33,7 +33,7 @@
Expect.listEquals(expectedEvents.events, actualEvents.events);
// Test manual unsubscription.
- c = new StreamController();
+ c = new StreamController(sync: true);
expectedEvents = new Events()..add(42)..error("error")..add(37);
actualEvents = new Events.capture(c.stream.asBroadcastStream(),
cancelOnError: false);
@@ -43,7 +43,7 @@
Expect.listEquals(expectedEvents.events, actualEvents.events);
// Test filter.
- c = new StreamController();
+ c = new StreamController(sync: true);
expectedEvents = new Events()
..add("a string")..add("another string")..close();
sentEvents = new Events()
@@ -55,7 +55,7 @@
Expect.listEquals(expectedEvents.events, actualEvents.events);
// Test map.
- c = new StreamController();
+ c = new StreamController(sync: true);
expectedEvents = new Events()..add("abab")..error("error")..close();
sentEvents = new Events()..add("ab")..error("error")..close();
actualEvents = new Events.capture(c.stream
@@ -65,7 +65,7 @@
Expect.listEquals(expectedEvents.events, actualEvents.events);
// Test handleError.
- c = new StreamController();
+ c = new StreamController(sync: true);
expectedEvents = new Events()..add("ab")..error("[foo]");
sentEvents = new Events()..add("ab")..error("foo")..add("ab")..close();
actualEvents = new Events.capture(c.stream
@@ -82,7 +82,7 @@
// reduce is tested asynchronously and therefore not in this file.
// Test expand
- c = new StreamController();
+ c = new StreamController(sync: true);
sentEvents = new Events()..add(3)..add(2)..add(4)..close();
expectedEvents = new Events()..add(1)..add(2)..add(3)
..add(1)..add(2)
@@ -97,7 +97,7 @@
Expect.listEquals(expectedEvents.events, actualEvents.events);
// Test transform.
- c = new StreamController();
+ c = new StreamController(sync: true);
sentEvents = new Events()..add("a")..error(42)..add("b")..close();
expectedEvents =
new Events()..error("a")..add(42)..error("b")..add("foo")..close();
@@ -116,7 +116,7 @@
Expect.listEquals(expectedEvents.events, actualEvents.events);
// Test multiple filters.
- c = new StreamController();
+ c = new StreamController(sync: true);
sentEvents = new Events()..add(42)
..add("snugglefluffy")
..add(7)
@@ -136,7 +136,7 @@
Expect.listEquals(expectedEvents.events, actualEvents.events);
// Test subscription changes while firing.
- c = new StreamController();
+ c = new StreamController(sync: true);
var sink = c.sink;
var stream = c.stream.asBroadcastStream();
var counter = 0;
@@ -163,7 +163,7 @@
testSingleController() {
// Test normal flow.
- var c = new StreamController();
+ var c = new StreamController(sync: true);
Events expectedEvents = new Events()
..add(42)
..add("dibs")
@@ -175,7 +175,7 @@
Expect.listEquals(expectedEvents.events, actualEvents.events);
// Test automatic unsubscription on error.
- c = new StreamController();
+ c = new StreamController(sync: true);
expectedEvents = new Events()..add(42)..error("error");
actualEvents = new Events.capture(c.stream, cancelOnError: true);
Events sentEvents =
@@ -184,7 +184,7 @@
Expect.listEquals(expectedEvents.events, actualEvents.events);
// Test manual unsubscription.
- c = new StreamController();
+ c = new StreamController(sync: true);
expectedEvents = new Events()..add(42)..error("error")..add(37);
actualEvents = new Events.capture(c.stream, cancelOnError: false);
expectedEvents.replay(c);
@@ -193,7 +193,7 @@
Expect.listEquals(expectedEvents.events, actualEvents.events);
// Test filter.
- c = new StreamController();
+ c = new StreamController(sync: true);
expectedEvents = new Events()
..add("a string")..add("another string")..close();
sentEvents = new Events()
@@ -203,7 +203,7 @@
Expect.listEquals(expectedEvents.events, actualEvents.events);
// Test map.
- c = new StreamController();
+ c = new StreamController(sync: true);
expectedEvents = new Events()..add("abab")..error("error")..close();
sentEvents = new Events()..add("ab")..error("error")..close();
actualEvents = new Events.capture(c.stream.map((v) => "$v$v"));
@@ -211,7 +211,7 @@
Expect.listEquals(expectedEvents.events, actualEvents.events);
// Test handleError.
- c = new StreamController();
+ c = new StreamController(sync: true);
expectedEvents = new Events()..add("ab")..error("[foo]");
sentEvents = new Events()..add("ab")..error("foo")..add("ab")..close();
actualEvents = new Events.capture(c.stream.handleError((error) {
@@ -226,7 +226,7 @@
// reduce is tested asynchronously and therefore not in this file.
// Test expand
- c = new StreamController();
+ c = new StreamController(sync: true);
sentEvents = new Events()..add(3)..add(2)..add(4)..close();
expectedEvents = new Events()..add(1)..add(2)..add(3)
..add(1)..add(2)
@@ -242,7 +242,7 @@
// test contains.
{
- c = new StreamController();
+ c = new StreamController(sync: true);
// Error after match is not important.
sentEvents = new Events()..add("a")..add("x")..error("FAIL")..close();
Future<bool> contains = c.stream.contains("x");
@@ -253,7 +253,7 @@
}
{
- c = new StreamController();
+ c = new StreamController(sync: true);
// Not matching is ok.
sentEvents = new Events()..add("a")..add("x")..add("b")..close();
Future<bool> contains = c.stream.contains("y");
@@ -264,7 +264,7 @@
}
{
- c = new StreamController();
+ c = new StreamController(sync: true);
// Error before match makes future err.
sentEvents = new Events()..add("a")..error("FAIL")..add("b")..close();
Future<bool> contains = c.stream.contains("b");
@@ -277,7 +277,7 @@
}
// Test transform.
- c = new StreamController();
+ c = new StreamController(sync: true);
sentEvents = new Events()..add("a")..error(42)..add("b")..close();
expectedEvents =
new Events()..error("a")..add(42)..error("b")..add("foo")..close();
@@ -293,7 +293,7 @@
Expect.listEquals(expectedEvents.events, actualEvents.events);
// Test multiple filters.
- c = new StreamController();
+ c = new StreamController(sync: true);
sentEvents = new Events()..add(42)
..add("snugglefluffy")
..add(7)
@@ -313,7 +313,7 @@
Expect.listEquals(expectedEvents.events, actualEvents.events);
// Test that only one subscription is allowed.
- c = new StreamController();
+ c = new StreamController(sync: true);
var sink = c.sink;
var stream = c.stream;
var counter = 0;
@@ -327,67 +327,67 @@
testExtraMethods() {
Events sentEvents = new Events()..add(1)..add(2)..add(3)..close();
- var c = new StreamController();
+ var c = new StreamController(sync: true);
Events expectedEvents = new Events()..add(3)..close();
Events actualEvents = new Events.capture(c.stream.skip(2));
sentEvents.replay(c);
Expect.listEquals(expectedEvents.events, actualEvents.events);
- c = new StreamController();
+ c = new StreamController(sync: true);
expectedEvents = new Events()..close();
actualEvents = new Events.capture(c.stream.skip(3));
sentEvents.replay(c);
Expect.listEquals(expectedEvents.events, actualEvents.events);
- c = new StreamController();
+ c = new StreamController(sync: true);
expectedEvents = new Events()..close();
actualEvents = new Events.capture(c.stream.skip(7));
sentEvents.replay(c);
Expect.listEquals(expectedEvents.events, actualEvents.events);
- c = new StreamController();
+ c = new StreamController(sync: true);
expectedEvents = sentEvents;
actualEvents = new Events.capture(c.stream.skip(0));
sentEvents.replay(c);
Expect.listEquals(expectedEvents.events, actualEvents.events);
- c = new StreamController();
+ c = new StreamController(sync: true);
expectedEvents = new Events()..add(3)..close();
actualEvents = new Events.capture(c.stream.skipWhile((x) => x <= 2));
sentEvents.replay(c);
Expect.listEquals(expectedEvents.events, actualEvents.events);
- c = new StreamController();
+ c = new StreamController(sync: true);
expectedEvents = new Events()..add(2)..add(3)..close();
actualEvents = new Events.capture(c.stream.skipWhile((x) => x <= 1));
sentEvents.replay(c);
Expect.listEquals(expectedEvents.events, actualEvents.events);
- c = new StreamController();
+ c = new StreamController(sync: true);
expectedEvents = new Events()..add(1)..add(2)..add(3)..close();
actualEvents = new Events.capture(c.stream.skipWhile((x) => false));
sentEvents.replay(c);
Expect.listEquals(expectedEvents.events, actualEvents.events);
- c = new StreamController();
+ c = new StreamController(sync: true);
expectedEvents = new Events()..add(1)..add(2)..close();
actualEvents = new Events.capture(c.stream.take(2));
sentEvents.replay(c);
Expect.listEquals(expectedEvents.events, actualEvents.events);
- c = new StreamController();
+ c = new StreamController(sync: true);
expectedEvents = new Events()..add(1)..add(2)..close();
actualEvents = new Events.capture(c.stream.takeWhile((x) => x <= 2));
sentEvents.replay(c);
Expect.listEquals(expectedEvents.events, actualEvents.events);
- c = new StreamController();
+ c = new StreamController(sync: true);
sentEvents = new Events()
..add(1)..add(1)..add(2)..add(1)..add(2)..add(2)..add(2)..close();
expectedEvents = new Events()
@@ -397,7 +397,7 @@
Expect.listEquals(expectedEvents.events, actualEvents.events);
- c = new StreamController();
+ c = new StreamController(sync: true);
sentEvents = new Events()
..add(5)..add(6)..add(4)..add(6)..add(8)..add(3)..add(4)..add(1)..close();
expectedEvents = new Events()
@@ -409,7 +409,7 @@
}
testClosed() {
- StreamController c = new StreamController();
+ StreamController c = new StreamController(sync: true);
Expect.isFalse(c.isClosed);
c.add(42);
Expect.isFalse(c.isClosed);
diff --git a/tests/lib/async/stream_event_transform_test.dart b/tests/lib/async/stream_event_transform_test.dart
index 87f114c..c10b8f5 100644
--- a/tests/lib/async/stream_event_transform_test.dart
+++ b/tests/lib/async/stream_event_transform_test.dart
@@ -46,7 +46,7 @@
main() {
{
- StreamController c = new StreamController();
+ StreamController c = new StreamController(sync: true);
Events expected = new Events()..error("0")..add(1)
..error("1")..add(2)
..add(3)..error("4")
@@ -61,7 +61,7 @@
}
{
- StreamController c = new StreamController();
+ StreamController c = new StreamController(sync: true);
Events expected = new Events()..error("0")..add(1)
..error("1")..add(2)
..add(3)..error("4")
diff --git a/tests/lib/async/stream_single_test.dart b/tests/lib/async/stream_single_test.dart
index fe0b384..4c3c486 100644
--- a/tests/lib/async/stream_single_test.dart
+++ b/tests/lib/async/stream_single_test.dart
@@ -13,21 +13,21 @@
main() {
test("single", () {
- StreamController c = new StreamController();
+ StreamController c = new StreamController(sync: true);
Future f = c.stream.single;
f.then(expectAsync1((v) { Expect.equals(42, v);}));
new Events.fromIterable([42]).replay(c);
});
test("single empty", () {
- StreamController c = new StreamController();
+ StreamController c = new StreamController(sync: true);
Future f = c.stream.single;
f.catchError(expectAsync1((error) { Expect.isTrue(error is StateError); }));
new Events.fromIterable([]).replay(c);
});
test("single error", () {
- StreamController c = new StreamController();
+ StreamController c = new StreamController(sync: true);
Future f = c.stream.single;
f.catchError(expectAsync1((error) { Expect.equals("error", error); }));
Events errorEvents = new Events()..error("error")..close();
@@ -35,7 +35,7 @@
});
test("single error 2", () {
- StreamController c = new StreamController();
+ StreamController c = new StreamController(sync: true);
Future f = c.stream.single;
f.catchError(expectAsync1((error) { Expect.equals("error", error); }));
Events errorEvents = new Events()..error("error")..error("error2")..close();
@@ -43,7 +43,7 @@
});
test("single error 3", () {
- StreamController c = new StreamController();
+ StreamController c = new StreamController(sync: true);
Future f = c.stream.single;
f.catchError(expectAsync1((error) { Expect.equals("error", error); }));
Events errorEvents = new Events()..add(499)..error("error")..close();
diff --git a/tests/lib/async/stream_single_to_multi_subscriber_test.dart b/tests/lib/async/stream_single_to_multi_subscriber_test.dart
index 1f4d693..8fd37e1 100644
--- a/tests/lib/async/stream_single_to_multi_subscriber_test.dart
+++ b/tests/lib/async/stream_single_to_multi_subscriber_test.dart
@@ -13,7 +13,7 @@
main() {
test("tomulti 1", () {
- StreamController c = new StreamController<int>();
+ StreamController c = new StreamController<int>(sync: true);
Stream<int> multi = c.stream.asBroadcastStream();
// Listen twice.
multi.listen(expectAsync1((v) => Expect.equals(42, v)));
@@ -22,7 +22,7 @@
});
test("tomulti 2", () {
- StreamController c = new StreamController<int>();
+ StreamController c = new StreamController<int>(sync: true);
Stream<int> multi = c.stream.asBroadcastStream();
Events expected = new Events.fromIterable([1, 2, 3, 4, 5]);
Events actual1 = new Events.capture(multi);
@@ -37,7 +37,7 @@
});
test("tomulti no-op", () {
- StreamController c = new StreamController<int>();
+ StreamController c = new StreamController<int>(sync: true);
Stream<int> multi = c.stream.asBroadcastStream();
Events expected = new Events.fromIterable([1, 2, 3, 4, 5]);
Events actual1 = new Events.capture(multi);
diff --git a/tests/lib/async/stream_state_helper.dart b/tests/lib/async/stream_state_helper.dart
index c433e39..1ab5a4c 100644
--- a/tests/lib/async/stream_state_helper.dart
+++ b/tests/lib/async/stream_state_helper.dart
@@ -8,46 +8,12 @@
import "dart:async";
import "dart:collection";
-class StreamProtocolTest {
- bool trace = false;
- StreamController _controller;
- Stream _controllerStream;
+class SubscriptionProtocolTest {
+ final StreamProtocolTest _streamTest;
+ final int id;
StreamSubscription _subscription;
- List<Event> _expectations = new List<Event>();
- int _nextExpectationIndex = 0;
- Function _onComplete;
- StreamProtocolTest([bool broadcast = false]) {
- _controller = new StreamController(
- onListen: _onSubcription,
- onPause: _onPause,
- onResume: _onResume,
- onCancel: _onCancel);
- if (broadcast) {
- _controllerStream = _controller.stream.asBroadcastStream();
- } else {
- _controllerStream = _controller.stream;
- }
- _onComplete = expectAsync0((){
- _onComplete = null; // Being null marks the test to be complete.
- });
- }
-
- // Actions on the stream and controller.
- void add(var data) { _controller.add(data); }
- void error(var error) { _controller.addError(error); }
- void close() { _controller.close(); }
-
- void subscribe({bool cancelOnError : false}) {
- // TODO(lrn): Handle more subscriptions (e.g., a subscription-id
- // per subscription, and an id on event _expectations).
- if (_subscription != null) throw new StateError("Already subscribed");
- _subscription = _controllerStream.listen(_onData,
- onError: _onError,
- onDone: _onDone,
- cancelOnError:
- cancelOnError);
- }
+ SubscriptionProtocolTest(this.id, this._subscription, this._streamTest);
void pause([Future resumeSignal]) {
if (_subscription == null) throw new StateError("Not subscribed");
@@ -65,34 +31,138 @@
_subscription = null;
}
+ void expectData(var data, [void action()]) {
+ _streamTest._expectData(this, data, action);
+ }
+
+ void expectError(var error, [void action()]) {
+ _streamTest._expectError(this, error, action);
+ }
+
+ void expectDone([void action()]) {
+ _streamTest._expectDone(this, action);
+ }
+}
+
+class StreamProtocolTest {
+ bool trace = false;
+ // If not a broadcast stream, the onComplete is called automatically by
+ // the first onCancel.
+ bool isBroadcast;
+ StreamController _controller;
+ Stream _controllerStream;
+ // Most recent subscription created. Used as default for pause/resume.
+ SubscriptionProtocolTest _latestSubscription;
+ List<Event> _expectations = new List<Event>();
+ int _nextExpectationIndex = 0;
+ int _subscriptionIdCounter = 0;
+ Function _onComplete;
+
+ StreamProtocolTest.broadcast({ bool sync: false })
+ : isBroadcast = true {
+ _controller = new StreamController.broadcast(
+ sync: sync,
+ onListen: _onListen,
+ onCancel: _onCancel);
+ _controllerStream = _controller.stream;
+ _onComplete = expectAsync0((){
+ _onComplete = null; // Being null marks the test as being complete.
+ });
+ }
+
+ StreamProtocolTest({ bool broadcast: false, bool sync: false })
+ : isBroadcast = false {
+ _controller = new StreamController(
+ sync: sync,
+ onListen: _onListen,
+ onPause: _onPause,
+ onResume: _onResume,
+ onCancel: _onCancel);
+ if (broadcast) {
+ _controllerStream = _controller.stream.asBroadcastStream();
+ } else {
+ _controllerStream = _controller.stream;
+ }
+ _onComplete = expectAsync0((){
+ _onComplete = null; // Being null marks the test as being complete.
+ });
+ }
+
+ // Actions on the stream and controller.
+ void add(var data) { _controller.add(data); }
+ void error(var error) { _controller.addError(error); }
+ void close() { _controller.close(); }
+
+ SubscriptionProtocolTest listen({bool cancelOnError : false}) {
+ int subscriptionId = _subscriptionIdCounter++;
+
+ StreamSubscription subscription = _controllerStream.listen(
+ (var data) { _onData(subscriptionId, data); },
+ onError: (Object error) { _onError(subscriptionId, error); },
+ onDone: () { _onDone(subscriptionId); },
+ cancelOnError: cancelOnError);
+ _latestSubscription =
+ new SubscriptionProtocolTest(subscriptionId, subscription, this);
+ if (trace) {
+ print("[Listen #$subscriptionId(#${_latestSubscription.hashCode})]");
+ }
+ return _latestSubscription;
+ }
+
+ // Actions on the most recently created subscription.
+ void pause([Future resumeSignal]) {
+ _latestSubscription.pause(resumeSignal);
+ }
+
+ void resume() {
+ _latestSubscription.resume();
+ }
+
+ void cancel() {
+ _latestSubscription.cancel();
+ _latestSubscription = null;
+ }
+
+ // End the test now. There must be no open expectations, and no furter
+ // expectations will be allowed.
+ // Called automatically by an onCancel event on a non-broadcast stream.
+ void terminate() {
+ if (_nextExpectationIndex != _expectations.length) {
+ _withNextExpectation((Event expect) {
+ _fail("Expected: $expect\n"
+ "Found : Early termination.\n${expect._stackTrace}");
+ });
+ }
+ _onComplete();
+ }
+
// Handling of stream events.
- void _onData(var data) {
- if (trace) print("[Data : $data]");
+ void _onData(int id, var data) {
+ if (trace) print("[Data#$id : $data]");
_withNextExpectation((Event expect) {
- if (!expect.matchData(data)) {
+ if (!expect.matchData(id, data)) {
_fail("Expected: $expect\n"
- "Found : [Data: $data]");
+ "Found : [Data#$id: $data]\n${expect._stackTrace}");
}
});
}
- void _onError(error) {
- if (trace) print("[Error : $error]");
+ void _onError(int id, Object error) {
+ if (trace) print("[Error#$id : $error]");
_withNextExpectation((Event expect) {
- if (!expect.matchError(error)) {
+ if (!expect.matchError(id, error)) {
_fail("Expected: $expect\n"
- "Found : [Error: ${error}]");
+ "Found : [Error#$id: ${error}]\n${expect._stackTrace}");
}
});
}
- void _onDone() {
- if (trace) print("[Done]");
- _subscription = null;
+ void _onDone(int id) {
+ if (trace) print("[Done#$id]");
_withNextExpectation((Event expect) {
- if (!expect.matchDone()) {
+ if (!expect.matchDone(id)) {
_fail("Expected: $expect\n"
- "Found : [Done]");
+ "Found : [Done#$id]\n${expect._stackTrace}");
}
});
}
@@ -102,7 +172,7 @@
_withNextExpectation((Event expect) {
if (!expect.matchPause()) {
_fail("Expected: $expect\n"
- "Found : [Paused]");
+ "Found : [Paused]\n${expect._stackTrace}");
}
});
}
@@ -112,17 +182,17 @@
_withNextExpectation((Event expect) {
if (!expect.matchResume()) {
_fail("Expected: $expect\n"
- "Found : [Resumed]");
+ "Found : [Resumed]\n${expect._stackTrace}");
}
});
}
- void _onSubcription() {
+ void _onListen() {
if (trace) print("[Subscribed]");
_withNextExpectation((Event expect) {
if (!expect.matchSubscribe()) {
_fail("Expected: $expect\n"
- "Found: [Subscribed]");
+ "Found: [Subscribed]\n${expect._stackTrace}");
}
});
}
@@ -132,29 +202,22 @@
_withNextExpectation((Event expect) {
if (!expect.matchCancel()) {
_fail("Expected: $expect\n"
- "Found: [Cancelled]");
+ "Found: [Cancelled]\n${expect._stackTrace}");
}
});
+ if (!isBroadcast) terminate();
}
void _withNextExpectation(void action(Event expect)) {
if (_nextExpectationIndex == _expectations.length) {
+ _nextExpectationIndex++;
action(new MismatchEvent());
} else {
- Event next = _expectations[_nextExpectationIndex];
+ Event next = _expectations[_nextExpectationIndex++];
action(next);
}
- _nextExpectationIndex++;
- _checkDone();
}
- void _checkDone() {
- if (_nextExpectationIndex == _expectations.length) {
- _onComplete();
- }
- }
-
-
// Adds _expectations.
void expectAny([void action()]) {
if (_onComplete == null) {
@@ -162,43 +225,62 @@
}
_expectations.add(new LogAnyEvent(action));
}
+
void expectData(var data, [void action()]) {
+ _expectData(null, data, action);
+ }
+
+ void _expectData(SubscriptionProtocolTest sub, var data, void action()) {
if (_onComplete == null) {
_fail("Adding expectation after completing");
}
- _expectations.add(new DataEvent(data, action));
+ _expectations.add(new DataEvent(sub, data, action));
}
+
void expectError(var error, [void action()]) {
+ _expectError(null, error, action);
+ }
+
+ void _expectError(SubscriptionProtocolTest sub, var error, void action()) {
if (_onComplete == null) {
_fail("Adding expectation after completing");
}
- _expectations.add(new ErrorEvent(error, action));
+ _expectations.add(new ErrorEvent(sub, error, action));
}
+
void expectDone([void action()]) {
+ _expectDone(null, action);
+ }
+
+ void _expectDone(SubscriptionProtocolTest sub, [void action()]) {
if (_onComplete == null) {
_fail("Adding expectation after completing");
}
- _expectations.add(new DoneEvent(action));
+ _expectations.add(new DoneEvent(sub, action));
}
+
void expectPause([void action()]) {
if (_onComplete == null) {
_fail("Adding expectation after completing");
}
_expectations.add(new PauseCallbackEvent(action));
}
+
void expectResume([void action()]) {
if (_onComplete == null) {
_fail("Adding expectation after completing");
}
_expectations.add(new ResumeCallbackEvent(action));
}
- void expectSubscription([void action()]) {
+
+ void expectListen([void action()]) {
if (_onComplete == null) {
_fail("Adding expectation after completing");
}
_expectations.add(
new SubscriptionCallbackEvent(action));
}
+
void expectCancel([void action()]) {
if (_onComplete == null) {
_fail("Adding expectation after completing");
@@ -211,45 +293,58 @@
if (_nextExpectationIndex == 0) {
throw "Unexpected event:\n$message\nNo earlier events matched.";
}
- throw "Unexpected event:\n$message\nMatched so far:\n"
- " ${_expectations.take(_nextExpectationIndex).join("\n ")}";
+ StringBuffer buf = new StringBuffer();
+ for (int i = 0; i < _expectations.length; i++) {
+ if (i == _nextExpectationIndex - 1) {
+ buf.write("->");
+ } else {
+ buf.write(" ");
+ }
+ buf.write(_expectations[i]);
+ buf.write("\n");
+ }
+ throw "Unexpected event:\n$message\nAll expectations:\n$buf";
}
}
class Event {
Function _action;
- Event(void this._action());
+ StackTrace _stackTrace;
+ Event(void action())
+ : _action = (action == null) ? null : expectAsync0(action) {
+ try { throw 0; } catch (_, s) { _stackTrace = s; }
+ }
- bool matchData(var data) {
- if (!_testData(data)) return false;
- if (_action != null) _action();
- return true;
+ bool matchData(int id, var data) {
+ return false;
}
- bool matchError(e) {
- if (!_testError(e)) return false;
- if (_action != null) _action();
- return true;
+
+ bool matchError(int id, e) {
+ return false;
}
- bool matchDone() {
- if (!_testDone()) return false;
- if (_action != null) _action();
- return true;
+
+ bool matchDone(int id) {
+ return false;
}
+
bool matchPause() {
if (!_testPause()) return false;
if (_action != null) _action();
return true;
}
+
bool matchResume() {
if (!_testResume()) return false;
if (_action != null) _action();
return true;
}
+
bool matchSubscribe() {
if (!_testSubscribe()) return false;
if (_action != null) _action();
return true;
}
+
bool matchCancel() {
if (!_testCancel()) return false;
if (_action != null) _action();
@@ -265,29 +360,59 @@
bool _testCancel() => false;
}
+class SubscriptionEvent extends Event {
+ SubscriptionProtocolTest subscription;
+ SubscriptionEvent(this.subscription, void action()) : super(action);
+
+ bool matchData(int id, var data) {
+ if (subscription != null && subscription.id != id) return false;
+ if (!_testData(data)) return false;
+ if (_action != null) _action();
+ return true;
+ }
+
+ bool matchError(int id, e) {
+ if (subscription != null && subscription.id != id) return false;
+ if (!_testError(e)) return false;
+ if (_action != null) _action();
+ return true;
+ }
+
+ bool matchDone(int id) {
+ if (subscription != null && subscription.id != id) return false;
+ if (!_testDone()) return false;
+ if (_action != null) _action();
+ return true;
+ }
+
+ String get _id => (subscription == null) ? "" : "#${subscription.id}";
+}
+
class MismatchEvent extends Event {
MismatchEvent() : super(null);
toString() => "[No event expected]";
}
-class DataEvent extends Event {
+class DataEvent extends SubscriptionEvent {
final data;
- DataEvent(this.data, void action()) : super(action);
+ DataEvent(SubscriptionProtocolTest sub, this.data, void action())
+ : super(sub, action);
bool _testData(var data) => this.data == data;
- String toString() => "[Data: $data]";
+ String toString() => "[Data$_id: $data]";
}
-class ErrorEvent extends Event {
+class ErrorEvent extends SubscriptionEvent {
final error;
- ErrorEvent(this.error, void action()) : super(action);
+ ErrorEvent(SubscriptionProtocolTest sub, this.error, void action())
+ : super(sub, action);
bool _testError(error) => this.error == error;
- String toString() => "[Error: $error]";
+ String toString() => "[Error$_id: $error]";
}
-class DoneEvent extends Event {
- DoneEvent(void action()) : super(action);
+class DoneEvent extends SubscriptionEvent {
+ DoneEvent(SubscriptionProtocolTest sub, void action()) : super(sub, action);
bool _testDone() => true;
- String toString() => "[Done]";
+ String toString() => "[Done$_id]";
}
class PauseCallbackEvent extends Event {
@@ -314,38 +439,47 @@
String toString() => "[Cancelled]";
}
-
+/** Event matcher that matches any other event. */
class LogAnyEvent extends Event {
String _actual = "*Not matched yet*";
+
LogAnyEvent(void action()) : super(action);
+
bool _testData(var data) {
_actual = "*[Data $data]";
return true;
}
+
bool _testError(error) {
_actual = "*[Error ${error}]";
return true;
}
+
bool _testDone() {
_actual = "*[Done]";
return true;
}
+
bool _testPause() {
_actual = "*[Paused]";
return true;
}
+
bool _testResume() {
_actual = "*[Resumed]";
return true;
}
+
bool _testSubcribe() {
_actual = "*[Subscribed]";
return true;
}
+
bool _testCancel() {
_actual = "*[Cancelled]";
return true;
}
+ /** Returns a representation of the event it was tested against. */
String toString() => _actual;
}
diff --git a/tests/lib/async/stream_state_nonzero_timer_test.dart b/tests/lib/async/stream_state_nonzero_timer_test.dart
index 0beff6f..38c14a6 100644
--- a/tests/lib/async/stream_state_nonzero_timer_test.dart
+++ b/tests/lib/async/stream_state_nonzero_timer_test.dart
@@ -23,8 +23,8 @@
var p = broadcast ? "BC" : "SC";
test("$p-sub-data/pause/resume/pause/resume-done", () {
- var t = new StreamProtocolTest(broadcast);
- t..expectSubscription()
+ var t = new StreamProtocolTest(broadcast: broadcast);
+ t..expectListen()
..expectData(42, () {
t.pause();
})
@@ -34,12 +34,12 @@
..expectResume(() { t.close(); })
..expectDone()
..expectCancel();
- t..subscribe()..add(42);
+ t..listen()..add(42);
});
test("$p-sub-data/pause-done", () {
- var t = new StreamProtocolTest(broadcast);
- t..expectSubscription()
+ var t = new StreamProtocolTest(broadcast: broadcast);
+ t..expectListen()
..expectData(42, () {
t.pause(new Future.delayed(ms5, () => null));
})
@@ -48,12 +48,12 @@
..expectCancel();
// We are calling "close" while the controller is actually paused,
// and it will stay paused until the pending events are sent.
- t..subscribe()..add(42)..close();
+ t..listen()..add(42)..close();
});
test("$p-sub-data/pause-resume/done", () {
- var t = new StreamProtocolTest(broadcast);
- t..expectSubscription()
+ var t = new StreamProtocolTest(broadcast: broadcast);
+ t..expectListen()
..expectData(42, () {
t.pause(new Future.delayed(ms5, () => null));
})
@@ -61,12 +61,12 @@
..expectResume(t.close)
..expectDone()
..expectCancel();
- t..subscribe()..add(42);
+ t..listen()..add(42);
});
test("$p-sub-data/data+pause-data-resume-done", () {
- var t = new StreamProtocolTest(broadcast);
- t..expectSubscription()
+ var t = new StreamProtocolTest(broadcast: broadcast);
+ t..expectListen()
..expectData(42, () {
t.add(43);
t.pause(new Future.delayed(ms5, () => null));
@@ -79,12 +79,12 @@
..expectResume(t.close)
..expectDone()
..expectCancel();
- t..subscribe()..add(42);
+ t..listen()..add(42);
});
-return;
+
test("$p-pause-during-callback", () {
- var t = new StreamProtocolTest(broadcast);
- t..expectSubscription()
+ var t = new StreamProtocolTest(broadcast: broadcast);
+ t..expectListen()
..expectData(42, () {
t.pause();
})
@@ -98,7 +98,7 @@
})
..expectDone()
..expectCancel();
- t..subscribe()
+ t..listen()
..add(42);
});
}
diff --git a/tests/lib/async/stream_state_test.dart b/tests/lib/async/stream_state_test.dart
index 08cb7a1..bee7f9b 100644
--- a/tests/lib/async/stream_state_test.dart
+++ b/tests/lib/async/stream_state_test.dart
@@ -11,38 +11,44 @@
const ms5 = const Duration(milliseconds: 5);
main() {
- mainTest(false);
- // TODO(floitsch): reenable?
- // mainTest(true);
+ mainTest(sync: true, broadcast: false);
+ mainTest(sync: true, broadcast: true);
+ mainTest(sync: false, broadcast: false);
+ mainTest(sync: false, broadcast: true);
}
-mainTest(bool broadcast) {
- var p = broadcast ? "BC" : "SC";
+mainTest({bool sync, bool broadcast}) {
+ var p = (sync ? "S" : "AS") + (broadcast ? "BC" : "SC");
test("$p-sub-data-done", () {
- var t = new StreamProtocolTest(broadcast);
- t..expectSubscription()
+ var t = new StreamProtocolTest(sync: sync, broadcast: broadcast);
+ t..expectListen()
..expectData(42)
..expectDone()
..expectCancel();
- t..subscribe()..add(42)..close();
+ t..listen()..add(42)..close();
});
- test("$p-data-done-sub", () {
- var t = new StreamProtocolTest(broadcast);
- if (broadcast) {
- t..expectDone();
- } else {
- t..expectSubscription()
- ..expectData(42)
- ..expectDone()
- ..expectCancel();
- }
- t..add(42)..close()..subscribe();
+ test("$p-data-done-sub-sync", () {
+ var t = new StreamProtocolTest(sync: sync, broadcast: broadcast);
+ t..expectListen()
+ ..expectData(42)
+ ..expectDone()
+ ..expectCancel();
+ t..add(42)..close()..listen();
+ });
+
+ test("$p-data-done-sub-async", () {
+ var t = new StreamProtocolTest(sync: sync, broadcast: broadcast);
+ t..expectListen()
+ ..expectData(42)
+ ..expectDone()
+ ..expectCancel();
+ t..add(42)..close()..listen();
});
test("$p-sub-data/pause+resume-done", () {
- var t = new StreamProtocolTest(broadcast);
- t..expectSubscription()
+ var t = new StreamProtocolTest(sync: sync, broadcast: broadcast);
+ t..expectListen()
..expectData(42, () {
t.pause();
t.resume();
@@ -50,16 +56,16 @@
})
..expectDone()
..expectCancel();
- t..subscribe()..add(42);
+ t..listen()..add(42);
});
test("$p-sub-data-unsubonerror", () {
- var t = new StreamProtocolTest(broadcast);
- t..expectSubscription()
+ var t = new StreamProtocolTest(sync: sync, broadcast: broadcast);
+ t..expectListen()
..expectData(42)
..expectError("bad")
..expectCancel();
- t..subscribe(cancelOnError: true)
+ t..listen(cancelOnError: true)
..add(42)
..error("bad")
..add(43)
@@ -67,14 +73,14 @@
});
test("$p-sub-data-no-unsubonerror", () {
- var t = new StreamProtocolTest(broadcast);
- t..expectSubscription()
+ var t = new StreamProtocolTest(sync: sync, broadcast: broadcast);
+ t..expectListen()
..expectData(42)
..expectError("bad")
..expectData(43)
..expectDone()
..expectCancel();
- t..subscribe(cancelOnError: false)
+ t..listen(cancelOnError: false)
..add(42)
..error("bad")
..add(43)
@@ -82,15 +88,18 @@
});
test("$p-pause-resume-during-event", () {
- var t = new StreamProtocolTest(broadcast);
- t..expectSubscription()
+ var t = new StreamProtocolTest(sync: sync, broadcast: broadcast);
+ t..expectListen()
..expectData(42, () {
t.pause();
t.resume();
- })
- ..expectDone()
+ });
+ if (!broadcast && !sync) {
+ t..expectPause();
+ }
+ t..expectDone()
..expectCancel();
- t..subscribe()
+ t..listen()
..add(42)
..close();
});
diff --git a/tests/lib/async/stream_subscription_as_future_test.dart b/tests/lib/async/stream_subscription_as_future_test.dart
index 5be8f79..3c2c082 100644
--- a/tests/lib/async/stream_subscription_as_future_test.dart
+++ b/tests/lib/async/stream_subscription_as_future_test.dart
@@ -20,7 +20,7 @@
});
test("subscription.asStream success2", () {
- StreamController controller = new StreamController();
+ StreamController controller = new StreamController(sync: true);
[1, 2, 3].forEach(controller.add);
controller.close();
Stream stream = controller.stream;
@@ -41,7 +41,7 @@
});
test("subscription.asStream failure", () {
- StreamController controller = new StreamController();
+ StreamController controller = new StreamController(sync: true);
[1, 2, 3].forEach(controller.add);
controller.addError("foo");
controller.close();
diff --git a/tests/lib/async/stream_transform_test.dart b/tests/lib/async/stream_transform_test.dart
index 414c02c..fc6a3cf 100644
--- a/tests/lib/async/stream_transform_test.dart
+++ b/tests/lib/async/stream_transform_test.dart
@@ -14,7 +14,7 @@
// Regression tests for http://dartbug.com/8310 and 8311
test("simpleDone", () {
- StreamController c = new StreamController();
+ StreamController c = new StreamController(sync: true);
Stream out = c.stream.handleError((x){}).handleError((x){});
out.listen((v){}, onDone: expectAsync0(() {}));
// Should not throw.
@@ -22,7 +22,7 @@
});
test("with events", () {
- StreamController c = new StreamController();
+ StreamController c = new StreamController(sync: true);
Events expected = new Events.fromIterable([10, 12]);
Events input = new Events.fromIterable([1, 2, 3, 4, 5, 6, 7]);
Events actual = new Events.capture(
@@ -34,7 +34,7 @@
});
test("paused events", () {
- StreamController c = new StreamController();
+ StreamController c = new StreamController(sync: true);
Events expected = new Events.fromIterable([10, 12]);
Events input = new Events.fromIterable([1, 2, 3, 4, 5, 6, 7]);
Events actual = new Events.capture(
@@ -48,7 +48,7 @@
});
test("closing after done", () {
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
controller.stream.map((e) => e).transform(new StreamTransformer(
handleData: (element, sink) { sink.add(element); },
handleDone: (sink) { sink.close(); })
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index f905060..a1bd9e0 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -2,16 +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.
-# The typed_data library is not supported by dart2js or dart2dart yet.
-[ $compiler == dart2js || $compiler == dart2dart ]
-typed_data/*: Fail
-
-
-# The typed_data library is not supported by dart2js or dart2dart yet.
-[ $compiler == dart2js || $compiler == dart2dart ]
-typed_data/*: Skip
-
-
[ $compiler == dart2js ]
math/*: Skip
mirrors/mirrors_test: Fail # TODO(ahe): I'm working on fixing this.
@@ -20,6 +10,15 @@
async/run_async4_test: Pass, Fail # no global exception handler in isolates. http://dartbug.com/9012
async/run_async6_test: Fail # global error handling is not supported. http://dartbug.com/5958
+# SIMD is unsupported on dart2js.
+typed_data/float32x4_test: Fail, OK
+typed_data/float32x4_list_test: Fail, OK
+typed_data/float32x4_unbox_phi_test: Fail, OK
+typed_data/float32x4_unbox_regress_test: Fail, OK
+
+[ $compiler == dart2js && ($runtime == d8 || $runtime == ie9) ]
+typed_data/byte_data_test: Fail, OK # d8/ie9 doesn't support DataView
+
[ $compiler == dart2js && $minified ]
mirrors/mirrors_resolve_fields_test: Fail # Issue 6490
@@ -61,8 +60,16 @@
# implement timer (currently only in d8)
[ $compiler == dart2dart ]
-# Skip until we stabilize language tests.
-*: Skip
+mirrors/mirrors_test: Fail # Issue 10957
+mirrors/library_uri_package_test: Fail # Issue 10957
+async/run_async6_test: Fail # Issue 10957 - may be related to issue 10910
+
+[ $compiler == dart2dart && $minified ]
+json/json_test: Fail # Issue 10961
+typed_data/float32x4_test: Fail # Issue 10961
+typed_data/float32x4_list_test: Fail # Issue 10961
+typed_data/float32x4_unbox_phi_test: Fail # Issue 10961
+typed_data/float32x4_unbox_regress_test: Fail # Issue 10961
[ $runtime == safari]
# Bug in JSC: the test only passes when being debugged.
@@ -88,6 +95,7 @@
[ $runtime == vm || ($compiler == none && $runtime == drt) ]
async/run_async3_test: Fail # _enqueueImmediate runs after Timer. http://dartbug.com/9001.
+mirrors/metadata_test: Fail # http://dartbug.com/10906
[ $compiler == none && $runtime == drt ]
async/timer_isolate_test: Skip # See Issue 4997
@@ -96,6 +104,13 @@
mirrors/library_uri_io_test: Skip # Not intended for drt as it uses dart:io.
async/run_async6_test: Fail # Issue 10910
+[ $compiler == none && $runtime == drt && $system == windows ]
+async/multiple_timer_test: Fail # See Issue 10982
+async/timer_test: Fail # See Issue 10982
+
+[ $arch == arm ]
+*: Skip
+
[ $arch == simarm ]
*: Skip
diff --git a/tests/lib/mirrors/metadata_test.dart b/tests/lib/mirrors/metadata_test.dart
new file mode 100644
index 0000000..973bf34
--- /dev/null
+++ b/tests/lib/mirrors/metadata_test.dart
@@ -0,0 +1,48 @@
+// 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.
+
+@fisk @symbol
+library test.metadata_test;
+
+import 'dart:mirrors';
+
+const fisk = 'a metadata string';
+
+const symbol = const Symbol('fisk');
+
+@symbol @fisk
+class MyClass {
+}
+
+checkMetadata(DeclarationMirror mirror, List expectedMetadata) {
+ List metadata = mirror.metadata.map((m) => m.reflectee).toList();
+ if (metadata == null) {
+ throw 'Null metadata on $mirror';
+ }
+ int expectedLength = expectedMetadata.length;
+ int actualLength = metadata.length;
+ if (expectedLength != actualLength) {
+ throw 'Expected length = $expectedLength, but got length = $actualLength.';
+ }
+ for (int i = 0; i < expectedLength; i++) {
+ if (metadata[i] != expectedMetadata[i]) {
+ throw '${metadata[i]} is not "${expectedMetadata[i]}"'
+ ' in $mirror at index $i';
+ }
+ }
+ print(metadata);
+}
+
+main() {
+ if (MirrorSystem.getName(symbol) != 'fisk') {
+ // This happened in dart2js due to how early library metadata is
+ // computed.
+ throw 'Bad constant: $symbol';
+ }
+
+ MirrorSystem mirrors = currentMirrorSystem();
+ checkMetadata(mirrors.findLibrary(const Symbol('test.metadata_test')).first,
+ [fisk, symbol]);
+ checkMetadata(reflect(new MyClass()).type, [symbol, fisk]);
+}
diff --git a/tests/lib/typed_data/byte_data_test.dart b/tests/lib/typed_data/byte_data_test.dart
new file mode 100644
index 0000000..cffa631
--- /dev/null
+++ b/tests/lib/typed_data/byte_data_test.dart
@@ -0,0 +1,40 @@
+// 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 'dart:typed_data';
+
+main() {
+ testRegress10898();
+}
+
+testRegress10898() {
+ ByteData data = new ByteData(16);
+ Expect.equals(16, data.lengthInBytes);
+ for (int i = 0; i < data.lengthInBytes; i++) {
+ Expect.equals(0, data.getInt8(i));
+ data.setInt8(i, 42 + i);
+ Expect.equals(42 + i, data.getInt8(i));
+ }
+
+ ByteData backing = new ByteData(16);
+ ByteData view = new ByteData.view(backing.buffer);
+ for (int i = 0; i < view.lengthInBytes; i++) {
+ Expect.equals(0, view.getInt8(i));
+ view.setInt8(i, 87 + i);
+ Expect.equals(87 + i, view.getInt8(i));
+ }
+
+ view = new ByteData.view(backing.buffer, 4);
+ Expect.equals(12, view.lengthInBytes);
+ for (int i = 0; i < view.lengthInBytes; i++) {
+ Expect.equals(87 + i + 4, view.getInt8(i));
+ }
+
+ view = new ByteData.view(backing.buffer, 8, 4);
+ Expect.equals(4, view.lengthInBytes);
+ for (int i = 0; i < view.lengthInBytes; i++) {
+ Expect.equals(87 + i + 8, view.getInt8(i));
+ }
+}
diff --git a/tests/lib/typed_data/typed_list_iterable_test.dart b/tests/lib/typed_data/typed_list_iterable_test.dart
new file mode 100644
index 0000000..4d4a3db
--- /dev/null
+++ b/tests/lib/typed_data/typed_list_iterable_test.dart
@@ -0,0 +1,180 @@
+// 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 'dart:typed_data';
+
+void testIterableFunctions(list, first, last) {
+ assert(list.length > 0);
+
+ Expect.equals(first, list.first);
+ Expect.equals(last, list.last);
+ Expect.equals(first, list.firstWhere((x) => x == first));
+ Expect.equals(last, list.lastWhere((x) => x == last));
+ if (list.length == 1) {
+ Expect.equals(first, list.single);
+ Expect.equals(first, list.singleWhere((x) => x == last));
+ } else {
+ Expect.throws(() => list.single, (e) => e is StateError);
+ bool isFirst = true;
+ Expect.equals(first, list.singleWhere((x) {
+ if (isFirst) {
+ isFirst = false;
+ return true;
+ }
+ return false;
+ }));
+ }
+ Expect.isFalse(list.isEmpty);
+
+ int i = 0;
+ for (var x in list) {
+ Expect.equals(list[i++], x);
+ }
+ Expect.isTrue(list.any((x) => x == last));
+ Expect.isFalse(list.any((x) => false));
+ Expect.isTrue(list.contains(last));
+ Expect.equals(first, list.elementAt(0));
+ Expect.isTrue(list.every((x) => true));
+ Expect.isFalse(list.every((x) => x != last));
+ Expect.listEquals([], list.expand((x) => []).toList());
+ var expand2 = list.expand((x) => [x, x]);
+ i = 0;
+ for (var x in expand2) {
+ Expect.equals(list[i ~/ 2], x);
+ i++;
+ }
+ Expect.equals(2 * list.length, i);
+ Expect.listEquals(list, list.fold([], (result, x) => result..add(x)));
+ i = 0;
+ list.forEach((x) {
+ Expect.equals(list[i++], x);
+ });
+ Expect.equals(list.toList().join("*"), list.join("*"));
+ Expect.listEquals(list, list.map((x) => x).toList());
+ int mapCount = 0;
+ var mappedList = list.map((x) {
+ mapCount++;
+ return x;
+ });
+ Expect.equals(0, mapCount);
+ Expect.equals(list.length, mappedList.length);
+ Expect.equals(0, mapCount);
+ mappedList.join();
+ Expect.equals(list.length, mapCount);
+
+ Expect.listEquals(list, list.where((x) => true).toList());
+ int whereCount = 0;
+ var whereList = list.where((x) {
+ whereCount++;
+ return true;
+ });
+ Expect.equals(0, whereCount);
+ Expect.equals(list.length, whereList.length);
+ Expect.equals(list.length, whereCount);
+
+ if (list.length > 1) {
+ int reduceResult = 1;
+ Expect.equals(list.length, list.reduce((x, y) => ++reduceResult));
+ } else {
+ Expect.equals(first, list.reduce((x, y) { throw "should not be called"; }));
+ }
+
+ Expect.isTrue(list.skip(list.length).isEmpty);
+ Expect.listEquals(list, list.skip(0).toList());
+ Expect.isTrue(list.skipWhile((x) => true).isEmpty);
+ Expect.listEquals(list, list.skipWhile((x) => false).toList());
+ Expect.listEquals(list, list.take(list.length).toList());
+ Expect.isTrue(list.take(0).isEmpty);
+ Expect.isTrue(list.takeWhile((x) => false).isEmpty);
+ Expect.listEquals(list, list.takeWhile((x) => true).toList());
+ Expect.listEquals(list, list.toList().toList());
+ var l2 = list.toList();
+ l2.add(first);
+ Expect.equals(first, l2.last);
+ var l3 = list.toList(growable: false);
+ Expect.throws(() => l3.add(last), (e) => e is UnsupportedError);
+}
+
+void emptyChecks(list) {
+ assert(list.length == 0);
+
+ Expect.isTrue(list.isEmpty);
+
+ Expect.throws(() => list.first, (e) => e is StateError);
+ Expect.throws(() => list.last, (e) => e is StateError);
+ Expect.throws(() => list.single, (e) => e is StateError);
+ Expect.throws(() => list.firstWhere((x) => true), (e) => e is StateError);
+ Expect.throws(() => list.lastWhere((x) => true), (e) => e is StateError);
+ Expect.throws(() => list.singleWhere((x) => true), (e) => e is StateError);
+
+ Expect.isFalse(list.any((x) => true));
+ Expect.isFalse(list.contains(null));
+ Expect.throws(() => list.elementAt(0), (e) => e is RangeError);
+ Expect.isTrue(list.every((x) => false));
+ Expect.listEquals([], list.expand((x) => []).toList());
+ Expect.listEquals([], list.expand((x) => [x, x]).toList());
+ Expect.listEquals(
+ [], list.expand((x) { throw "should not be reached"; }).toList());
+ Expect.listEquals([], list.fold([], (result, x) => result..add(x)));
+ Expect.equals(list.toList().join("*"), list.join("*"));
+ Expect.listEquals(list, list.map((x) => x).toList());
+ int mapCount = 0;
+ var mappedList = list.map((x) {
+ mapCount++;
+ return x;
+ });
+ Expect.equals(0, mapCount);
+ Expect.equals(list.length, mappedList.length);
+ Expect.equals(0, mapCount);
+ mappedList.join();
+ Expect.equals(list.length, mapCount);
+
+ Expect.listEquals(list, list.where((x) => true).toList());
+ int whereCount = 0;
+ var whereList = list.where((x) {
+ whereCount++;
+ return true;
+ });
+ Expect.equals(0, whereCount);
+ Expect.equals(list.length, whereList.length);
+ Expect.equals(list.length, whereCount);
+
+ Expect.throws(() => list.reduce((x, y) => x), (e) => e is StateError);
+
+ Expect.isTrue(list.skip(list.length).isEmpty);
+ Expect.isTrue(list.skip(0).isEmpty);
+ Expect.isTrue(list.skipWhile((x) => true).isEmpty);
+ Expect.isTrue(list.skipWhile((x) => false).isEmpty);
+ Expect.isTrue(list.take(list.length).isEmpty);
+ Expect.isTrue(list.take(0).isEmpty);
+ Expect.isTrue(list.takeWhile((x) => false).isEmpty);
+ Expect.isTrue(list.takeWhile((x) => true).isEmpty);
+ Expect.isTrue(list.toList().isEmpty);
+ var l2 = list.toList();
+ l2.add(0);
+ Expect.equals(0, l2.last);
+ var l3 = list.toList(growable: false);
+ Expect.throws(() => l3.add(0), (e) => e is UnsupportedError);
+}
+
+main() {
+ testIterableFunctions(new Float32List.fromList([1.5, 9.5]), 1.5, 9.5);
+ testIterableFunctions(new Float64List.fromList([1.5, 9.5]), 1.5, 9.5);
+ testIterableFunctions(new Int8List.fromList([3, 9]), 3, 9);
+ testIterableFunctions(new Int16List.fromList([3, 9]), 3, 9);
+ testIterableFunctions(new Int32List.fromList([3, 9]), 3, 9);
+ testIterableFunctions(new Uint8List.fromList([3, 9]), 3, 9);
+ testIterableFunctions(new Uint16List.fromList([3, 9]), 3, 9);
+ testIterableFunctions(new Uint32List.fromList([3, 9]), 3, 9);
+
+ emptyChecks(new Float32List(0));
+ emptyChecks(new Float64List(0));
+ emptyChecks(new Int8List(0));
+ emptyChecks(new Int16List(0));
+ emptyChecks(new Int32List(0));
+ emptyChecks(new Uint8List(0));
+ emptyChecks(new Uint16List(0));
+ emptyChecks(new Uint32List(0));
+}
diff --git a/tests/standalone/io/file_error_test.dart b/tests/standalone/io/file_error_test.dart
index 16c0e24..8af6f1f 100644
--- a/tests/standalone/io/file_error_test.dart
+++ b/tests/standalone/io/file_error_test.dart
@@ -171,38 +171,6 @@
});
}
-bool checkDirectoryInNonExistentDirectoryException(e) {
- Expect.isTrue(e is FileIOException);
- Expect.isTrue(e.osError != null);
- Expect.isTrue(
- e.toString().indexOf("Cannot retrieve directory for file") != -1);
- // File not not found has error code 2 on all supported platforms.
- Expect.equals(2, e.osError.errorCode);
-
- return true;
-}
-
-void testDirectoryInNonExistentDirectory() {
- Directory temp = tempDir();
- ReceivePort p = new ReceivePort();
- p.receive((x, y) {
- p.close();
- temp.deleteSync(recursive: true);
- });
- var file = new File("${temp.path}/nonExistentDirectory/newFile");
-
- // Create in non-existent directory should throw exception.
- Expect.throws(() => file.directorySync(),
- (e) => checkDirectoryInNonExistentDirectoryException(e));
-
- var dirFuture = file.directory();
- dirFuture.then((directory) => Expect.fail("Unreachable code"))
- .catchError((error) {
- checkDirectoryInNonExistentDirectoryException(error);
- p.toSendPort().send(null);
- });
-}
-
void testReadAsBytesNonExistent() {
Directory temp = tempDir();
ReceivePort p = new ReceivePort();
@@ -481,7 +449,6 @@
testLengthNonExistent();
testCreateInNonExistentDirectory();
testFullPathOnNonExistentDirectory();
- testDirectoryInNonExistentDirectory();
testReadAsBytesNonExistent();
testReadAsTextNonExistent();
testReadAsLinesNonExistent();
diff --git a/tests/standalone/io/file_fuzz_test.dart b/tests/standalone/io/file_fuzz_test.dart
index 3013a01..81d9d4e 100644
--- a/tests/standalone/io/file_fuzz_test.dart
+++ b/tests/standalone/io/file_fuzz_test.dart
@@ -18,7 +18,6 @@
doItSync(f.existsSync);
doItSync(f.createSync);
doItSync(f.deleteSync);
- doItSync(f.directorySync);
doItSync(f.lengthSync);
doItSync(f.modifiedSync);
doItSync(f.fullPathSync);
diff --git a/tests/standalone/io/file_non_ascii_sync_test.dart b/tests/standalone/io/file_non_ascii_sync_test.dart
index 23290e3..c5004f6 100644
--- a/tests/standalone/io/file_non_ascii_sync_test.dart
+++ b/tests/standalone/io/file_non_ascii_sync_test.dart
@@ -20,7 +20,7 @@
// The contents of the file is precomposed utf8.
Expect.equals(precomposed, nonAsciiFile.readAsStringSync());
nonAsciiFile.createSync();
- var path = nonAsciiFile.directorySync().path;
+ var path = nonAsciiFile.directory.path;
Expect.isTrue(path.endsWith(precomposed) || path.endsWith(decomposed));
Expect.equals(6, nonAsciiFile.lengthSync());
nonAsciiFile.lastModifiedSync();
diff --git a/tests/standalone/io/file_non_ascii_test.dart b/tests/standalone/io/file_non_ascii_test.dart
index 3bdc939..3aa0a3a 100644
--- a/tests/standalone/io/file_non_ascii_test.dart
+++ b/tests/standalone/io/file_non_ascii_test.dart
@@ -27,7 +27,7 @@
// The contents of the file is precomposed utf8.
Expect.equals(precomposed, contents);
nonAsciiFile.create().then((_) {
- nonAsciiFile.directory().then((d) {
+ var d = nonAsciiFile.directory;
Expect.isTrue(d.path.endsWith(precomposed) ||
d.path.endsWith(decomposed));
nonAsciiFile.length().then((length) {
@@ -37,8 +37,7 @@
Expect.isTrue(path.endsWith('${precomposed}.txt') ||
path.endsWith('${decomposed}.txt'));
tempDir.delete(recursive: true).then((_) {
- port.close();
- });
+ port.close();
});
});
});
diff --git a/tests/standalone/io/file_test.dart b/tests/standalone/io/file_test.dart
index a94185c..64cedd8 100644
--- a/tests/standalone/io/file_test.dart
+++ b/tests/standalone/io/file_test.dart
@@ -568,50 +568,36 @@
var tempDir = tempDirectory.path;
var file = new File("${tempDir}/testDirectory");
- var errors = 0;
- var dirFuture = file.directory();
- dirFuture.then((d) => Expect.fail("non-existing file"))
- .catchError((e) {
file.create().then((ignore) {
- file.directory().then((Directory d) {
- d.exists().then((exists) {
- Expect.isTrue(exists);
- Expect.isTrue(d.path.endsWith(tempDir));
- file.delete().then((ignore) {
- var fileDir = new File(".");
- var dirFuture2 = fileDir.directory();
- dirFuture2.then((d) => Expect.fail("non-existing file"))
- .catchError((e) {
- var fileDir = new File(tempDir);
- var dirFuture3 = fileDir.directory();
- dirFuture3.then((d) => Expect.fail("non-existing file"))
- .catchError((e) {
- port.toSendPort().send(1);
- });
- });
- });
+ Directory d = file.directory;
+ d.exists().then((xexists) {
+ Expect.isTrue(xexists);
+ Expect.isTrue(d.path.endsWith(tempDir));
+ file.delete().then((ignore) {
+ port.toSendPort().send(1);
});
});
});
- });
}
static void testDirectorySync() {
var tempDir = tempDirectory.path;
var file = new File("${tempDir}/testDirectorySync");
- // Non-existing file should throw exception.
- Expect.throws(file.directorySync, (e) { return e is FileIOException; });
+ // Non-existing file still provides the directory.
+ Expect.equals("${tempDir}", file.directory.path);
file.createSync();
// Check that the path of the returned directory is the temp directory.
- Directory d = file.directorySync();
+ Directory d = file.directory;
Expect.isTrue(d.existsSync());
Expect.isTrue(d.path.endsWith(tempDir));
file.deleteSync();
- // Directories should throw exception.
- var file_dir = new File(".");
- Expect.throws(file_dir.directorySync, (e) { return e is FileIOException; });
- file_dir = new File(tempDir);
- Expect.throws(file_dir.directorySync, (e) { return e is FileIOException; });
+ // The directory getter does not care about file or type of file
+ // system entity.
+ Expect.equals("${tempDir}", file.directory.path);
+ file = new File("foo");
+ Expect.equals(".", file.directory.path);
+ file = new File(".");
+ Expect.equals(".", file.directory.path);
}
// Test for file length functionality.
diff --git a/tests/standalone/io/http_keep_alive_test.dart b/tests/standalone/io/http_keep_alive_test.dart
index b2d821a..3e5d198 100644
--- a/tests/standalone/io/http_keep_alive_test.dart
+++ b/tests/standalone/io/http_keep_alive_test.dart
@@ -25,8 +25,8 @@
Future<HttpServer> startServer() {
return HttpServer.bind("127.0.0.1", 0).then((server) {
server.listen((request) {
- bool chunked = request.queryParameters["chunked"] == "true";
- int length = int.parse(request.queryParameters["length"]);
+ bool chunked = request.uri.queryParameters["chunked"] == "true";
+ int length = int.parse(request.uri.queryParameters["length"]);
var buffer = new List<int>.filled(length, 0);
if (!chunked) request.response.contentLength = length;
request.response.add(buffer);
diff --git a/tests/standalone/io/http_parser_test.dart b/tests/standalone/io/http_parser_test.dart
index dbd9564..a2ebc78 100644
--- a/tests/standalone/io/http_parser_test.dart
+++ b/tests/standalone/io/http_parser_test.dart
@@ -37,7 +37,7 @@
StreamController controller;
void reset() {
_HttpParser httpParser = new _HttpParser.requestParser();
- controller = new StreamController();
+ controller = new StreamController(sync: true);
var port1 = new ReceivePort();
var port2 = new ReceivePort();
@@ -135,7 +135,7 @@
void reset() {
httpParser = new _HttpParser.requestParser();
- controller = new StreamController();
+ controller = new StreamController(sync: true);
var port = new ReceivePort();
controller.stream.pipe(httpParser);
var subscription = httpParser.listen((incoming) {
@@ -198,7 +198,7 @@
int contentLength;
int bytesReceived;
httpParser = new _HttpParser.responseParser();
- controller = new StreamController();
+ controller = new StreamController(sync: true);
var port = new ReceivePort();
controller.stream.pipe(httpParser);
int doneCallCount = 0;
@@ -280,7 +280,7 @@
static void _testParseInvalidResponse(String response, [bool close = false]) {
void testWrite(List<int> requestData, [int chunkSize = -1]) {
_HttpParser httpParser = new _HttpParser.responseParser();
- StreamController controller = new StreamController();
+ StreamController controller = new StreamController(sync: true);
bool errorCalled = false;;
if (chunkSize == -1) chunkSize = requestData.length;
diff --git a/tests/standalone/io/http_server_response_test.dart b/tests/standalone/io/http_server_response_test.dart
index 5b0a525..f31d183 100644
--- a/tests/standalone/io/http_server_response_test.dart
+++ b/tests/standalone/io/http_server_response_test.dart
@@ -102,7 +102,7 @@
}, bytes: bytes * 2);
testServerRequest((server, request) {
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
request.response.addStream(controller.stream)
.then((response) {
response.close();
diff --git a/tests/standalone/io/io_sink_test.dart b/tests/standalone/io/io_sink_test.dart
index 1c96448..de83044 100644
--- a/tests/standalone/io/io_sink_test.dart
+++ b/tests/standalone/io/io_sink_test.dart
@@ -65,7 +65,7 @@
void testAddStreamClose() {
{
var sink = new IOSink(new TestConsumer([0]));
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
sink.addStream(controller.stream)
.then((_) {
sink.close();
@@ -75,7 +75,7 @@
}
{
var sink = new IOSink(new TestConsumer([0, 1, 2]));
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
sink.addStream(controller.stream)
.then((_) {
sink.close();
@@ -90,7 +90,7 @@
void testAddStreamAddClose() {
{
var sink = new IOSink(new TestConsumer([0, 1]));
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
sink.addStream(controller.stream)
.then((_) {
sink.add([1]);
diff --git a/tests/standalone/io/mime_multipart_parser_test.dart b/tests/standalone/io/mime_multipart_parser_test.dart
index 5a81df7..49e5b6a 100644
--- a/tests/standalone/io/mime_multipart_parser_test.dart
+++ b/tests/standalone/io/mime_multipart_parser_test.dart
@@ -14,7 +14,7 @@
List expectedParts,
bool expectError = false]) {
void testWrite(List<int> data, [int chunkSize = -1]) {
- StreamController controller = new StreamController();
+ StreamController controller = new StreamController(sync: true);
var stream = controller.stream.transform(
new MimeMultipartTransformer(boundary));
diff --git a/tests/standalone/io/regress_10026_test.dart b/tests/standalone/io/regress_10026_test.dart
index 44f2e54..444c145 100644
--- a/tests/standalone/io/regress_10026_test.dart
+++ b/tests/standalone/io/regress_10026_test.dart
@@ -10,7 +10,7 @@
void testZLibInflate_regress10026() {
test(data, expect) {
var port = new ReceivePort();
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
controller.stream
.transform(new ZLibInflater())
.transform(new StringDecoder())
@@ -25,46 +25,61 @@
controller.add(data);
controller.close();
}
+ // Generated by using 'gzip -c | od -v -tu1 -An -w12' and adding commas.
test([
- 31, 139, 8, 0, 140, 39, 113, 81, 2, 255, 125, 84, 205, 142, 211, 48, 16,
- 62, 55, 79, 49, 132, 11, 72, 77, 211, 101, 1, 85, 217, 52, 2, 1, 18, 23,
- 224, 0, 23, 142, 211, 120, 210, 142, 54, 177, 131, 237, 164, 173, 16, 239,
- 206, 216, 105, 187, 133, 21, 168, 145, 26, 207, 196, 223, 159, 39, 41,
- 159, 40, 83, 251, 99, 79, 176, 243, 93, 91, 37, 229, 249, 143, 80, 85,
- 201, 172, 244, 236, 91, 170, 62, 28, 176, 235, 91, 130, 247, 166, 67, 214,
- 101, 62, 85, 19, 233, 119, 228, 17, 234, 29, 90, 71, 126, 157, 14, 190,
- 201, 86, 41, 228, 213, 185, 179, 243, 190, 207, 232, 199, 192, 227, 58,
- 125, 103, 180, 39, 237, 179, 192, 150, 66, 61, 173, 214, 169, 167, 131,
- 207, 3, 235, 221, 5, 231, 17, 140, 198, 142, 214, 233, 200, 180, 239, 141,
- 245, 87, 155, 247, 172, 252, 110, 173, 104, 228, 154, 178, 184, 152, 3,
- 107, 246, 140, 109, 230, 106, 108, 105, 125, 115, 194, 113, 254, 40, 6, 2,
- 247, 137, 178, 118, 46, 149, 198, 198, 168, 35, 252, 76, 102, 179, 13,
- 214, 247, 91, 107, 6, 173, 178, 218, 180, 198, 22, 240, 180, 89, 202, 239,
- 197, 157, 52, 59, 180, 91, 214, 5, 44, 195, 162, 71, 165, 88, 111, 79,
- 171, 70, 180, 100, 13, 118, 220, 30, 11, 72, 191, 244, 164, 225, 43, 106,
- 151, 206, 33, 253, 72, 237, 72, 158, 107, 132, 207, 52, 144, 84, 46, 133,
- 57, 188, 181, 162, 113, 14, 78, 30, 205, 28, 89, 110, 2, 86, 50, 251, 149,
- 204, 20, 143, 81, 80, 180, 83, 192, 235, 229, 178, 63, 92, 107, 120, 69,
- 29, 224, 224, 205, 31, 82, 110, 169, 187, 251, 135, 137, 38, 66, 111, 140,
- 85, 100, 51, 139, 138, 7, 87, 192, 77, 124, 94, 216, 176, 104, 89, 223,
- 207, 1, 139, 145, 29, 123, 82, 145, 251, 188, 249, 118, 245, 114, 181,
- 138, 251, 67, 102, 153, 162, 218, 88, 244, 108, 68, 134, 54, 154, 38, 136,
- 55, 29, 41, 70, 120, 214, 225, 33, 187, 22, 253, 124, 202, 245, 28, 240,
- 127, 196, 9, 200, 197, 246, 217, 247, 217, 226, 67, 246, 15, 165, 191,
- 204, 196, 115, 120, 200, 98, 242, 22, 64, 229, 42, 243, 120, 242, 213, 44,
- 41, 243, 105, 168, 147, 50, 72, 146, 25, 23, 198, 48, 25, 187, 155, 71,
- 243, 45, 37, 105, 244, 213, 183, 29, 59, 80, 177, 8, 114, 71, 206, 227,
- 166, 101, 183, 147, 148, 188, 129, 13, 193, 224, 228, 182, 49, 22, 184,
- 109, 7, 231, 67, 54, 35, 1, 77, 112, 78, 70, 81, 118, 215, 67, 39, 179,
- 234, 22, 240, 221, 12, 178, 148, 224, 60, 104, 138, 16, 49, 105, 241, 194,
- 26, 61, 129, 192, 160, 187, 143, 112, 61, 217, 142, 157, 147, 160, 3, 145,
- 176, 128, 191, 150, 162, 47, 20, 114, 112, 90, 1, 251, 32, 47, 0, 227,
- 136, 220, 138, 72, 10, 48, 2, 111, 105, 203, 147, 46, 163, 23, 101, 222,
- 79, 190, 74, 121, 51, 45, 53, 235, 52, 188, 159, 69, 158, 239, 247, 251,
- 5, 163, 198, 133, 177, 219, 124, 34, 113, 185, 235, 169, 150, 25, 77, 171,
- 79, 198, 146, 112, 10, 96, 55, 225, 44, 4, 9, 171, 136, 86, 230, 49, 197,
- 50, 63, 101, 154, 79, 223, 143, 223, 163, 237, 129, 168, 87, 4, 0, 0],
- '''<!doctype html>
+ 31, 139, 8, 8, 238, 42, 167, 81, 0, 3, 116, 101,
+ 120, 116, 46, 116, 120, 116, 0, 125, 84, 79, 175, 147,
+ 64, 16, 63, 183, 159, 98, 196, 139, 38, 165, 244, 249,
+ 212, 52, 20, 136, 70, 77, 188, 168, 7, 189, 120, 156,
+ 178, 67, 153, 20, 118, 113, 119, 161, 109, 140, 223, 221,
+ 97, 105, 251, 170, 47, 154, 54, 41, 51, 195, 254, 254,
+ 49, 52, 123, 162, 76, 233, 79, 29, 65, 237, 219, 166,
+ 152, 103, 151, 31, 66, 85, 204, 103, 153, 103, 223, 80,
+ 241, 225, 136, 109, 215, 16, 188, 55, 45, 178, 206, 146,
+ 169, 59, 151, 121, 75, 30, 161, 172, 209, 58, 242, 121,
+ 212, 251, 42, 94, 71, 144, 20, 151, 73, 237, 125, 23,
+ 211, 143, 158, 135, 60, 122, 103, 180, 39, 237, 227, 145,
+ 45, 130, 114, 170, 242, 200, 211, 209, 39, 35, 235, 230,
+ 138, 243, 8, 70, 99, 75, 121, 52, 48, 29, 58, 99,
+ 253, 205, 225, 3, 43, 95, 231, 138, 6, 46, 41, 14,
+ 197, 2, 88, 179, 103, 108, 98, 87, 98, 67, 249, 221,
+ 25, 199, 249, 147, 24, 24, 185, 207, 148, 165, 115, 145,
+ 12, 182, 70, 157, 224, 231, 124, 54, 219, 98, 185, 223,
+ 89, 211, 107, 21, 151, 166, 49, 54, 133, 167, 213, 74,
+ 62, 47, 54, 50, 108, 209, 238, 88, 167, 176, 26, 139,
+ 14, 149, 98, 189, 59, 87, 149, 104, 137, 43, 108, 185,
+ 57, 165, 16, 125, 233, 72, 195, 87, 212, 46, 90, 64,
+ 244, 145, 154, 129, 60, 151, 8, 159, 169, 39, 233, 92,
+ 27, 11, 120, 107, 69, 227, 2, 156, 220, 26, 59, 178,
+ 92, 109, 36, 206, 95, 243, 153, 226, 33, 200, 9, 102,
+ 82, 120, 189, 90, 117, 199, 91, 5, 175, 168, 5, 236,
+ 189, 249, 67, 200, 61, 181, 155, 127, 88, 168, 170, 48,
+ 49, 86, 145, 141, 45, 42, 238, 93, 10, 119, 225, 126,
+ 97, 195, 180, 97, 189, 95, 0, 166, 3, 59, 246, 164,
+ 2, 247, 229, 240, 253, 250, 229, 122, 29, 206, 143, 137,
+ 197, 138, 74, 99, 209, 179, 17, 25, 218, 104, 154, 32,
+ 222, 180, 164, 24, 225, 89, 139, 199, 248, 86, 244, 243,
+ 41, 213, 75, 188, 255, 17, 39, 32, 87, 219, 23, 223,
+ 23, 139, 15, 201, 63, 180, 254, 50, 19, 158, 194, 67,
+ 22, 147, 183, 17, 84, 190, 89, 18, 158, 187, 44, 116,
+ 50, 109, 244, 60, 27, 21, 73, 45, 132, 227, 90, 212,
+ 119, 143, 150, 91, 90, 50, 232, 138, 111, 53, 59, 80,
+ 161, 9, 114, 69, 206, 227, 182, 97, 87, 75, 72, 222,
+ 192, 150, 160, 119, 114, 89, 25, 11, 220, 52, 189, 243,
+ 99, 52, 3, 1, 77, 112, 78, 246, 80, 78, 151, 125,
+ 43, 139, 234, 150, 240, 221, 244, 82, 74, 110, 30, 52,
+ 5, 136, 16, 180, 88, 97, 141, 158, 64, 96, 208, 237,
+ 3, 92, 71, 182, 101, 231, 36, 231, 145, 72, 88, 192,
+ 223, 74, 209, 87, 10, 121, 110, 90, 1, 251, 81, 222,
+ 8, 140, 3, 114, 35, 34, 105, 132, 17, 120, 75, 59,
+ 158, 116, 25, 189, 204, 146, 110, 242, 149, 201, 107, 105,
+ 169, 202, 163, 241, 229, 76, 147, 228, 112, 56, 44, 25,
+ 53, 46, 141, 221, 37, 19, 137, 75, 92, 71, 165, 44,
+ 104, 84, 124, 50, 150, 132, 83, 0, 219, 9, 103, 41,
+ 72, 88, 4, 180, 44, 9, 41, 102, 201, 57, 211, 100,
+ 250, 243, 248, 13, 215, 32, 235, 247, 84, 4, 0, 0
+ ], '''
+<!doctype html>
<html>
<head>
<title>Example Domain</title>
@@ -78,7 +93,7 @@
margin: 0;
padding: 0;
font-family: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
-
+
}
div {
width: 600px;
@@ -102,7 +117,7 @@
padding: 1em;
}
}
- </style>
+ </style>
</head>
<body>
diff --git a/tests/standalone/io/stdout_stderr_test.dart b/tests/standalone/io/stdout_stderr_test.dart
index ccd1550..1f7ac91 100644
--- a/tests/standalone/io/stdout_stderr_test.dart
+++ b/tests/standalone/io/stdout_stderr_test.dart
@@ -16,14 +16,14 @@
sink.writeCharCode(72);
sink.add([101, 108, 108, 111, 10]);
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
var future = sink.addStream(controller.stream);
controller.add([72, 101, 108]);
controller.add([108, 111, 10]);
controller.close();
future.then((_) {
- controller = new StreamController();
+ controller = new StreamController(sync: true);
controller.stream.pipe(sink);
controller.add([72, 101, 108]);
controller.add([108, 111, 10]);
diff --git a/tests/standalone/io/string_decoder_test.dart b/tests/standalone/io/string_decoder_test.dart
index 975e1cc..df808ae 100644
--- a/tests/standalone/io/string_decoder_test.dart
+++ b/tests/standalone/io/string_decoder_test.dart
@@ -8,7 +8,7 @@
void test() {
// Code point U+10FFFF is the largest code point supported by Dart.
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
controller.add([0xf0, 0x90, 0x80, 0x80]); // U+10000
controller.add([0xf4, 0x8f, 0xbf, 0xbf]); // U+10FFFF
controller.add([0xf4, 0x90, 0x80, 0x80]); // U+110000
@@ -42,7 +42,7 @@
void testInvalid() {
void invalid(var bytes, var outputLength) {
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
controller.add(bytes);
controller.close();
controller.stream.transform(new StringDecoder()).listen((string) {
diff --git a/tests/standalone/io/string_transformer_test.dart b/tests/standalone/io/string_transformer_test.dart
index a7dd544..e9e11b5 100644
--- a/tests/standalone/io/string_transformer_test.dart
+++ b/tests/standalone/io/string_transformer_test.dart
@@ -17,7 +17,7 @@
0xef, 0xbf, 0xbf,
0xf0, 0x9d, 0x84, 0x9e,
0x100, -0x1, -0xFF];
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
controller.add(data);
controller.close();
var stringStream = controller.stream
@@ -52,7 +52,7 @@
0x80,
0xff,
0x100, -0x1, -0xff];
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
controller.add(data);
controller.close();
var stream = controller.stream
@@ -73,7 +73,7 @@
0x44, 0x61, 0x72, 0x74,
0x7f,
0xf4, 0x100, -0x1, -0xff];
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
controller.add(data);
controller.close();
var stream = controller.stream
@@ -88,7 +88,7 @@
}
void testReadLine1() {
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
var stream = controller.stream
.transform(new StringDecoder())
.transform(new LineTransformer());
@@ -119,7 +119,7 @@
}
void testReadLine2() {
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
var stream = controller.stream
.transform(new StringDecoder())
@@ -187,7 +187,7 @@
}
testErrorHandler() {
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
var errors = 0;
var stream = controller.stream
.transform(new StringDecoder())
@@ -212,7 +212,7 @@
0x80,
0xff,
0x100];
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
controller.add(new String.fromCharCodes(data));
controller.close();
var stream = controller.stream
diff --git a/tests/standalone/io/web_socket_protocol_processor_test.dart b/tests/standalone/io/web_socket_protocol_processor_test.dart
index b655b13..2aa9fb9 100644
--- a/tests/standalone/io/web_socket_protocol_processor_test.dart
+++ b/tests/standalone/io/web_socket_protocol_processor_test.dart
@@ -101,7 +101,7 @@
int messageCount = 0;
// Use the same web socket protocol transformer for all frames.
var transformer = new _WebSocketProtocolTransformer();
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
WebSocketMessageCollector mc = new WebSocketMessageCollector(
controller.stream.transform(transformer),
message);
@@ -165,7 +165,7 @@
void testFragmentedMessages() {
// Use the same web socket protocol transformer for all frames.
var transformer = new _WebSocketProtocolTransformer();
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
WebSocketMessageCollector mc = new WebSocketMessageCollector(
controller.stream.transform(transformer));
@@ -230,7 +230,7 @@
void testUnmaskedMessage() {
var transformer = new _WebSocketProtocolTransformer(true);
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
var port = new ReceivePort();
controller.stream.transform(transformer).listen((_) {}, onError: (e) {
port.close();
diff --git a/tests/standalone/io/zlib_test.dart b/tests/standalone/io/zlib_test.dart
index 6cfa46f..d1214ae 100644
--- a/tests/standalone/io/zlib_test.dart
+++ b/tests/standalone/io/zlib_test.dart
@@ -11,7 +11,7 @@
test(int level, List<int> expected) {
var port = new ReceivePort();
var data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
controller.stream.transform(new ZLibDeflater(gzip: false, level: level))
.fold([], (buffer, data) {
buffer.addAll(data);
@@ -31,7 +31,7 @@
void testZLibDeflateEmpty() {
var port = new ReceivePort();
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
controller.stream.transform(new ZLibDeflater(gzip: false, level: 6))
.fold([], (buffer, data) {
buffer.addAll(data);
@@ -48,7 +48,7 @@
void testZLibDeflateGZip() {
var port = new ReceivePort();
var data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
controller.stream.transform(new ZLibDeflater())
.fold([], (buffer, data) {
buffer.addAll(data);
@@ -92,7 +92,7 @@
test2(bool gzip, int level) {
var port = new ReceivePort();
var data = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
controller.stream
.transform(new ZLibDeflater(gzip: gzip, level: level))
.transform(new ZLibInflater())
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index 6027974..3b328ab 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -88,6 +88,10 @@
io/url_encoding_test: fail
io/web_socket_protocol_processor_test: fail
+# Fails because checked-in dart executable is not up to date.
+io/test_runner_test: fail, OK
+io/skipping_dart2js_compilations_test: fail, OK
+
[ $compiler == dart2js ]
number_identity_test: Skip # Bigints and int/double diff. not supported.
@@ -133,6 +137,9 @@
# Skip until we stabilize language tests.
*: Skip
+[ $arch == arm ]
+*: Skip
+
[ $arch == simarm ]
*: Skip
diff --git a/tests/standalone/typed_data_test.dart b/tests/standalone/typed_data_test.dart
index 21f17a5b..f8f28aa 100644
--- a/tests/standalone/typed_data_test.dart
+++ b/tests/standalone/typed_data_test.dart
@@ -30,7 +30,7 @@
typed_data = new Uint8ClampedList(0);
Expect.isTrue(typed_data is Uint8ClampedList);
- Expect.isFalse(typed_data is Uint8List);
+ Expect.isTrue(typed_data is Uint8List);
Expect.equals(0, typed_data.length);
Expect.equals(0, typed_data.lengthInBytes);
diff --git a/tests/utils/dummy_compiler_test.dart b/tests/utils/dummy_compiler_test.dart
index 50ab451..59d3ee9 100644
--- a/tests/utils/dummy_compiler_test.dart
+++ b/tests/utils/dummy_compiler_test.dart
@@ -29,6 +29,7 @@
class List {}
class Map {}
class Closure {}
+ class BoundClosure {}
class Dynamic_ {}
class Null {}
class StackTrace {}
diff --git a/tests/utils/recursive_import_test.dart b/tests/utils/recursive_import_test.dart
index 59aade0..a21c5a9 100644
--- a/tests/utils/recursive_import_test.dart
+++ b/tests/utils/recursive_import_test.dart
@@ -21,6 +21,7 @@
class Function{}
class List {}
class Map {}
+class BoundClosure {}
class Closure {}
class Dynamic_ {}
class Type {}
diff --git a/tests/utils/utils.status b/tests/utils/utils.status
index d8a3a34..79344f3 100644
--- a/tests/utils/utils.status
+++ b/tests/utils/utils.status
@@ -9,6 +9,7 @@
[ $compiler == none && $runtime == drt ]
dummy_compiler_test: Skip # http://dartbug.com/7233
dart2js_test: Skip # Uses dart:io.
+txt_layout_test: Skip # Might just go away.
[ $compiler == dart2js && $browser ]
*: Skip
@@ -23,6 +24,9 @@
# Skip until we stabilize language tests.
*: Skip
+[ $arch == arm ]
+*: Skip
+
[ $arch == simarm ]
*: Skip
diff --git a/tools/VERSION b/tools/VERSION
index 0a54219..b6d74d9 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -1,4 +1,4 @@
MAJOR 0
MINOR 5
-BUILD 12
+BUILD 13
PATCH 0
diff --git a/tools/bots/compiler.py b/tools/bots/compiler.py
index 38c116b..9dab287 100644
--- a/tools/bots/compiler.py
+++ b/tools/bots/compiler.py
@@ -114,13 +114,13 @@
def UseBrowserController(runtime, system):
supported_platforms = {
'linux': ['ff', 'chromeOnAndroid', 'chrome'],
- 'mac': [],
+ 'mac': ['safari'],
'windows': []
}
# Platforms that we run on the fyi waterfall only.
fyi_supported_platforms = {
'linux': [],
- 'mac': ['safari'],
+ 'mac': [],
'windows': []
}
diff --git a/tools/bots/cross-vm.py b/tools/bots/cross-vm.py
index 54d43c1..3671f20 100644
--- a/tools/bots/cross-vm.py
+++ b/tools/bots/cross-vm.py
@@ -50,14 +50,18 @@
num_run = int(os.environ['BUILDBOT_ANNOTATED_STEPS_RUN'])
if num_run == 1:
with bot.BuildStep('Build %s %s' % (arch, mode)):
- args = [sys.executable, build_py,
- '-m%s' % mode, '--arch=%s' % arch, 'runtime']
+ run([sys.executable, build_py,
+ '-m%s' % mode, '--arch=%s' % arch, 'runtime'])
+ # We need to build 'run_vm_tests.host' as well to enable
+ # test.py to list the VM tests.
+ run([sys.executable, build_py,
+ '-m%s' % mode, '--arch=%s' % arch, 'run_vm_tests.host'])
- run(args)
with bot.BuildStep('Create build tarball'):
run(['tar', '-cjf', tarball, '--exclude=**/obj',
'--exclude=**/obj.host', '--exclude=**/obj.target',
- '--exclude=**/*analyzer*', '--exclude=**/*IA32', 'out/'])
+ '--exclude=**/*analyzer*', '--exclude=**/run_vm_tests.host',
+ 'out/'])
with bot.BuildStep('Upload build tarball'):
uri = "%s/%s" % (GCS_BUCKET, tarball)
diff --git a/tools/coverage.dart b/tools/coverage.dart
new file mode 100644
index 0000000..1c9519e
--- /dev/null
+++ b/tools/coverage.dart
@@ -0,0 +1,492 @@
+// 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 test forks a second vm process that runs a dart script as
+// a debug target, single stepping through the entire program, and
+// recording each breakpoint. At the end, a coverage map of the source
+// is printed.
+//
+// Usage: dart coverage.dart [--wire] [--verbose] target_script.dart
+//
+// --wire see json messages sent between the processes.
+// --verbose see the stdout and stderr output of the debug
+// target process.
+
+import "dart:io";
+import "dart:utf";
+import "dart:json" as JSON;
+
+
+// Whether or not to print debug target process on the console.
+var showDebuggeeOutput = false;
+
+// Whether or not to print the debugger wire messages on the console.
+var verboseWire = false;
+
+
+class Program {
+ static int numBps = 0;
+
+ // Maps source code url to source.
+ static var sources = new Map<String, Source>();
+
+ // Takes a JSON Debugger response and increments the count for
+ // the source position.
+ static void recordBp(Debugger debugger, Map<String,dynamic> msg) {
+ // Progress indicator.
+ if (++numBps % 100 == 0) print(numBps);
+ var location = msg["params"]["location"];
+ if (location == null) return;
+ String url = location["url"];
+ assert(url != null);
+ int tokenPos = location["tokenOffset"];;
+ Source s = sources[url];
+ if (s == null) {
+ debugger.GetLineNumberTable(url);
+ s = new Source(url);
+ sources[url] = s;
+ }
+ s.recordBp(tokenPos);
+ }
+
+ // Prints the annotated source code.
+ static void printCoverage() {
+ print("Coverage info collected from $numBps breakpoints:");
+ for(Source s in sources.values) s.printCoverage();
+ }
+}
+
+
+class Source {
+ final String url;
+
+ // Maps token position to breakpoint count.
+ final tokenCounts = new Map<int,int>();
+
+ // Maps token position to line number.
+ final tokenPosToLine = new Map<int,int>();
+
+ Source(this.url);
+
+ void recordBp(int tokenPos) {
+ var count = tokenCounts[tokenPos];
+ tokenCounts[tokenPos] = count == null ? 1 : count + 1;
+ }
+
+ void SetLineInfo(List lineInfoTable) {
+ // Each line is encoded as an array with first element being the line
+ // number, followed by pairs of (tokenPosition, textOffset).
+ lineInfoTable.forEach((List<int> line) {
+ int lineNumber = line[0];
+ for (int t = 1; t < line.length; t += 2) {
+ assert(tokenPosToLine[line[t]] == null);
+ tokenPosToLine[line[t]] = lineNumber;
+ }
+ });
+ }
+
+ // Print out the annotated source code. For each line that has seen
+ // a breakpoint, print out the maximum breakpoint count for all
+ // tokens in the line.
+ void printCoverage() {
+ var lineCounts = new Map<int,int>(); // BP counts for each line.
+ print(url);
+ tokenCounts.forEach((tp, bpCount) {
+ int lineNumber = tokenPosToLine[tp];
+ var lineCount = lineCounts[lineNumber];
+ // Remember maximum breakpoint count of all tokens in this line.
+ if (lineCount == null || lineCount < bpCount) {
+ lineCounts[lineNumber] = bpCount;
+ }
+ });
+
+ List lines = new File(Uri.parse(url).path).readAsLinesSync();
+ for (int line = 1; line <= lines.length; line++) {
+ String prefix = " ";
+ if (lineCounts.containsKey(line)) {
+ prefix = lineCounts[line].toString();
+ StringBuffer b = new StringBuffer();
+ for (int i = prefix.length; i < 6; i++) b.write(" ");
+ b.write(prefix);
+ prefix = b.toString();
+ }
+ print("${prefix}|${lines[line-1]}");
+ }
+ }
+}
+
+
+class StepCmd {
+ Map msg;
+ StepCmd(int isolateId) {
+ msg = {"id": 0, "command": "stepInto", "params": {"isolateId": isolateId}};
+ }
+ void handleResponse(Map response) {}
+}
+
+
+class GetLineTableCmd {
+ Map msg;
+ GetLineTableCmd(int isolateId, int libraryId, String url) {
+ msg = { "id": 0,
+ "command": "getLineNumberTable",
+ "params": { "isolateId" : isolateId,
+ "libraryId": libraryId,
+ "url": url } };
+ }
+
+ void handleResponse(Map response) {
+ var url = msg["params"]["url"];
+ Source s = Program.sources[url];
+ assert(s != null);
+ s.SetLineInfo(response["result"]["lines"]);
+ }
+}
+
+
+class Debugger {
+ // Debug target process properties.
+ Process targetProcess;
+ Socket socket;
+ bool cleanupDone = false;
+ JsonBuffer responses = new JsonBuffer();
+ List<String> errors = new List();
+
+ // Data collected from debug target.
+ Map currentMessage = null; // Currently handled message sent by target.
+ var outstandingCommand = null;
+ var queuedCommand = null;
+ String scriptUrl = null;
+ bool shutdownEventSeen = false;
+ int isolateId = 0;
+ int libraryId = null;
+
+ int nextMessageId = 0;
+ bool isPaused = false;
+ bool pendingAck = false;
+
+ Debugger(this.targetProcess) {
+ var stdoutStringStream = targetProcess.stdout
+ .transform(new StringDecoder())
+ .transform(new LineTransformer());
+ stdoutStringStream.listen((line) {
+ if (showDebuggeeOutput) {
+ print("TARG: $line");
+ }
+ if (line.startsWith("Debugger listening")) {
+ RegExp portExpr = new RegExp(r"\d+");
+ var port = portExpr.stringMatch(line);
+ print("Debug target found listening at port '$port'");
+ openConnection(int.parse(port));
+ }
+ });
+
+ var stderrStringStream = targetProcess.stderr
+ .transform(new StringDecoder())
+ .transform(new LineTransformer());
+ stderrStringStream.listen((line) {
+ if (showDebuggeeOutput) {
+ print("TARG: $line");
+ }
+ });
+ }
+
+ // Handle debugger events, updating the debugger state.
+ void handleEvent(Map<String,dynamic> msg) {
+ if (msg["event"] == "isolate") {
+ if (msg["params"]["reason"] == "created") {
+ isolateId = msg["params"]["id"];
+ assert(isolateId != null);
+ print("Debuggee isolate id $isolateId created.");
+ } else if (msg["params"]["reason"] == "shutdown") {
+ print("Debuggee isolate id ${msg["params"]["id"]} shut down.");
+ shutdownEventSeen = true;
+ }
+ } else if (msg["event"] == "breakpointResolved") {
+ var bpId = msg["params"]["breakpointId"];
+ assert(bpId != null);
+ var isolateId = msg["params"]["isolateId"];
+ assert(isolateId != null);
+ var location = msg["params"]["location"];
+ assert(location != null);
+ print("Isolate $isolateId: breakpoint $bpId resolved"
+ " at location $location");
+ // We may want to maintain a table of breakpoints in the future.
+ } else if (msg["event"] == "paused") {
+ isPaused = true;
+ if (libraryId == null) {
+ libraryId = msg["params"]["location"]["libraryId"];
+ assert(libraryId != null);
+ }
+ if (msg["params"]["reason"] == "breakpoint") {
+ Program.recordBp(this, msg);
+ }
+ } else {
+ error("Error: unknown debugger event received");
+ }
+ }
+
+ // Handle one JSON message object and match it to the
+ // expected events and responses in the debugging script.
+ void handleMessage(Map<String,dynamic> receivedMsg) {
+ currentMessage = receivedMsg;
+ if (receivedMsg["event"] != null) {
+ handleEvent(receivedMsg);
+ if (errorsDetected) {
+ error("Error while handling debugger event");
+ error("Event received from debug target: $receivedMsg");
+ }
+ } else if (receivedMsg["id"] != null) {
+ // This is a response to the last command we sent.
+ int id = receivedMsg["id"];
+ assert(outstandingCommand != null);
+ assert(outstandingCommand.msg["id"] == id);
+ outstandingCommand.handleResponse(receivedMsg);
+ outstandingCommand = null;
+ } else {
+ error("Unexpected message from target");
+ }
+ }
+
+ // Handle data received over the wire from the debug target
+ // process. Split input from JSON wire format into individual
+ // message objects (maps).
+ void handleMessages() {
+ var msg = responses.getNextMessage();
+ while (msg != null) {
+ if (verboseWire) print("RECV: $msg");
+ if (responses.haveGarbage()) {
+ error("Error: leftover text after message: '${responses.buffer}'");
+ error("Previous message may be malformed, was: '$msg'");
+ cleanup();
+ return;
+ }
+ var msgObj = JSON.parse(msg);
+ handleMessage(msgObj);
+ if (errorsDetected) {
+ error("Error while handling message from debug target");
+ error("Message received from debug target: $msg");
+ cleanup();
+ return;
+ }
+ if (shutdownEventSeen) {
+ if (outstandingCommand != null) {
+ error("Error: outstanding command when shutdown received");
+ }
+ cleanup();
+ return;
+ }
+ if (isPaused && (outstandingCommand == null)) {
+ var cmd = queuedCommand;
+ queuedCommand = null;
+ if (cmd == null) {
+ cmd = new StepCmd(isolateId);
+ isPaused = false;
+ }
+ sendMessage(cmd.msg);
+ outstandingCommand = cmd;
+ }
+ msg = responses.getNextMessage();
+ }
+ }
+
+ // Send a debugger command to the target VM.
+ void sendMessage(Map<String,dynamic> msg) {
+ assert(msg["id"] != null);
+ msg["id"] = nextMessageId++;
+ String jsonMsg = JSON.stringify(msg);
+ if (verboseWire) print("SEND: $jsonMsg");
+ socket.write(jsonMsg);
+ }
+
+ void GetLineNumberTable(String url) {
+ assert(queuedCommand == null);
+ queuedCommand = new GetLineTableCmd(isolateId, libraryId, url);
+ }
+
+ bool get errorsDetected => errors.length > 0;
+
+ // Record error message.
+ void error(String s) {
+ errors.add(s);
+ }
+
+ void openConnection(int portNumber) {
+ Socket.connect("127.0.0.1", portNumber).then((s) {
+ socket = s;
+ var stringStream = socket.transform(new StringDecoder());
+ stringStream.listen(
+ (str) {
+ try {
+ responses.append(str);
+ handleMessages();
+ } catch(e, trace) {
+ print("Unexpected exception:\n$e\n$trace");
+ cleanup();
+ }
+ },
+ onDone: () {
+ print("Connection closed by debug target");
+ cleanup();
+ },
+ onError: (e) {
+ print("Error '$e' detected in input stream from debug target");
+ cleanup();
+ });
+ },
+ onError: (e) {
+ String msg = "Error while connecting to debugee: $e";
+ var trace = getAttachedStackTrace(e);
+ if (trace != null) msg += "\nStackTrace: $trace";
+ error(msg);
+ cleanup();
+ });
+ }
+
+ void cleanup() {
+ if (cleanupDone) return;
+ if (socket != null) {
+ socket.close().catchError((error) {
+ // Print this directly in addition to adding it to the
+ // error message queue, in case the error message queue
+ // gets printed before this error handler is called.
+ print("Error occurred while closing socket: $error");
+ error("Error while closing socket: $error");
+ });
+ }
+ var targetPid = targetProcess.pid;
+ print("Sending kill signal to process $targetPid...");
+ targetProcess.kill();
+ // If the process was already dead exitCode is already
+ // available and we call exit() in the next event loop cycle.
+ // Otherwise this will wait for the process to exit.
+
+ targetProcess.exitCode.then((exitCode) {
+ print("process $targetPid terminated with exit code $exitCode.");
+ if (errorsDetected) {
+ print("\n===== Errors detected: =====");
+ for (int i = 0; i < errors.length; i++) print(errors[i]);
+ print("============================\n");
+ }
+ Program.printCoverage();
+ exit(errors.length);
+ });
+ cleanupDone = true;
+ }
+}
+
+
+// Class to buffer wire protocol data from debug target and
+// break it down to individual json messages.
+class JsonBuffer {
+ String buffer = null;
+
+ append(String s) {
+ if (buffer == null || buffer.length == 0) {
+ buffer = s;
+ } else {
+ buffer = buffer.concat(s);
+ }
+ }
+
+ String getNextMessage() {
+ if (buffer == null) return null;
+ int msgLen = objectLength();
+ if (msgLen == 0) return null;
+ String msg = null;
+ if (msgLen == buffer.length) {
+ msg = buffer;
+ buffer = null;
+ } else {
+ assert(msgLen < buffer.length);
+ msg = buffer.substring(0, msgLen);
+ buffer = buffer.substring(msgLen);
+ }
+ return msg;
+ }
+
+ bool haveGarbage() {
+ if (buffer == null || buffer.length == 0) return false;
+ var i = 0, char = " ";
+ while (i < buffer.length) {
+ char = buffer[i];
+ if (char != " " && char != "\n" && char != "\r" && char != "\t") break;
+ i++;
+ }
+ if (i >= buffer.length) {
+ return false;
+ } else {
+ return char != "{";
+ }
+ }
+
+ // Returns the character length of the next json message in the
+ // buffer, or 0 if there is only a partial message in the buffer.
+ // The object value must start with '{' and continues to the
+ // matching '}'. No attempt is made to otherwise validate the contents
+ // as JSON. If it is invalid, a later JSON.parse() will fail.
+ int objectLength() {
+ int skipWhitespace(int index) {
+ while (index < buffer.length) {
+ String char = buffer[index];
+ if (char != " " && char != "\n" && char != "\r" && char != "\t") break;
+ index++;
+ }
+ return index;
+ }
+ int skipString(int index) {
+ assert(buffer[index - 1] == '"');
+ while (index < buffer.length) {
+ String char = buffer[index];
+ if (char == '"') return index + 1;
+ if (char == r'\') index++;
+ if (index == buffer.length) return index;
+ index++;
+ }
+ return index;
+ }
+ int index = 0;
+ index = skipWhitespace(index);
+ // Bail out if the first non-whitespace character isn't '{'.
+ if (index == buffer.length || buffer[index] != '{') return 0;
+ int nesting = 0;
+ while (index < buffer.length) {
+ String char = buffer[index++];
+ if (char == '{') {
+ nesting++;
+ } else if (char == '}') {
+ nesting--;
+ if (nesting == 0) return index;
+ } else if (char == '"') {
+ // Strings can contain braces. Skip their content.
+ index = skipString(index);
+ }
+ }
+ return 0;
+ }
+}
+
+
+void main() {
+ var options = new Options();
+ var targetOpts = [ "--debug:0" ];
+ for (String str in options.arguments) {
+ switch (str) {
+ case "--verbose":
+ showDebuggeeOutput = true;
+ break;
+ case "--wire":
+ verboseWire = true;
+ break;
+ default:
+ targetOpts.add(str);
+ break;
+ }
+ }
+
+ Process.start(options.executable, targetOpts).then((Process process) {
+ process.stdin.close();
+ var debugger = new Debugger(process);
+ });
+}
diff --git a/tools/dom/dom.json b/tools/dom/dom.json
index c01a78f..f773ca9 100644
--- a/tools/dom/dom.json
+++ b/tools/dom/dom.json
@@ -883,6 +883,7 @@
},
"CustomElementConstructor": {
"comment": "https://dvcs.w3.org/hg/webcomponents/raw-file/tip/spec/custom/index.html#dfn-custom-element-constructor-generation",
+ "dart_action": "suppress",
"members": {},
"support_level": "experimental"
},
@@ -2354,6 +2355,7 @@
"comment": "http://www.w3.org/TR/touch-events/, http://www.chromestatus.com/features",
"support_level": "experimental"
},
+ "ontransitionend": {},
"onwebkitTransitionEnd": {
"support_level": "deprecated"
},
diff --git a/tools/dom/scripts/dartmetadata.py b/tools/dom/scripts/dartmetadata.py
index 9daed68..3cbd995 100644
--- a/tools/dom/scripts/dartmetadata.py
+++ b/tools/dom/scripts/dartmetadata.py
@@ -279,7 +279,7 @@
'DOMWindow.webkitNotifications': _webkit_experimental_annotations,
'DOMWindow.webkitRequestFileSystem': _file_system_annotations,
'DOMWindow.webkitResolveLocalFileSystemURL': _file_system_annotations,
- 'Element.onwebkitTransitionEnd': _all_but_ie9_annotations,
+ 'Element.ontransitionend': _all_but_ie9_annotations,
# Placeholder to add experimental flag, implementation for this is
# pending in a separate CL.
'Element.webkitMatchesSelector': ['@Experimental()'],
diff --git a/tools/dom/scripts/htmleventgenerator.py b/tools/dom/scripts/htmleventgenerator.py
index 3ed4393..c2ead7c 100644
--- a/tools/dom/scripts/htmleventgenerator.py
+++ b/tools/dom/scripts/htmleventgenerator.py
@@ -15,7 +15,7 @@
# onEventName methods in the IDL but some events aren't listed so we need
# to manually add them here so that they are easy for users to find.
_html_manual_events = monitored.Dict('htmleventgenerator._html_manual_events', {
- 'Element': ['touchleave', 'touchenter', 'webkitTransitionEnd'],
+ 'Element': ['touchleave', 'touchenter', 'transitionend'],
'Window': ['DOMContentLoaded']
})
@@ -28,7 +28,6 @@
'webkitanimationiteration': 'webkitAnimationIteration',
'webkitanimationstart': 'webkitAnimationStart',
'webkitspeechchange': 'webkitSpeechChange',
- 'webkittransitionend': 'webkitTransitionEnd',
})
_html_event_types = monitored.Dict('htmleventgenerator._html_event_types', {
@@ -108,7 +107,7 @@
'*.webkitAnimationEnd': ('animationEnd', 'AnimationEvent'),
'*.webkitAnimationIteration': ('animationIteration', 'AnimationEvent'),
'*.webkitAnimationStart': ('animationStart', 'AnimationEvent'),
- '*.webkitTransitionEnd': ('transitionEnd', 'TransitionEvent'),
+ '*.transitionend': ('transitionEnd', 'TransitionEvent'),
'*.webkitfullscreenchange': ('fullscreenChange', 'Event'),
'*.webkitfullscreenerror': ('fullscreenError', 'Event'),
'AbstractWorker.error': ('error', 'ErrorEvent'),
@@ -118,7 +117,7 @@
'DOMApplicationCache.downloading': ('downloading', 'Event'),
'DOMApplicationCache.noupdate': ('noUpdate', 'Event'),
'DOMApplicationCache.obsolete': ('obsolete', 'Event'),
- 'DOMApplicationCache.progress': ('progress', 'Event'),
+ 'DOMApplicationCache.progress': ('progress', 'ProgressEvent'),
'DOMApplicationCache.updateready': ('updateReady', 'Event'),
'Document.readystatechange': ('readyStateChange', 'Event'),
'Document.securitypolicyviolation': ('securityPolicyViolation', 'SecurityPolicyViolationEvent'),
diff --git a/tools/dom/scripts/htmlrenamer.py b/tools/dom/scripts/htmlrenamer.py
index 7262ee1..b3d7354 100644
--- a/tools/dom/scripts/htmlrenamer.py
+++ b/tools/dom/scripts/htmlrenamer.py
@@ -23,6 +23,7 @@
html_interface_renames = monitored.Dict('htmlrenamer.html_interface_renames',
dict({
+ 'Attr': '_Attr',
'CDATASection': 'CDataSection',
'Clipboard': 'DataTransfer',
'Database': 'SqlDatabase', # Avoid conflict with Index DB's Database.
@@ -270,6 +271,7 @@
'Node.childNodes',
'Node.firstChild',
'Node.lastChild',
+ 'Node.localName',
'Node.namespaceURI',
'Node.removeChild',
'Node.replaceChild',
@@ -363,7 +365,6 @@
# to be suppressed but not the setter, etc.
# TODO(jacobr): cleanup and augment this list.
_removed_html_members = monitored.Set('htmlrenamer._removed_html_members', [
- 'Attr.*',
'AudioBufferSourceNode.looping', # TODO(vsm): Use deprecated IDL annotation
'CSSStyleDeclaration.getPropertyCSSValue',
'CanvasRenderingContext2D.clearShadow',
diff --git a/tools/dom/src/AttributeMap.dart b/tools/dom/src/AttributeMap.dart
index b0cb0cc..76a9064 100644
--- a/tools/dom/src/AttributeMap.dart
+++ b/tools/dom/src/AttributeMap.dart
@@ -44,7 +44,7 @@
var keys = new List<String>();
for (int i = 0, len = attributes.length; i < len; i++) {
if (_matches(attributes[i])) {
- keys.add(attributes[i].localName);
+ keys.add(attributes[i].name);
}
}
return keys;
diff --git a/tools/dom/src/KeyboardEventStream.dart b/tools/dom/src/KeyboardEventStream.dart
index 6f08c70..2e838d1 100644
--- a/tools/dom/src/KeyboardEventStream.dart
+++ b/tools/dom/src/KeyboardEventStream.dart
@@ -28,7 +28,7 @@
static final int _ROMAN_ALPHABET_OFFSET = "a".codeUnits[0] - "A".codeUnits[0];
/** Controller to produce KeyEvents for the stream. */
- final StreamController _controller = new StreamController();
+ final StreamController _controller = new StreamController(sync: true);
static const _EVENT_TYPE = 'KeyEvent';
@@ -97,7 +97,7 @@
* Hook up all event listeners under the covers so we can estimate keycodes
* and charcodes when they are not provided.
*/
- _KeyboardEventHandler.initializeAllEventListeners(this._type, this._target) :
+ _KeyboardEventHandler.initializeAllEventListeners(this._type, this._target) :
super(_EVENT_TYPE) {
Element.keyDownEvent.forTarget(_target, useCapture: true).listen(
processKeyDown);
diff --git a/tools/dom/src/PathObserver.dart b/tools/dom/src/PathObserver.dart
index b0eda5f..bc07ac1 100644
--- a/tools/dom/src/PathObserver.dart
+++ b/tools/dom/src/PathObserver.dart
@@ -72,7 +72,8 @@
// TODO(jmesserly): if the path is empty, or the object is! Observable, we
// can optimize the PathObserver to be more lightweight.
- _values = new StreamController.broadcast(onListen: _observe,
+ _values = new StreamController.broadcast(sync: true,
+ onListen: _observe,
onCancel: _unobserve);
if (_isValid) {
diff --git a/tools/dom/src/TemplateBindings.dart b/tools/dom/src/TemplateBindings.dart
index 81cebd3..5f379da 100644
--- a/tools/dom/src/TemplateBindings.dart
+++ b/tools/dom/src/TemplateBindings.dart
@@ -611,11 +611,12 @@
static void _removeChild(Node parent, Node child) {
child._templateInstance = null;
if (child is Element && (child as Element).isTemplate) {
+ Element childElement = child;
// Make sure we stop observing when we remove an element.
- var templateIterator = child._templateIterator;
+ var templateIterator = childElement._templateIterator;
if (templateIterator != null) {
templateIterator.abandon();
- child._templateIterator = null;
+ childElement._templateIterator = null;
}
}
child.remove();
diff --git a/tools/dom/templates/html/impl/impl_Element.darttemplate b/tools/dom/templates/html/impl/impl_Element.darttemplate
index 188759e..7b8a594 100644
--- a/tools/dom/templates/html/impl/impl_Element.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Element.darttemplate
@@ -58,6 +58,24 @@
throw new UnsupportedError('Cannot sort element lists');
}
+ void removeWhere(bool test(Element element)) {
+ _filter(test, false);
+ }
+
+ void retainWhere(bool test(Element element)) {
+ _filter(test, true);
+ }
+
+ void _filter(bool test(var element), bool retainMatching) {
+ var removed;
+ if (retainMatching) {
+ removed = _element.children.where((e) => !test(e));
+ } else {
+ removed = _element.children.where(test);
+ }
+ for (var e in removed) e.remove();
+ }
+
void setRange(int start, int end, Iterable<Element> iterable,
[int skipCount = 0]) {
throw new UnimplementedError();
@@ -450,6 +468,16 @@
_xtag = value;
}
+ @DomName('Element.localName')
+ @DocsEditable
+ String get localName => $dom_localName;
+
+ @DomName('Element.namespaceUri')
+ @DocsEditable
+ String get namespaceUri => $dom_namespaceUri;
+
+ String toString() => localName;
+
/**
* Scrolls this element into view.
*
@@ -507,7 +535,7 @@
}
}
- @DomName('Element.webkitTransitionEndEvent')
+ @DomName('Element.transitionEndEvent')
static const EventStreamProvider<TransitionEvent> transitionEndEvent =
const _CustomEventStreamProvider<TransitionEvent>(
Element._determineTransitionEventType);
diff --git a/tools/dom/templates/html/impl/impl_Geolocation.darttemplate b/tools/dom/templates/html/impl/impl_Geolocation.darttemplate
index c4fec21..5049d4b 100644
--- a/tools/dom/templates/html/impl/impl_Geolocation.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Geolocation.darttemplate
@@ -53,7 +53,7 @@
int watchId;
var controller;
- controller = new StreamController<Geoposition>(
+ controller = new StreamController<Geoposition>(sync: true,
onListen: () {
assert(watchId == null);
watchId = $dom_watchPosition(
diff --git a/tools/dom/templates/html/impl/impl_HTMLTemplateElement.darttemplate b/tools/dom/templates/html/impl/impl_HTMLTemplateElement.darttemplate
index 42f8d38..3ee3646 100644
--- a/tools/dom/templates/html/impl/impl_HTMLTemplateElement.darttemplate
+++ b/tools/dom/templates/html/impl/impl_HTMLTemplateElement.darttemplate
@@ -29,7 +29,7 @@
@Experimental
static Stream<DocumentFragment> get instanceCreated {
if (_instanceCreated == null) {
- _instanceCreated = new StreamController<DocumentFragment>();
+ _instanceCreated = new StreamController<DocumentFragment>(sync: true);
}
return _instanceCreated.stream;
}
diff --git a/tools/dom/templates/html/impl/impl_IDBObjectStore.darttemplate b/tools/dom/templates/html/impl/impl_IDBObjectStore.darttemplate
index 4251ff5..3d9aa48 100644
--- a/tools/dom/templates/html/impl/impl_IDBObjectStore.darttemplate
+++ b/tools/dom/templates/html/impl/impl_IDBObjectStore.darttemplate
@@ -147,7 +147,7 @@
// TODO: need to guarantee that the controller provides the values
// immediately as waiting until the next tick will cause the transaction to
// close.
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
request.onError.listen((e) {
//TODO: Report stacktrace once issue 4061 is resolved.
diff --git a/tools/dom/templates/html/impl/impl_Node.darttemplate b/tools/dom/templates/html/impl/impl_Node.darttemplate
index 287151f..02edf51 100644
--- a/tools/dom/templates/html/impl/impl_Node.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Node.darttemplate
@@ -230,14 +230,15 @@
*/
Node insertAllBefore(Iterable<Node> newNodes, Node refChild) {
if (newNodes is _ChildNodeListLazy) {
- if (identical(newNodes._this, this)) {
+ _ChildNodeListLazy otherList = newNodes;
+ if (identical(otherList._this, this)) {
throw new ArgumentError(newNodes);
}
// Optimized route for copying between nodes.
- for (var i = 0, len = newNodes.length; i < len; ++i) {
+ for (var i = 0, len = otherList.length; i < len; ++i) {
// Should use $dom_firstChild, Bug 8886.
- this.insertBefore(newNodes[0], refChild);
+ this.insertBefore(otherList[0], refChild);
}
} else {
for (var node in newNodes) {
@@ -249,8 +250,7 @@
/**
* Print out a String representation of this Node.
*/
- String toString() => localName == null ?
- (nodeValue == null ? super.toString() : nodeValue) : localName;
+ String toString() => nodeValue == null ? super.toString() : nodeValue;
/**
* Binds the attribute [name] to the [path] of the [model].
diff --git a/tools/dom/templates/html/impl/impl_ScriptProcessorNode.darttemplate b/tools/dom/templates/html/impl/impl_ScriptProcessorNode.darttemplate
index d6f813f..2c9a2eb 100644
--- a/tools/dom/templates/html/impl/impl_ScriptProcessorNode.darttemplate
+++ b/tools/dom/templates/html/impl/impl_ScriptProcessorNode.darttemplate
@@ -16,8 +16,8 @@
*/
Stream<AudioProcessingEvent> get onAudioProcess {
if (_eventStream == null) {
- var controller = new StreamController();
- var callback = (audioData) {
+ var controller = new StreamController(sync: true);
+ var callback = (audioData) {
if (controller.hasListener) {
// This stream is a strange combination of broadcast and single
// subscriber streams. We only allow one listener, but if there is
diff --git a/tools/dom/templates/html/impl/impl_WheelEvent.darttemplate b/tools/dom/templates/html/impl/impl_WheelEvent.darttemplate
index dcad713..dce1f69 100644
--- a/tools/dom/templates/html/impl/impl_WheelEvent.darttemplate
+++ b/tools/dom/templates/html/impl/impl_WheelEvent.darttemplate
@@ -50,7 +50,7 @@
var axis = 0;
var detail = 0;
if (deltaX != 0 && deltaY != 0) {
- throw UnsupportedError(
+ throw new UnsupportedError(
'Cannot modify deltaX and deltaY simultaneously');
}
if (deltaY != 0) {
diff --git a/tools/dom/templates/html/impl/impl_Window.darttemplate b/tools/dom/templates/html/impl/impl_Window.darttemplate
index 9c8f8ce..cce9a48 100644
--- a/tools/dom/templates/html/impl/impl_Window.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Window.darttemplate
@@ -315,7 +315,7 @@
const _BeforeUnloadEventStreamProvider(this._eventType);
Stream<BeforeUnloadEvent> forTarget(EventTarget e, {bool useCapture: false}) {
- var controller = new StreamController();
+ var controller = new StreamController(sync: true);
var stream = new _EventStream(e, _eventType, useCapture);
stream.listen((event) {
var wrapped = new _BeforeUnloadEvent(event);
diff --git a/tools/test.dart b/tools/test.dart
index 781ae2c..b1c587a 100755
--- a/tools/test.dart
+++ b/tools/test.dart
@@ -167,16 +167,9 @@
if (key == 'co19') {
testSuites.add(new Co19TestSuite(conf));
} else if (conf['runtime'] == 'vm' && key == 'vm') {
- // TODO(kustermann): Currently we don't support running VM unittest
- // tests (i.e. run_vm_tests) on ARM because:
- // a) we currently use record&replay [test.dart cannot be used on ARM]
- // b) we cannot easily determine all the VM test names
- // [we would need to run 'run_vm_tests --list' on ARM]
- if (!['arm', 'mips'].contains(conf['arch'])) {
- // vm tests contain both cc tests (added here) and dart tests (added
- // in [TEST_SUITE_DIRECTORIES]).
- testSuites.add(new VMTestSuite(conf));
- }
+ // vm tests contain both cc tests (added here) and dart tests (added
+ // in [TEST_SUITE_DIRECTORIES]).
+ testSuites.add(new VMTestSuite(conf));
} else if (conf['analyzer']) {
if (key == 'dartc' && conf['compiler'] == 'dartc') {
testSuites.add(new JUnitDartcTestSuite(conf));
diff --git a/tools/testing/dart/browser_controller.dart b/tools/testing/dart/browser_controller.dart
index 9b5e966..8570f35 100644
--- a/tools/testing/dart/browser_controller.dart
+++ b/tools/testing/dart/browser_controller.dart
@@ -53,6 +53,31 @@
// We use this to gracefully handle double calls to close.
bool underTermination = false;
+ Browser();
+
+ factory Browser.byName(String name) {
+ if (name == 'ff' || name == 'firefox') {
+ return new Firefox();
+ } else if (name == 'chrome') {
+ return new Chrome();
+ } else if (name == 'safari') {
+ return new Safari();
+ } else {
+ throw "Non supported browser";
+ }
+ }
+
+ static const List<String> SUPPORTED_BROWSERS =
+ const ['safari', 'ff', 'firefox', 'chrome'];
+
+ static const List<String> BROWSERS_WITH_WINDOW_SUPPORT =
+ const ['safari', 'ff', 'firefox', 'chrome'];
+
+ // TODO(kustermann): add standard support for chrome on android
+ static bool supportedBrowser(String name) {
+ return SUPPORTED_BROWSERS.contains(name);
+ }
+
void _logEvent(String event) {
String toLog = "$this ($id) - ${new DateTime.now()}: $event \n";
if (debugPrint) print("usageLog: $toLog");
@@ -510,7 +535,11 @@
BrowserTestRunner(this.local_ip, this.browserName, this.maxNumBrowsers);
Future<bool> start() {
- testingServer = new BrowserTestingServer(local_ip);
+ // If [browserName] doesn't support opening new windows, we use new iframes
+ // instead.
+ bool useIframe =
+ !Browser.BROWSERS_WITH_WINDOW_SUPPORT.contains(browserName);
+ testingServer = new BrowserTestingServer(local_ip, useIframe);
return testingServer.start().then((_) {
testingServer.testDoneCallBack = handleResults;
testingServer.nextTestCallBack = getNextTest;
@@ -709,16 +738,7 @@
}
Browser getInstance() {
- var browser;
- if (browserName == "chrome") {
- browser = new Chrome();
- } else if (browserName == "ff") {
- browser = new Firefox();
- } else if (browserName == "safari") {
- browser = new Safari();
- } else {
- throw "Non supported browser for browser controller";
- }
+ var browser = new Browser.byName(browserName);
browser.logger = logger;
return browser;
}
@@ -748,11 +768,12 @@
var testCount = 0;
var httpServer;
bool underTermination = false;
+ bool useIframe = false;
Function testDoneCallBack;
Function nextTestCallBack;
- BrowserTestingServer(this.local_ip);
+ BrowserTestingServer(this.local_ip, this.useIframe);
Future start() {
return HttpServer.bind(local_ip, 0).then((createdServer) {
@@ -837,98 +858,109 @@
<head>
<title>Driving page</title>
<script type='text/javascript'>
- var number_of_tests = 0;
- var current_id;
- var last_reported_id;
- var testing_window;
- // We use this to determine if we did actually get back a start event
- // from the test we just loaded.
- var did_start = false;
- function newTaskHandler() {
- if (this.readyState == this.DONE) {
- if (this.status == 200) {
- if (this.responseText == '$waitSignal') {
- setTimeout(getNextTask, 500);
- } else if (this.responseText == '$terminateSignal') {
- // Don't do anything, we will be killed shortly.
- } else {
- // TODO(ricow): Do something more clever here.
- if (nextTask != undefined) alert('This is really bad');
- // The task is send to us as:
- // URL#ID
- var split = this.responseText.split('#');
- var nextTask = split[0];
- current_id = split[1];
- did_start = false;
- run(nextTask);
- }
- } else {
- // We are basically in trouble - do something clever.
- }
- }
- }
+ function startTesting() {
+ var number_of_tests = 0;
+ var current_id;
+ var last_reported_id;
+ var testing_window;
+ // We use this to determine if we did actually get back a start event
+ // from the test we just loaded.
+ var did_start = false;
- function getNextTask() {
- var client = new XMLHttpRequest();
- client.onreadystatechange = newTaskHandler;
- client.open('GET', '$nextTestPath/$browserId');
- client.send();
- }
+ var embedded_iframe = document.getElementById('embedded_iframe');
+ var use_iframe = ${useIframe};
- function run(url) {
- number_of_tests++;
- document.getElementById('number').innerHTML = number_of_tests;
- if (testing_window == undefined) {
- testing_window = window.open(url);
- } else {
- testing_window.location = url;
- }
- }
-
- function reportMessage(msg) {
- if (msg == 'STARTING') {
- did_start = true;
- return;
- }
- var client = new XMLHttpRequest();
- function handleReady() {
+ function newTaskHandler() {
if (this.readyState == this.DONE) {
- if (last_reported_id != current_id && did_start) {
- getNextTask();
- last_reported_id = current_id;
+ if (this.status == 200) {
+ if (this.responseText == '$waitSignal') {
+ setTimeout(getNextTask, 500);
+ } else if (this.responseText == '$terminateSignal') {
+ // Don't do anything, we will be killed shortly.
+ } else {
+ // TODO(ricow): Do something more clever here.
+ if (nextTask != undefined) alert('This is really bad');
+ // The task is send to us as:
+ // URL#ID
+ var split = this.responseText.split('#');
+ var nextTask = split[0];
+ current_id = split[1];
+ did_start = false;
+ run(nextTask);
+ }
+ } else {
+ // We are basically in trouble - do something clever.
}
}
}
- client.onreadystatechange = handleReady;
- // If did_start is false it means that we did actually set the url on
- // the testing_window, but this is a report left in the event loop or
- // a callback because the page did not load yet.
- // In both cases this is a double report from the last test.
- var posting_id = did_start ? current_id : last_reported_id;
- client.open('POST', '$reportPath/${browserId}?id=' + posting_id);
- client.setRequestHeader('Content-type',
- 'application/x-www-form-urlencoded');
- client.send(msg);
- // TODO(ricow) add error handling to somehow report the fact that
- // we could not send back a result.
+
+ function getNextTask() {
+ var client = new XMLHttpRequest();
+ client.onreadystatechange = newTaskHandler;
+ client.open('GET', '$nextTestPath/$browserId');
+ client.send();
+ }
+
+ function run(url) {
+ number_of_tests++;
+ document.getElementById('number').innerHTML = number_of_tests;
+ if (use_iframe) {
+ embedded_iframe.src = url;
+ } else {
+ if (testing_window == undefined) {
+ testing_window = window.open(url);
+ } else {
+ testing_window.location = url;
+ }
+ }
+ }
+
+ function reportMessage(msg) {
+ if (msg == 'STARTING') {
+ did_start = true;
+ return;
+ }
+ var client = new XMLHttpRequest();
+ function handleReady() {
+ if (this.readyState == this.DONE) {
+ if (last_reported_id != current_id && did_start) {
+ getNextTask();
+ last_reported_id = current_id;
+ }
+ }
+ }
+ client.onreadystatechange = handleReady;
+ // If did_start is false it means that we did actually set the url on
+ // the testing_window, but this is a report left in the event loop or
+ // a callback because the page did not load yet.
+ // In both cases this is a double report from the last test.
+ var posting_id = did_start ? current_id : last_reported_id;
+ client.open('POST', '$reportPath/${browserId}?id=' + posting_id);
+ client.setRequestHeader('Content-type',
+ 'application/x-www-form-urlencoded');
+ client.send(msg);
+ // TODO(ricow) add error handling to somehow report the fact that
+ // we could not send back a result.
+ }
+
+ function messageHandler(e) {
+ var msg = e.data;
+ if (typeof msg != 'string') return;
+ reportMessage(msg);
+ }
+
+ window.addEventListener('message', messageHandler, false);
+ waitForDone = false;
+
+ getNextTask();
}
- function messageHandler(e) {
- var msg = e.data;
- if (typeof msg != 'string') return;
- reportMessage(msg);
- }
-
- window.addEventListener('message', messageHandler, false);
- waitForDone = false;
-
- getNextTask();
-
</script>
</head>
- <body>
+ <body onload="startTesting()">
Dart test driver, number of tests: <div id="number"></div>
+ <iframe id="embedded_iframe"></iframe>
</body>
</html>
""";
diff --git a/tools/testing/dart/launch_browser.dart b/tools/testing/dart/launch_browser.dart
new file mode 100644
index 0000000..3637906
--- /dev/null
+++ b/tools/testing/dart/launch_browser.dart
@@ -0,0 +1,39 @@
+// 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.
+
+/**
+ * Simple command line interface to launching browsers.
+ * Uses the browser_controller framework.
+ * The usage is:
+ * DARTBIN launch_browser.dart BROWSER_NAME URL
+ * DARTBIN should be the checked in stable binary.
+ */
+
+import "dart:io";
+import "browser_controller.dart";
+
+void printHelp() {
+ print("Usage pattern:");
+ print("launch_browser.dart browser url");
+ print("Supported browsers: ${Browser.SUPPORTED_BROWSERS}");
+}
+
+void main() {
+ var args = new Options().arguments;
+ if (args.length != 2) {
+ print("Wrong number of arguments, please pass in exactly two arguments");
+ printHelp();
+ return;
+ }
+
+ if (!Browser.supportedBrowser(args[0])) {
+ print("Specified browser not supported");
+ printHelp();
+ return;
+ }
+
+ var browser = new Browser.byName(args[0]);
+ browser.start(args[1]);
+
+}
diff --git a/tools/testing/dart/test_progress.dart b/tools/testing/dart/test_progress.dart
index b9ce10b..f105505 100644
--- a/tools/testing/dart/test_progress.dart
+++ b/tools/testing/dart/test_progress.dart
@@ -90,40 +90,46 @@
}
}
}
- if (!test.lastCommandOutput.diagnostics.isEmpty) {
- String prefix = 'diagnostics:';
- for (var s in test.lastCommandOutput.diagnostics) {
- output.add('$prefix ${s}');
- prefix = ' ';
+ for (var i = 0; i < test.commands.length; i++) {
+ var command = test.commands[i];
+ var commandOutput = test.commandOutputs[command];
+ if (commandOutput != null) {
+ output.add("CommandOutput[$i]:");
+ if (!commandOutput.diagnostics.isEmpty) {
+ String prefix = 'diagnostics:';
+ for (var s in commandOutput.diagnostics) {
+ output.add('$prefix ${s}');
+ prefix = ' ';
+ }
+ }
+ if (!commandOutput.stdout.isEmpty) {
+ output.add('');
+ output.add('stdout:');
+ if (command.isPixelTest) {
+ output.add('DRT pixel test failed! stdout is not printed because it '
+ 'contains binary data!');
+ } else {
+ output.addAll(getLinesWithoutCarriageReturn(commandOutput.stdout));
+ }
+ }
+ if (!commandOutput.stderr.isEmpty) {
+ output.add('');
+ output.add('stderr:');
+ output.addAll(getLinesWithoutCarriageReturn(commandOutput.stderr));
+ }
}
}
- if (!test.lastCommandOutput.stdout.isEmpty) {
- output.add('');
- output.add('stdout:');
- if (test.lastCommandOutput.command.isPixelTest) {
- output.add('DRT pixel test failed! stdout is not printed because it '
- 'contains binary data!');
- } else {
- output.addAll(
- getLinesWithoutCarriageReturn(test.lastCommandOutput.stdout));
- }
- }
- if (!test.lastCommandOutput.stderr.isEmpty) {
- output.add('');
- output.add('stderr:');
- output.addAll(getLinesWithoutCarriageReturn(test.lastCommandOutput.stderr));
- }
if (test is BrowserTestCase) {
// Additional command for rerunning the steps locally after the fact.
var command =
test.configuration["_servers_"].httpServerCommandline();
+ output.add('');
output.add('To retest, run: $command');
}
- for (Command c in test.commands) {
+ for (var i = 0; i < test.commands.length; i++) {
+ var command = test.commands[i];
output.add('');
- String message = (c == test.commands.last
- ? "Command line" : "Compilation command");
- output.add('$message: $c');
+ output.add('Command[$i]: $command');
}
return output;
}
diff --git a/tools/testing/dart/test_runner.dart b/tools/testing/dart/test_runner.dart
index 9169a83..0b3b454 100644
--- a/tools/testing/dart/test_runner.dart
+++ b/tools/testing/dart/test_runner.dart
@@ -117,7 +117,7 @@
}
var quotedArguments = [];
arguments.forEach((argument) => quotedArguments.add('"$argument"'));
- commandLine = "$executable ${quotedArguments.join(' ')}";
+ commandLine = "\"$executable\" ${quotedArguments.join(' ')}";
}
String toString() => commandLine;
@@ -1649,7 +1649,7 @@
Future<BrowserTestRunner> _getBrowserTestRunner(TestCase test) {
var local_ip = test.configuration['local_ip'];
var runtime = test.configuration['runtime'];
- var num_browsers = 1;//test.configuration['tasks'];
+ var num_browsers = test.configuration['tasks'];
if (_browserTestRunners[runtime] == null) {
var testRunner =
new BrowserTestRunner(local_ip, runtime, num_browsers);
diff --git a/tools/testing/dart/test_suite.dart b/tools/testing/dart/test_suite.dart
index 2a6fa18..843bb8c 100644
--- a/tools/testing/dart/test_suite.dart
+++ b/tools/testing/dart/test_suite.dart
@@ -304,7 +304,8 @@
*/
class CCTestSuite extends TestSuite {
final String testPrefix;
- String runnerPath;
+ String targetRunnerPath;
+ String hostRunnerPath;
final String dartDir;
List<String> statusFilePaths;
TestCaseEvent doTest;
@@ -319,7 +320,18 @@
{this.testPrefix: ''})
: super(configuration, suiteName),
dartDir = TestUtils.dartDir().toNativePath() {
- runnerPath = '$buildDir/$runnerName';
+ // For running the tests we use the given '$runnerName' binary
+ targetRunnerPath = '$buildDir/$runnerName';
+
+ // For listing the tests we use the '$runnerName.host' binary if it exists
+ // and use '$runnerName' if it doesn't.
+ var binarySuffix = Platform.operatingSystem == 'windows' ? '.exe' : '';
+ var hostBinary = '$targetRunnerPath.host$binarySuffix';
+ if (new File(hostBinary).existsSync()) {
+ hostRunnerPath = hostBinary;
+ } else {
+ hostRunnerPath = targetRunnerPath;
+ }
}
void testNameHandler(String testName, ignore) {
@@ -347,7 +359,7 @@
args.add(testName);
doTest(new TestCase(constructedName,
- [new Command(runnerPath, args)],
+ [new Command(targetRunnerPath, args)],
configuration,
completeHandler,
expectations));
@@ -364,7 +376,7 @@
if (filesRead == statusFilePaths.length) {
receiveTestName = new ReceivePort();
var port = spawnFunction(ccTestLister);
- port.send(runnerPath, receiveTestName.toSendPort());
+ port.send(hostRunnerPath, receiveTestName.toSendPort());
receiveTestName.receive(testNameHandler);
}
}
@@ -1181,8 +1193,9 @@
return configuration['drt'];
}
if (Platform.operatingSystem == 'macos') {
- return dartDir.append('/client/tests/drt/Content Shell.app/Contents/'
- 'MacOS/Content Shell').toNativePath();
+ final path = dartDir.append(
+ '/client/tests/drt/Content Shell.app/Contents/MacOS/Content Shell');
+ return path.toNativePath();
}
return dartDir.append('client/tests/drt/content_shell').toNativePath();
}
diff --git a/utils/compiler/create_snapshot.dart b/utils/compiler/create_snapshot.dart
index f1bc9db..c5a8af4 100644
--- a/utils/compiler/create_snapshot.dart
+++ b/utils/compiler/create_snapshot.dart
@@ -82,10 +82,9 @@
if (!args.containsKey("dart2js_main")) throw "Please specify dart2js_main";
if (!args.containsKey("output_dir")) throw "Please specify output_dir";
- var scriptFile = new File(options.script);
- var path = new Path(scriptFile.directorySync().path);
+ var scriptFile = new File(new File(options.script).fullPathSync());
+ var path = new Path(scriptFile.directory.path);
var rootPath = path.directoryPath.directoryPath;
-
getSnapshotGenerationFile(options, args, rootPath).then((result) {
var wrapper = "${args['output_dir']}/utils_wrapper.dart";
writeSnapshotFile(wrapper, result);
diff --git a/utils/tests/css/css.status b/utils/tests/css/css.status
index e857409..6b7ba1c 100644
--- a/utils/tests/css/css.status
+++ b/utils/tests/css/css.status
@@ -8,8 +8,14 @@
[ $arch == x64 ]
*: Skip
+[ $arch == arm ]
+*: Skip
+
[ $arch == simarm ]
*: Skip
-[ $arch == arm ]
+[ $arch == mips ]
+*: Skip
+
+[ $arch == simmips ]
*: Skip
diff --git a/utils/tests/peg/peg.status b/utils/tests/peg/peg.status
index d933e20..ba6061c 100644
--- a/utils/tests/peg/peg.status
+++ b/utils/tests/peg/peg.status
@@ -8,8 +8,14 @@
[ $arch == x64 ]
*: Skip
+[ $arch == arm ]
+*: Skip
+
[ $arch == simarm ]
*: Skip
-[ $arch == arm ]
+[ $arch == mips ]
+*: Skip
+
+[ $arch == simmips ]
*: Skip