Version 0.3.5.0 .
svn merge -r 18113:18264 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
git-svn-id: http://dart.googlecode.com/svn/trunk@18267 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/compiler/java/com/google/dart/compiler/SystemLibraryManager.java b/compiler/java/com/google/dart/compiler/SystemLibraryManager.java
index 63626bc..a86558e 100644
--- a/compiler/java/com/google/dart/compiler/SystemLibraryManager.java
+++ b/compiler/java/com/google/dart/compiler/SystemLibraryManager.java
@@ -138,7 +138,10 @@
HashSet<String> explicitShortNames = new HashSet<String>();
for (Entry<String, DartLibrary> entry : declaredLibraries.entrySet()) {
- if (entry.getValue().getCategory().equals("Internal")){
+ if (entry.getValue().getCategory().equals("Internal")
+ // TODO(8365): the following line allows dart:_collection-dev to
+ // be imported even though it's a hidden library.
+ && !entry.getKey().equals("dart:_collection-dev")) {
continue;
}
String shortName = entry.getKey().trim();
diff --git a/compiler/javatests/com/google/dart/compiler/DartCompilerListenerTest.java b/compiler/javatests/com/google/dart/compiler/DartCompilerListenerTest.java
index ec97e7a..c6fbf39 100644
--- a/compiler/javatests/com/google/dart/compiler/DartCompilerListenerTest.java
+++ b/compiler/javatests/com/google/dart/compiler/DartCompilerListenerTest.java
@@ -4,6 +4,8 @@
package com.google.dart.compiler;
+import com.google.dart.compiler.resolver.TypeErrorCode;
+
/**
* Testing implementation of {@link DartCompilerListener}.
*/
@@ -49,6 +51,11 @@
@Override
public void onError(DartCompilationError event) {
+ // ignore deprecated
+ if (event.getErrorCode() == TypeErrorCode.DEPRECATED_ELEMENT) {
+ return;
+ }
+ // validate
String reportedSrcName = (event.getSource() != null)
? event.getSource().getName()
: null;
diff --git a/pkg/analyzer-experimental/README b/pkg/analyzer-experimental/README.md
similarity index 100%
rename from pkg/analyzer-experimental/README
rename to pkg/analyzer-experimental/README.md
diff --git a/pkg/http/lib/src/multipart_request.dart b/pkg/http/lib/src/multipart_request.dart
index 9bb1c46..b311b8e 100644
--- a/pkg/http/lib/src/multipart_request.dart
+++ b/pkg/http/lib/src/multipart_request.dart
@@ -73,7 +73,7 @@
///
/// This doesn't need to be closed. When the request is sent, whichever files
/// are written to this sink at that point will be used.
- Sink<MultipartFile> get files => _files;
+ StreamSink<MultipartFile> get files => _files;
/// The private version of [files], typed so that the underlying collection is
/// accessible.
diff --git a/pkg/http/lib/src/streamed_request.dart b/pkg/http/lib/src/streamed_request.dart
index a87d27b..b313f68 100644
--- a/pkg/http/lib/src/streamed_request.dart
+++ b/pkg/http/lib/src/streamed_request.dart
@@ -24,7 +24,7 @@
/// buffered.
///
/// Closing this signals the end of the request.
- Sink<List<int>> get sink => _controller.sink;
+ StreamSink<List<int>> get sink => _controller.sink;
/// The controller for [sink], from which [BaseRequest] will read data for
/// [finalize].
diff --git a/pkg/unittest/coverage_controller.js b/pkg/unittest/lib/coverage_controller.js
similarity index 100%
rename from pkg/unittest/coverage_controller.js
rename to pkg/unittest/lib/coverage_controller.js
diff --git a/pkg/unittest/lib/src/basematcher.dart b/pkg/unittest/lib/src/basematcher.dart
index 2859336..a74928c 100644
--- a/pkg/unittest/lib/src/basematcher.dart
+++ b/pkg/unittest/lib/src/basematcher.dart
@@ -23,10 +23,9 @@
/**
* BaseMatcher is the base class for all matchers. To implement a new
- * matcher, either add a class that implements from IMatcher or
- * a class that inherits from Matcher. Inheriting from Matcher has
- * the benefit that a default implementation of describeMismatch will
- * be provided.
+ * matcher, either add a class that implements Matcher or a class that
+ * extends BaseMatcher. Extending BaseMatcher has the benefit that a
+ * default implementation of describeMismatch will be provided.
*/
abstract class BaseMatcher implements Matcher {
const BaseMatcher();
diff --git a/pkg/unittest/lib/src/core_matchers.dart b/pkg/unittest/lib/src/core_matchers.dart
index 489fecd..449990b 100644
--- a/pkg/unittest/lib/src/core_matchers.dart
+++ b/pkg/unittest/lib/src/core_matchers.dart
@@ -632,14 +632,16 @@
/**
* Returns a matcher that uses an arbitrary function that returns
- * true or false for the actual value.
+ * true or false for the actual value. For example:
+ *
+ * expect(v, predicate((x) => ((x % 2) == 0), "is even"))
*/
-Matcher predicate(f, [description ='satisfies function']) =>
+Matcher predicate(Function f, [description ='satisfies function']) =>
new _Predicate(f, description);
class _Predicate extends BaseMatcher {
- final _matcher;
+ final Function _matcher;
final String _description;
const _Predicate(this._matcher, this._description);
diff --git a/pkg/unittest/test_controller.js b/pkg/unittest/lib/test_controller.js
similarity index 100%
rename from pkg/unittest/test_controller.js
rename to pkg/unittest/lib/test_controller.js
diff --git a/pkg/unittest/lib/unittest.dart b/pkg/unittest/lib/unittest.dart
index ea44bea..0bd231d 100644
--- a/pkg/unittest/lib/unittest.dart
+++ b/pkg/unittest/lib/unittest.dart
@@ -468,7 +468,7 @@
* tracked and reported. [callback] should take between 0 and 4 positional
* arguments (named arguments are not supported here).
*/
-Function _expectAsync(Function callback, [int count = 1]) {
+Function _expectAsync(Function callback, {int count: 1}) {
return new _SpreadArgsHelper.fixedCallCount(callback, count).invoke;
}
@@ -481,7 +481,7 @@
* arguments are not supported).
*/
// TODO(sigmund): deprecate this API when issue 2706 is fixed.
-Function expectAsync0(Function callback, [int count = 1]) {
+Function expectAsync0(Function callback, {int count: 1}) {
return new _SpreadArgsHelper.fixedCallCount(callback, count).invoke0;
}
@@ -493,7 +493,7 @@
/** Like [expectAsync0] but [callback] should take 2 positional arguments. */
// TODO(sigmund): deprecate this API when issue 2706 is fixed.
-Function expectAsync2(Function callback, [int count = 1]) {
+Function expectAsync2(Function callback, {int count: 1}) {
return new _SpreadArgsHelper.fixedCallCount(callback, count).invoke2;
}
diff --git a/pkg/unittest/static/coverage_controller.js b/pkg/unittest/static/coverage_controller.js
deleted file mode 100644
index 78ddb9d..0000000
--- a/pkg/unittest/static/coverage_controller.js
+++ /dev/null
@@ -1,31 +0,0 @@
-// 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.
-
-/**
- * Coverage controller logic - used by coverage test harness to embed tests in
- * DumpRenderTree and extract coverage information.
- */
-
-var LONG_LINE = 60000;
-
-function onReceive(e) {
- if (e.data == 'unittest-suite-done') {
- var s = JSON.stringify(top._$jscoverage);
- var res = '';
- // DumpRenderTree has a bug on lines longer than 2^16, so we split them
- while (s.length > LONG_LINE) {
- res += s.substr(0, LONG_LINE) + '<br>\n';
- s = s.substr(LONG_LINE);
- }
- res += s;
- window.document.body.innerHTML = res;
- window.layoutTestController.notifyDone();
- }
-}
-
-if (window.layoutTestController) {
- window.layoutTestController.dumpAsText();
- window.layoutTestController.waitUntilDone();
- window.addEventListener("message", onReceive, false);
-}
diff --git a/pkg/unittest/static/test_controller.js b/pkg/unittest/static/test_controller.js
deleted file mode 100644
index b5734b9..0000000
--- a/pkg/unittest/static/test_controller.js
+++ /dev/null
@@ -1,120 +0,0 @@
-// 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.
-
-/**
- * Test controller logic - used by unit test harness to embed tests in
- * DumpRenderTree.
- */
-
-if (navigator.webkitStartDart) {
- navigator.webkitStartDart();
-}
-
-// testRunner is provided by DRT or WebKit's layout tests.
-// It is not available in selenium tests.
-var testRunner = window.testRunner || window.layoutTestController;
-
-var waitForDone = false;
-
-function processMessage(msg) {
- if (typeof msg != 'string') return;
- if (msg == 'unittest-suite-done') {
- if (testRunner) testRunner.notifyDone();
- } else if (msg == 'unittest-suite-wait-for-done') {
- waitForDone = true;
- if (testRunner) testRunner.startedDartTest = true;
- } else if (msg == 'dart-calling-main') {
- if (testRunner) testRunner.startedDartTest = true;
- } else if (msg == 'dart-main-done') {
- if (!waitForDone) {
- window.postMessage('unittest-suite-success', '*');
- }
- } else if (msg == 'unittest-suite-success') {
- dartPrint('PASS');
- if (testRunner) testRunner.notifyDone();
- } else if (msg == 'unittest-suite-fail') {
- showErrorAndExit('Some tests failed.');
- }
-}
-
-function onReceive(e) {
- processMessage(e.data);
-}
-
-if (testRunner) {
- testRunner.dumpAsText();
- testRunner.waitUntilDone();
-}
-window.addEventListener("message", onReceive, false);
-
-function showErrorAndExit(message) {
- if (message) {
- dartPrint('Error: ' + String(message));
- }
- // dart/tools/testing/run_selenium.py is looking for either PASS or
- // FAIL and will continue polling until one of these words show up.
- dartPrint('FAIL');
- if (testRunner) testRunner.notifyDone();
-}
-
-function onLoad(e) {
- // needed for dartium compilation errors.
- if (window.compilationError) {
- showErrorAndExit(window.compilationError);
- }
-}
-
-window.addEventListener("DOMContentLoaded", onLoad, false);
-
-// If nobody intercepts the error, finish the test.
-window.addEventListener("error", function(e) {
- // needed for dartium compilation errors.
- showErrorAndExit(e && e.message);
-}, false);
-
-document.addEventListener('readystatechange', function () {
- if (document.readyState != "loaded") return;
- // If 'startedDartTest' is not set, that means that the test did not have
- // a chance to load. This will happen when a load error occurs in the VM.
- // Give the machine time to start up.
- setTimeout(function() {
- // A window.postMessage might have been enqueued after this timeout.
- // Just sleep another time to give the browser the time to process the
- // posted message.
- setTimeout(function() {
- if (testRunner && !testRunner.startedDartTest) {
- testRunner.notifyDone();
- }
- }, 0);
- }, 50);
-});
-
-// dart2js will generate code to call this function to handle the Dart
-// [print] method. The base [Configuration] (config.html) calls
-// [print] with the secret messages "unittest-suite-success" and
-// "unittest-suite-wait-for-done". These messages are then posted so
-// processMessage above will see them.
-function dartPrint(msg) {
- if ((msg === 'unittest-suite-success')
- || (msg === 'unittest-suite-wait-for-done')) {
- window.postMessage(msg, '*');
- return;
- }
- var pre = document.createElement("pre");
- pre.appendChild(document.createTextNode(String(msg)));
- document.body.appendChild(pre);
-}
-
-// dart2js will generate code to call this function instead of calling
-// Dart [main] directly. The argument is a closure that invokes main.
-function dartMainRunner(main) {
- window.postMessage('dart-calling-main', '*');
- try {
- main();
- } catch (e) {
- window.postMessage('unittest-suite-fail', '*');
- return;
- }
- window.postMessage('dart-main-done', '*');
-}
diff --git a/runtime/bin/dbg_connection.cc b/runtime/bin/dbg_connection.cc
index 25d465d..583d737 100644
--- a/runtime/bin/dbg_connection.cc
+++ b/runtime/bin/dbg_connection.cc
@@ -264,7 +264,7 @@
void DebuggerConnectionHandler::CloseDbgConnection() {
if (debug_fd_ >= 0) {
- // TODO(hausner): need a Socket::Close() function.
+ Socket::Close(debug_fd_);
}
if (msgbuf_ != NULL) {
delete msgbuf_;
diff --git a/runtime/bin/directory_android.cc b/runtime/bin/directory_android.cc
index f3f471f..8b40073 100644
--- a/runtime/bin/directory_android.cc
+++ b/runtime/bin/directory_android.cc
@@ -6,6 +6,7 @@
#include <dirent.h>
#include <errno.h>
+#include <string.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -13,12 +14,36 @@
#include "bin/file.h"
#include "bin/platform.h"
+class PathBuffer {
+ public:
+ PathBuffer() : length(0) { }
-static char* SafeStrNCpy(char* dest, const char* src, size_t n) {
- strncpy(dest, src, n);
- dest[n - 1] = '\0';
- return dest;
-}
+
+
+ char data[PATH_MAX + 1];
+ int length;
+
+ bool Add(const char* name) {
+ size_t written = snprintf(data + length,
+ PATH_MAX - length,
+ "%s",
+ name);
+ data[PATH_MAX] = '\0';
+ if (written == strnlen(name, PATH_MAX + 1)) {
+ length += written;
+ return true;
+ } else {
+ errno = ENAMETOOLONG;
+ return false;
+ }
+ }
+
+ void Reset(int new_length) {
+ length = new_length;
+ data[length] = '\0';
+ }
+};
+
// Forward declarations.
@@ -28,76 +53,56 @@
static bool DeleteRecursively(const char* dir_name);
-static bool ComputeFullPath(const char* dir_name,
- char* path,
- int* path_length) {
- char* abs_path;
- do {
- abs_path = realpath(dir_name, path);
- } while (abs_path == NULL && errno == EINTR);
- if (abs_path == NULL) {
- return false;
- }
- *path_length = strlen(path);
- size_t written = snprintf(path + *path_length,
- PATH_MAX - *path_length,
- "%s",
- File::PathSeparator());
- if (written != strlen(File::PathSeparator())) {
- return false;
- }
- *path_length += written;
- return true;
-}
-
-
-static bool HandleDir(char* dir_name,
- char* path,
- int path_length,
- bool recursive,
- DirectoryListing *listing) {
- if (strcmp(dir_name, ".") != 0 &&
- strcmp(dir_name, "..") != 0) {
- size_t written = snprintf(path + path_length,
- PATH_MAX - path_length,
- "%s",
- dir_name);
- if (written != strlen(dir_name)) {
- return false;
- }
- bool ok = listing->HandleDirectory(path);
- if (!ok) return ok;
- if (recursive) {
- return ListRecursively(path, recursive, listing);
- }
- }
- return true;
-}
-
-
-static bool HandleFile(char* file_name,
- char* path,
- int path_length,
- DirectoryListing *listing) {
- // TODO(sgjesse): Pass flags to indicate whether file responses are
- // needed.
- size_t written = snprintf(path + path_length,
- PATH_MAX - path_length,
- "%s",
- file_name);
- if (written != strlen(file_name)) {
- return false;
- }
- return listing->HandleFile(path);
-}
-
-
static void PostError(DirectoryListing *listing,
const char* dir_name) {
listing->HandleError(dir_name);
}
+static PathBuffer* ComputeFullPath(const char* dir_name) {
+ PathBuffer* path = new PathBuffer();
+ char* abs_path;
+ do {
+ abs_path = realpath(dir_name, path->data);
+ } while (abs_path == NULL && errno == EINTR);
+ if (abs_path == NULL) {
+ delete path;
+ return NULL;
+ }
+ path->length = strnlen(path->data, PATH_MAX);
+ if (path->Add(File::PathSeparator())) {
+ return path;
+ } else {
+ delete path;
+ return NULL;
+ }
+}
+
+static bool HandleDir(char* dir_name,
+ PathBuffer* path,
+ bool recursive,
+ DirectoryListing *listing) {
+ if (strcmp(dir_name, ".") == 0) return true;
+ if (strcmp(dir_name, "..") == 0) return true;
+ if (!path->Add(dir_name)) {
+ PostError(listing, path->data);
+ return false;
+ }
+ return listing->HandleDirectory(path->data) &&
+ (!recursive || ListRecursively(path->data, recursive, listing));
+}
+
+static bool HandleFile(char* file_name,
+ PathBuffer* path,
+ DirectoryListing *listing) {
+ if (!path->Add(file_name)) {
+ PostError(listing, path->data);
+ return false;
+ }
+ return listing->HandleFile(path->data);
+}
+
+
static bool ListRecursively(const char* dir_name,
bool recursive,
DirectoryListing *listing) {
@@ -115,38 +120,32 @@
// recursive traversal. path_length does not always equal
// strlen(path) but indicates the current prefix of path that is the
// path of the current directory in the traversal.
- char *path = static_cast<char*>(malloc(PATH_MAX));
- ASSERT(path != NULL);
- int path_length = 0;
- bool valid = ComputeFullPath(dir_name, path, &path_length);
- if (!valid) {
- free(path);
+ PathBuffer* path = ComputeFullPath(dir_name);
+ if (path == NULL) {
PostError(listing, dir_name);
return false;
}
-
- // Iterated the directory and post the directories and files to the
+ // Iterate the directory and post the directories and files to the
// ports.
- int read = 0;
+ int path_length = path->length;
+ int status = 0;
bool success = true;
dirent entry;
dirent* result;
- while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
- &entry,
- &result))) == 0 &&
+ while ((status = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
+ &entry,
+ &result))) == 0 &&
result != NULL) {
switch (entry.d_type) {
case DT_DIR:
success = HandleDir(entry.d_name,
path,
- path_length,
recursive,
listing) && success;
break;
case DT_REG:
success = HandleFile(entry.d_name,
path,
- path_length,
listing) && success;
break;
case DT_LNK:
@@ -156,30 +155,25 @@
// the actual entry type. Notice that stat returns the type of
// the file pointed to.
struct stat entry_info;
- size_t written = snprintf(path + path_length,
- PATH_MAX - path_length,
- "%s",
- entry.d_name);
- if (written != strlen(entry.d_name)) {
+ if (!path->Add(entry.d_name)) {
success = false;
break;
}
- int stat_success = TEMP_FAILURE_RETRY(stat(path, &entry_info));
+ int stat_success = TEMP_FAILURE_RETRY(stat(path->data, &entry_info));
if (stat_success == -1) {
success = false;
- PostError(listing, path);
+ PostError(listing, path->data);
break;
}
+ path->Reset(path_length);
if (S_ISDIR(entry_info.st_mode)) {
success = HandleDir(entry.d_name,
path,
- path_length,
recursive,
listing) && success;
} else if (S_ISREG(entry_info.st_mode)) {
success = HandleFile(entry.d_name,
path,
- path_length,
listing) && success;
}
ASSERT(!S_ISLNK(entry_info.st_mode));
@@ -188,10 +182,11 @@
default:
break;
}
+ path->Reset(path_length);
}
- if (read != 0) {
- errno = read;
+ if (status != 0) {
+ errno = status;
success = false;
PostError(listing, dir_name);
}
@@ -200,41 +195,23 @@
success = false;
PostError(listing, dir_name);
}
- free(path);
+ delete path;
return success;
}
static bool DeleteFile(char* file_name,
- char* path,
- int path_length) {
- size_t written = snprintf(path + path_length,
- PATH_MAX - path_length,
- "%s",
- file_name);
- if (written != strlen(file_name)) {
- return false;
- }
- return (remove(path) == 0);
+ PathBuffer* path) {
+ return path->Add(file_name) && remove(path->data) == 0;
}
static bool DeleteDir(char* dir_name,
- char* path,
- int path_length) {
- if (strcmp(dir_name, ".") != 0 &&
- strcmp(dir_name, "..") != 0) {
- size_t written = snprintf(path + path_length,
- PATH_MAX - path_length,
- "%s",
- dir_name);
- if (written != strlen(dir_name)) {
- return false;
- }
- return DeleteRecursively(path);
- }
- return true;
+ PathBuffer* path) {
+ if (strcmp(dir_name, ".") == 0) return true;
+ if (strcmp(dir_name, "..") == 0) return true;
+ return path->Add(dir_name) && DeleteRecursively(path->data);
}
@@ -260,19 +237,12 @@
// Compute full path for the directory currently being deleted. The
// path buffer will be used to construct the current path in the
- // recursive traversal. path_length does not always equal
- // strlen(path) but indicates the current prefix of path that is the
- // path of the current directory in the traversal.
- char *path = static_cast<char*>(malloc(PATH_MAX));
- ASSERT(path != NULL);
- int path_length = 0;
- bool valid = ComputeFullPath(dir_name, path, &path_length);
- if (!valid) {
- free(path);
- return false;
- }
+ // recursive traversal.
+ PathBuffer* path = ComputeFullPath(dir_name);
+ if (path == NULL) return false;
// Iterate the directory and delete all files and directories.
+ int path_length = path->length;
int read = 0;
bool success = true;
dirent entry;
@@ -284,49 +254,46 @@
success) {
switch (entry.d_type) {
case DT_DIR:
- success = success && DeleteDir(entry.d_name, path, path_length);
+ success = success && DeleteDir(entry.d_name, path);
break;
case DT_REG:
case DT_LNK:
// Treat all links as files. This will delete the link which
// is what we want no matter if the link target is a file or a
// directory.
- success = success && DeleteFile(entry.d_name, path, path_length);
+ success = success && DeleteFile(entry.d_name, path);
break;
case DT_UNKNOWN: {
// On some file systems the entry type is not determined by
// readdir_r. For those we use lstat to determine the entry
// type.
struct stat entry_info;
- size_t written = snprintf(path + path_length,
- PATH_MAX - path_length,
- "%s",
- entry.d_name);
- if (written != strlen(entry.d_name)) {
+ if (!path->Add(entry.d_name)) {
success = false;
break;
}
- int lstat_success = TEMP_FAILURE_RETRY(lstat(path, &entry_info));
+ int lstat_success = TEMP_FAILURE_RETRY(lstat(path->data, &entry_info));
if (lstat_success == -1) {
success = false;
break;
}
+ path->Reset(path_length);
if (S_ISDIR(entry_info.st_mode)) {
- success = success && DeleteDir(entry.d_name, path, path_length);
+ success = success && DeleteDir(entry.d_name, path);
} else if (S_ISREG(entry_info.st_mode) || S_ISLNK(entry_info.st_mode)) {
// Treat links as files. This will delete the link which is
// what we want no matter if the link target is a file or a
// directory.
- success = success && DeleteFile(entry.d_name, path, path_length);
+ success = success && DeleteFile(entry.d_name, path);
}
break;
}
default:
break;
}
+ path->Reset(path_length);
}
-
- free(path);
+ delete path;
if ((read != 0) ||
(closedir(dir_pointer) == -1) ||
@@ -393,7 +360,7 @@
// process umask.
int result = TEMP_FAILURE_RETRY(mkdir(dir_name, 0777));
// If the directory already exists, treat it as a success.
- if (result == -1 && errno == EEXISTS) {
+ if (result == -1 && errno == EEXIST) {
return (Exists(dir_name) == EXISTS);
}
return (result == 0);
@@ -418,16 +385,9 @@
// dir_template. Creates the directory with the permissions specified
// by the process umask.
// The return value must be freed by the caller.
- char* path = static_cast<char*>(malloc(PATH_MAX + 1));
- SafeStrNCpy(path, const_template, PATH_MAX + 1);
- int path_length = strlen(path);
- if (path_length > 0) {
- if ((path)[path_length - 1] == '/') {
- snprintf(path + path_length, PATH_MAX - path_length, "temp_dir_XXXXXX");
- } else {
- snprintf(path + path_length, PATH_MAX - path_length, "XXXXXX");
- }
- } else {
+ PathBuffer* path = new PathBuffer();
+ path->Add(const_template);
+ if (path->length == 0) {
// Android does not have a /tmp directory. A partial substitute,
// suitable for bring-up work and tests, is to create a tmp
// directory in /data/local/tmp.
@@ -439,17 +399,29 @@
if (stat(ANDROID_TEMP_DIR, &st) != 0) {
mkdir(ANDROID_TEMP_DIR, 0777);
}
- snprintf(path, PATH_MAX, ANDROID_TEMP_DIR "/temp_dir1_XXXXXX");
+ path->Add(ANDROID_TEMP_DIR "/tmp/temp_dir1_");
+ } else if ((path->data)[path->length - 1] == '/') {
+ path->Add("temp_dir_");
+ }
+ if (!path->Add("XXXXXX")) {
+ // Pattern has overflowed.
+ delete path;
+ return NULL;
}
char* result;
do {
- result = MakeTempDirectory(path);
+ result = MakeTempDirectory(path->data);
} while (result == NULL && errno == EINTR);
if (result == NULL) {
- free(path);
+ delete path;
return NULL;
}
- return path;
+ int length = strnlen(path->data, PATH_MAX);
+ result = static_cast<char*>(malloc(length + 1));
+ strncpy(result, path->data, length);
+ result[length] = '\0';
+ delete path;
+ return result;
}
diff --git a/runtime/bin/directory_linux.cc b/runtime/bin/directory_linux.cc
index 241fce2..7b94aac 100644
--- a/runtime/bin/directory_linux.cc
+++ b/runtime/bin/directory_linux.cc
@@ -6,6 +6,7 @@
#include <dirent.h>
#include <errno.h>
+#include <string.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -13,12 +14,35 @@
#include "bin/file.h"
#include "bin/platform.h"
+class PathBuffer {
+ public:
+ PathBuffer() : length(0) { }
-static char* SafeStrNCpy(char* dest, const char* src, size_t n) {
- strncpy(dest, src, n);
- dest[n - 1] = '\0';
- return dest;
-}
+
+
+ char data[PATH_MAX + 1];
+ int length;
+
+ bool Add(const char* name) {
+ size_t written = snprintf(data + length,
+ PATH_MAX - length,
+ "%s",
+ name);
+ data[PATH_MAX] = '\0';
+ if (written == strnlen(name, PATH_MAX + 1)) {
+ length += written;
+ return true;
+ } else {
+ errno = ENAMETOOLONG;
+ return false;
+ }
+ }
+
+ void Reset(int new_length) {
+ length = new_length;
+ data[length] = '\0';
+ }
+};
// Forward declarations.
@@ -28,76 +52,56 @@
static bool DeleteRecursively(const char* dir_name);
-static bool ComputeFullPath(const char* dir_name,
- char* path,
- int* path_length) {
- char* abs_path;
- do {
- abs_path = realpath(dir_name, path);
- } while (abs_path == NULL && errno == EINTR);
- if (abs_path == NULL) {
- return false;
- }
- *path_length = strlen(path);
- size_t written = snprintf(path + *path_length,
- PATH_MAX - *path_length,
- "%s",
- File::PathSeparator());
- if (written != strlen(File::PathSeparator())) {
- return false;
- }
- *path_length += written;
- return true;
-}
-
-
-static bool HandleDir(char* dir_name,
- char* path,
- int path_length,
- bool recursive,
- DirectoryListing *listing) {
- if (strcmp(dir_name, ".") != 0 &&
- strcmp(dir_name, "..") != 0) {
- size_t written = snprintf(path + path_length,
- PATH_MAX - path_length,
- "%s",
- dir_name);
- if (written != strlen(dir_name)) {
- return false;
- }
- bool ok = listing->HandleDirectory(path);
- if (!ok) return ok;
- if (recursive) {
- return ListRecursively(path, recursive, listing);
- }
- }
- return true;
-}
-
-
-static bool HandleFile(char* file_name,
- char* path,
- int path_length,
- DirectoryListing *listing) {
- // TODO(sgjesse): Pass flags to indicate whether file responses are
- // needed.
- size_t written = snprintf(path + path_length,
- PATH_MAX - path_length,
- "%s",
- file_name);
- if (written != strlen(file_name)) {
- return false;
- }
- return listing->HandleFile(path);
-}
-
-
static void PostError(DirectoryListing *listing,
const char* dir_name) {
listing->HandleError(dir_name);
}
+static PathBuffer* ComputeFullPath(const char* dir_name) {
+ PathBuffer* path = new PathBuffer();
+ char* abs_path;
+ do {
+ abs_path = realpath(dir_name, path->data);
+ } while (abs_path == NULL && errno == EINTR);
+ if (abs_path == NULL) {
+ delete path;
+ return NULL;
+ }
+ path->length = strnlen(path->data, PATH_MAX);
+ if (path->Add(File::PathSeparator())) {
+ return path;
+ } else {
+ delete path;
+ return NULL;
+ }
+}
+
+static bool HandleDir(char* dir_name,
+ PathBuffer* path,
+ bool recursive,
+ DirectoryListing *listing) {
+ if (strcmp(dir_name, ".") == 0) return true;
+ if (strcmp(dir_name, "..") == 0) return true;
+ if (!path->Add(dir_name)) {
+ PostError(listing, path->data);
+ return false;
+ }
+ return listing->HandleDirectory(path->data) &&
+ (!recursive || ListRecursively(path->data, recursive, listing));
+}
+
+static bool HandleFile(char* file_name,
+ PathBuffer* path,
+ DirectoryListing *listing) {
+ if (!path->Add(file_name)) {
+ PostError(listing, path->data);
+ return false;
+ }
+ return listing->HandleFile(path->data);
+}
+
+
static bool ListRecursively(const char* dir_name,
bool recursive,
DirectoryListing *listing) {
@@ -115,38 +119,32 @@
// recursive traversal. path_length does not always equal
// strlen(path) but indicates the current prefix of path that is the
// path of the current directory in the traversal.
- char *path = static_cast<char*>(malloc(PATH_MAX));
- ASSERT(path != NULL);
- int path_length = 0;
- bool valid = ComputeFullPath(dir_name, path, &path_length);
- if (!valid) {
- free(path);
+ PathBuffer* path = ComputeFullPath(dir_name);
+ if (path == NULL) {
PostError(listing, dir_name);
return false;
}
-
- // Iterated the directory and post the directories and files to the
+ // Iterate the directory and post the directories and files to the
// ports.
- int read = 0;
+ int path_length = path->length;
+ int status = 0;
bool success = true;
dirent entry;
dirent* result;
- while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
- &entry,
- &result))) == 0 &&
+ while ((status = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
+ &entry,
+ &result))) == 0 &&
result != NULL) {
switch (entry.d_type) {
case DT_DIR:
success = HandleDir(entry.d_name,
path,
- path_length,
recursive,
listing) && success;
break;
case DT_REG:
success = HandleFile(entry.d_name,
path,
- path_length,
listing) && success;
break;
case DT_LNK:
@@ -156,30 +154,25 @@
// the actual entry type. Notice that stat returns the type of
// the file pointed to.
struct stat entry_info;
- size_t written = snprintf(path + path_length,
- PATH_MAX - path_length,
- "%s",
- entry.d_name);
- if (written != strlen(entry.d_name)) {
+ if (!path->Add(entry.d_name)) {
success = false;
break;
}
- int stat_success = TEMP_FAILURE_RETRY(stat(path, &entry_info));
+ int stat_success = TEMP_FAILURE_RETRY(stat(path->data, &entry_info));
if (stat_success == -1) {
success = false;
- PostError(listing, path);
+ PostError(listing, path->data);
break;
}
+ path->Reset(path_length);
if (S_ISDIR(entry_info.st_mode)) {
success = HandleDir(entry.d_name,
path,
- path_length,
recursive,
listing) && success;
} else if (S_ISREG(entry_info.st_mode)) {
success = HandleFile(entry.d_name,
path,
- path_length,
listing) && success;
}
ASSERT(!S_ISLNK(entry_info.st_mode));
@@ -188,10 +181,11 @@
default:
break;
}
+ path->Reset(path_length);
}
- if (read != 0) {
- errno = read;
+ if (status != 0) {
+ errno = status;
success = false;
PostError(listing, dir_name);
}
@@ -200,41 +194,23 @@
success = false;
PostError(listing, dir_name);
}
- free(path);
+ delete path;
return success;
}
static bool DeleteFile(char* file_name,
- char* path,
- int path_length) {
- size_t written = snprintf(path + path_length,
- PATH_MAX - path_length,
- "%s",
- file_name);
- if (written != strlen(file_name)) {
- return false;
- }
- return (remove(path) == 0);
+ PathBuffer* path) {
+ return path->Add(file_name) && remove(path->data) == 0;
}
static bool DeleteDir(char* dir_name,
- char* path,
- int path_length) {
- if (strcmp(dir_name, ".") != 0 &&
- strcmp(dir_name, "..") != 0) {
- size_t written = snprintf(path + path_length,
- PATH_MAX - path_length,
- "%s",
- dir_name);
- if (written != strlen(dir_name)) {
- return false;
- }
- return DeleteRecursively(path);
- }
- return true;
+ PathBuffer* path) {
+ if (strcmp(dir_name, ".") == 0) return true;
+ if (strcmp(dir_name, "..") == 0) return true;
+ return path->Add(dir_name) && DeleteRecursively(path->data);
}
@@ -260,19 +236,12 @@
// Compute full path for the directory currently being deleted. The
// path buffer will be used to construct the current path in the
- // recursive traversal. path_length does not always equal
- // strlen(path) but indicates the current prefix of path that is the
- // path of the current directory in the traversal.
- char *path = static_cast<char*>(malloc(PATH_MAX));
- ASSERT(path != NULL);
- int path_length = 0;
- bool valid = ComputeFullPath(dir_name, path, &path_length);
- if (!valid) {
- free(path);
- return false;
- }
+ // recursive traversal.
+ PathBuffer* path = ComputeFullPath(dir_name);
+ if (path == NULL) return false;
// Iterate the directory and delete all files and directories.
+ int path_length = path->length;
int read = 0;
bool success = true;
dirent entry;
@@ -284,49 +253,46 @@
success) {
switch (entry.d_type) {
case DT_DIR:
- success = success && DeleteDir(entry.d_name, path, path_length);
+ success = success && DeleteDir(entry.d_name, path);
break;
case DT_REG:
case DT_LNK:
// Treat all links as files. This will delete the link which
// is what we want no matter if the link target is a file or a
// directory.
- success = success && DeleteFile(entry.d_name, path, path_length);
+ success = success && DeleteFile(entry.d_name, path);
break;
case DT_UNKNOWN: {
// On some file systems the entry type is not determined by
// readdir_r. For those we use lstat to determine the entry
// type.
struct stat entry_info;
- size_t written = snprintf(path + path_length,
- PATH_MAX - path_length,
- "%s",
- entry.d_name);
- if (written != strlen(entry.d_name)) {
+ if (!path->Add(entry.d_name)) {
success = false;
break;
}
- int lstat_success = TEMP_FAILURE_RETRY(lstat(path, &entry_info));
+ int lstat_success = TEMP_FAILURE_RETRY(lstat(path->data, &entry_info));
if (lstat_success == -1) {
success = false;
break;
}
+ path->Reset(path_length);
if (S_ISDIR(entry_info.st_mode)) {
- success = success && DeleteDir(entry.d_name, path, path_length);
+ success = success && DeleteDir(entry.d_name, path);
} else if (S_ISREG(entry_info.st_mode) || S_ISLNK(entry_info.st_mode)) {
// Treat links as files. This will delete the link which is
// what we want no matter if the link target is a file or a
// directory.
- success = success && DeleteFile(entry.d_name, path, path_length);
+ success = success && DeleteFile(entry.d_name, path);
}
break;
}
default:
break;
}
+ path->Reset(path_length);
}
-
- free(path);
+ delete path;
if ((read != 0) ||
(closedir(dir_pointer) == -1) ||
@@ -397,27 +363,32 @@
// dir_template. Creates the directory with the permissions specified
// by the process umask.
// The return value must be freed by the caller.
- char* path = static_cast<char*>(malloc(PATH_MAX + 1));
- SafeStrNCpy(path, const_template, PATH_MAX + 1);
- int path_length = strlen(path);
- if (path_length > 0) {
- if ((path)[path_length - 1] == '/') {
- snprintf(path + path_length, PATH_MAX - path_length, "temp_dir_XXXXXX");
- } else {
- snprintf(path + path_length, PATH_MAX - path_length, "XXXXXX");
- }
- } else {
- snprintf(path, PATH_MAX, "/tmp/temp_dir1_XXXXXX");
+ PathBuffer* path = new PathBuffer();
+ path->Add(const_template);
+ if (path->length == 0) {
+ path->Add("/tmp/temp_dir1_");
+ } else if ((path->data)[path->length - 1] == '/') {
+ path->Add("temp_dir_");
+ }
+ if (!path->Add("XXXXXX")) {
+ // Pattern has overflowed.
+ delete path;
+ return NULL;
}
char* result;
do {
- result = mkdtemp(path);
+ result = mkdtemp(path->data);
} while (result == NULL && errno == EINTR);
if (result == NULL) {
- free(path);
+ delete path;
return NULL;
}
- return path;
+ int length = strnlen(path->data, PATH_MAX);
+ result = static_cast<char*>(malloc(length + 1));
+ strncpy(result, path->data, length);
+ result[length] = '\0';
+ delete path;
+ return result;
}
diff --git a/runtime/bin/directory_macos.cc b/runtime/bin/directory_macos.cc
index 241fce2..8a0f2b7 100644
--- a/runtime/bin/directory_macos.cc
+++ b/runtime/bin/directory_macos.cc
@@ -6,6 +6,7 @@
#include <dirent.h>
#include <errno.h>
+#include <string.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <unistd.h>
@@ -13,12 +14,36 @@
#include "bin/file.h"
#include "bin/platform.h"
+class PathBuffer {
+ public:
+ PathBuffer() : length(0) { }
-static char* SafeStrNCpy(char* dest, const char* src, size_t n) {
- strncpy(dest, src, n);
- dest[n - 1] = '\0';
- return dest;
-}
+
+
+ char data[PATH_MAX + 1];
+ int length;
+
+ bool Add(const char* name) {
+ size_t written = snprintf(data + length,
+ PATH_MAX - length,
+ "%s",
+ name);
+ data[PATH_MAX] = '\0';
+ if (written == strlen(name)) {
+ length += written;
+ return true;
+ } else {
+ errno = ENAMETOOLONG;
+ return false;
+ }
+ }
+
+ void Reset(int new_length) {
+ length = new_length;
+ data[length] = '\0';
+ }
+};
+
// Forward declarations.
@@ -28,76 +53,56 @@
static bool DeleteRecursively(const char* dir_name);
-static bool ComputeFullPath(const char* dir_name,
- char* path,
- int* path_length) {
- char* abs_path;
- do {
- abs_path = realpath(dir_name, path);
- } while (abs_path == NULL && errno == EINTR);
- if (abs_path == NULL) {
- return false;
- }
- *path_length = strlen(path);
- size_t written = snprintf(path + *path_length,
- PATH_MAX - *path_length,
- "%s",
- File::PathSeparator());
- if (written != strlen(File::PathSeparator())) {
- return false;
- }
- *path_length += written;
- return true;
-}
-
-
-static bool HandleDir(char* dir_name,
- char* path,
- int path_length,
- bool recursive,
- DirectoryListing *listing) {
- if (strcmp(dir_name, ".") != 0 &&
- strcmp(dir_name, "..") != 0) {
- size_t written = snprintf(path + path_length,
- PATH_MAX - path_length,
- "%s",
- dir_name);
- if (written != strlen(dir_name)) {
- return false;
- }
- bool ok = listing->HandleDirectory(path);
- if (!ok) return ok;
- if (recursive) {
- return ListRecursively(path, recursive, listing);
- }
- }
- return true;
-}
-
-
-static bool HandleFile(char* file_name,
- char* path,
- int path_length,
- DirectoryListing *listing) {
- // TODO(sgjesse): Pass flags to indicate whether file responses are
- // needed.
- size_t written = snprintf(path + path_length,
- PATH_MAX - path_length,
- "%s",
- file_name);
- if (written != strlen(file_name)) {
- return false;
- }
- return listing->HandleFile(path);
-}
-
-
static void PostError(DirectoryListing *listing,
const char* dir_name) {
listing->HandleError(dir_name);
}
+static PathBuffer* ComputeFullPath(const char* dir_name) {
+ PathBuffer* path = new PathBuffer();
+ char* abs_path;
+ do {
+ abs_path = realpath(dir_name, path->data);
+ } while (abs_path == NULL && errno == EINTR);
+ if (abs_path == NULL) {
+ delete path;
+ return NULL;
+ }
+ path->length = strlen(path->data);
+ if (path->Add(File::PathSeparator())) {
+ return path;
+ } else {
+ delete path;
+ return NULL;
+ }
+}
+
+static bool HandleDir(char* dir_name,
+ PathBuffer* path,
+ bool recursive,
+ DirectoryListing *listing) {
+ if (strcmp(dir_name, ".") == 0) return true;
+ if (strcmp(dir_name, "..") == 0) return true;
+ if (!path->Add(dir_name)) {
+ PostError(listing, path->data);
+ return false;
+ }
+ return listing->HandleDirectory(path->data) &&
+ (!recursive || ListRecursively(path->data, recursive, listing));
+}
+
+static bool HandleFile(char* file_name,
+ PathBuffer* path,
+ DirectoryListing *listing) {
+ if (!path->Add(file_name)) {
+ PostError(listing, path->data);
+ return false;
+ }
+ return listing->HandleFile(path->data);
+}
+
+
static bool ListRecursively(const char* dir_name,
bool recursive,
DirectoryListing *listing) {
@@ -115,38 +120,32 @@
// recursive traversal. path_length does not always equal
// strlen(path) but indicates the current prefix of path that is the
// path of the current directory in the traversal.
- char *path = static_cast<char*>(malloc(PATH_MAX));
- ASSERT(path != NULL);
- int path_length = 0;
- bool valid = ComputeFullPath(dir_name, path, &path_length);
- if (!valid) {
- free(path);
+ PathBuffer* path = ComputeFullPath(dir_name);
+ if (path == NULL) {
PostError(listing, dir_name);
return false;
}
-
- // Iterated the directory and post the directories and files to the
+ // Iterate the directory and post the directories and files to the
// ports.
- int read = 0;
+ int path_length = path->length;
+ int status = 0;
bool success = true;
dirent entry;
dirent* result;
- while ((read = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
- &entry,
- &result))) == 0 &&
+ while ((status = TEMP_FAILURE_RETRY(readdir_r(dir_pointer,
+ &entry,
+ &result))) == 0 &&
result != NULL) {
switch (entry.d_type) {
case DT_DIR:
success = HandleDir(entry.d_name,
path,
- path_length,
recursive,
listing) && success;
break;
case DT_REG:
success = HandleFile(entry.d_name,
path,
- path_length,
listing) && success;
break;
case DT_LNK:
@@ -156,30 +155,25 @@
// the actual entry type. Notice that stat returns the type of
// the file pointed to.
struct stat entry_info;
- size_t written = snprintf(path + path_length,
- PATH_MAX - path_length,
- "%s",
- entry.d_name);
- if (written != strlen(entry.d_name)) {
+ if (!path->Add(entry.d_name)) {
success = false;
break;
}
- int stat_success = TEMP_FAILURE_RETRY(stat(path, &entry_info));
+ int stat_success = TEMP_FAILURE_RETRY(stat(path->data, &entry_info));
if (stat_success == -1) {
success = false;
- PostError(listing, path);
+ PostError(listing, path->data);
break;
}
+ path->Reset(path_length);
if (S_ISDIR(entry_info.st_mode)) {
success = HandleDir(entry.d_name,
path,
- path_length,
recursive,
listing) && success;
} else if (S_ISREG(entry_info.st_mode)) {
success = HandleFile(entry.d_name,
path,
- path_length,
listing) && success;
}
ASSERT(!S_ISLNK(entry_info.st_mode));
@@ -188,10 +182,11 @@
default:
break;
}
+ path->Reset(path_length);
}
- if (read != 0) {
- errno = read;
+ if (status != 0) {
+ errno = status;
success = false;
PostError(listing, dir_name);
}
@@ -200,41 +195,23 @@
success = false;
PostError(listing, dir_name);
}
- free(path);
+ delete path;
return success;
}
static bool DeleteFile(char* file_name,
- char* path,
- int path_length) {
- size_t written = snprintf(path + path_length,
- PATH_MAX - path_length,
- "%s",
- file_name);
- if (written != strlen(file_name)) {
- return false;
- }
- return (remove(path) == 0);
+ PathBuffer* path) {
+ return path->Add(file_name) && remove(path->data) == 0;
}
static bool DeleteDir(char* dir_name,
- char* path,
- int path_length) {
- if (strcmp(dir_name, ".") != 0 &&
- strcmp(dir_name, "..") != 0) {
- size_t written = snprintf(path + path_length,
- PATH_MAX - path_length,
- "%s",
- dir_name);
- if (written != strlen(dir_name)) {
- return false;
- }
- return DeleteRecursively(path);
- }
- return true;
+ PathBuffer* path) {
+ if (strcmp(dir_name, ".") == 0) return true;
+ if (strcmp(dir_name, "..") == 0) return true;
+ return path->Add(dir_name) && DeleteRecursively(path->data);
}
@@ -260,19 +237,12 @@
// Compute full path for the directory currently being deleted. The
// path buffer will be used to construct the current path in the
- // recursive traversal. path_length does not always equal
- // strlen(path) but indicates the current prefix of path that is the
- // path of the current directory in the traversal.
- char *path = static_cast<char*>(malloc(PATH_MAX));
- ASSERT(path != NULL);
- int path_length = 0;
- bool valid = ComputeFullPath(dir_name, path, &path_length);
- if (!valid) {
- free(path);
- return false;
- }
+ // recursive traversal.
+ PathBuffer* path = ComputeFullPath(dir_name);
+ if (path == NULL) return false;
// Iterate the directory and delete all files and directories.
+ int path_length = path->length;
int read = 0;
bool success = true;
dirent entry;
@@ -284,49 +254,46 @@
success) {
switch (entry.d_type) {
case DT_DIR:
- success = success && DeleteDir(entry.d_name, path, path_length);
+ success = success && DeleteDir(entry.d_name, path);
break;
case DT_REG:
case DT_LNK:
// Treat all links as files. This will delete the link which
// is what we want no matter if the link target is a file or a
// directory.
- success = success && DeleteFile(entry.d_name, path, path_length);
+ success = success && DeleteFile(entry.d_name, path);
break;
case DT_UNKNOWN: {
// On some file systems the entry type is not determined by
// readdir_r. For those we use lstat to determine the entry
// type.
struct stat entry_info;
- size_t written = snprintf(path + path_length,
- PATH_MAX - path_length,
- "%s",
- entry.d_name);
- if (written != strlen(entry.d_name)) {
+ if (!path->Add(entry.d_name)) {
success = false;
break;
}
- int lstat_success = TEMP_FAILURE_RETRY(lstat(path, &entry_info));
+ int lstat_success = TEMP_FAILURE_RETRY(lstat(path->data, &entry_info));
if (lstat_success == -1) {
success = false;
break;
}
+ path->Reset(path_length);
if (S_ISDIR(entry_info.st_mode)) {
- success = success && DeleteDir(entry.d_name, path, path_length);
+ success = success && DeleteDir(entry.d_name, path);
} else if (S_ISREG(entry_info.st_mode) || S_ISLNK(entry_info.st_mode)) {
// Treat links as files. This will delete the link which is
// what we want no matter if the link target is a file or a
// directory.
- success = success && DeleteFile(entry.d_name, path, path_length);
+ success = success && DeleteFile(entry.d_name, path);
}
break;
}
default:
break;
}
+ path->Reset(path_length);
}
-
- free(path);
+ delete path;
if ((read != 0) ||
(closedir(dir_pointer) == -1) ||
@@ -397,27 +364,32 @@
// dir_template. Creates the directory with the permissions specified
// by the process umask.
// The return value must be freed by the caller.
- char* path = static_cast<char*>(malloc(PATH_MAX + 1));
- SafeStrNCpy(path, const_template, PATH_MAX + 1);
- int path_length = strlen(path);
- if (path_length > 0) {
- if ((path)[path_length - 1] == '/') {
- snprintf(path + path_length, PATH_MAX - path_length, "temp_dir_XXXXXX");
- } else {
- snprintf(path + path_length, PATH_MAX - path_length, "XXXXXX");
- }
- } else {
- snprintf(path, PATH_MAX, "/tmp/temp_dir1_XXXXXX");
+ PathBuffer* path = new PathBuffer();
+ path->Add(const_template);
+ if (path->length == 0) {
+ path->Add("/tmp/temp_dir1_");
+ } else if ((path->data)[path->length - 1] == '/') {
+ path->Add("temp_dir_");
+ }
+ if (!path->Add("XXXXXX")) {
+ // Pattern has overflowed.
+ delete path;
+ return NULL;
}
char* result;
do {
- result = mkdtemp(path);
+ result = mkdtemp(path->data);
} while (result == NULL && errno == EINTR);
if (result == NULL) {
- free(path);
+ delete path;
return NULL;
}
- return path;
+ int length = strlen(path->data);
+ result = static_cast<char*>(malloc(length + 1));
+ strncpy(result, path->data, length);
+ result[length] = '\0';
+ delete path;
+ return result;
}
diff --git a/runtime/bin/eventhandler_win.cc b/runtime/bin/eventhandler_win.cc
index 87706e8..60d0fed 100644
--- a/runtime/bin/eventhandler_win.cc
+++ b/runtime/bin/eventhandler_win.cc
@@ -261,12 +261,7 @@
return true;
}
IOBuffer::DisposeBuffer(buffer);
-
- if (GetLastError() == ERROR_BROKEN_PIPE) {
- event_handler_->HandleClosed(this);
- } else {
- event_handler_->HandleError(this);
- }
+ HandleIssueError();
return false;
} else {
// Completing asynchronously through thread.
@@ -301,13 +296,19 @@
return true;
}
IOBuffer::DisposeBuffer(buffer);
+ HandleIssueError();
+ return false;
+}
- if (GetLastError() == ERROR_BROKEN_PIPE) {
+
+void Handle::HandleIssueError() {
+ DWORD error = GetLastError();
+ if (error == ERROR_BROKEN_PIPE) {
event_handler_->HandleClosed(this);
} else {
event_handler_->HandleError(this);
}
- return false;
+ SetLastError(error);
}
@@ -329,6 +330,17 @@
}
+void SocketHandle::HandleIssueError() {
+ int error = WSAGetLastError();
+ if (error == WSAECONNRESET) {
+ event_handler_->HandleClosed(this);
+ } else {
+ event_handler_->HandleError(this);
+ }
+ WSASetLastError(error);
+}
+
+
bool ListenSocket::LoadAcceptEx() {
// Load the AcceptEx function into memory using WSAIoctl.
// The WSAIoctl function is an extension of the ioctlsocket()
@@ -564,12 +576,7 @@
}
IOBuffer::DisposeBuffer(buffer);
pending_read_ = NULL;
-
- if (WSAGetLastError() == WSAECONNRESET) {
- event_handler_->HandleClosed(this);
- } else {
- event_handler_->HandleError(this);
- }
+ HandleIssueError();
return false;
}
@@ -592,12 +599,7 @@
}
IOBuffer::DisposeBuffer(pending_write_);
pending_write_ = NULL;
-
- if (WSAGetLastError() == WSAECONNRESET) {
- event_handler_->HandleClosed(this);
- } else {
- event_handler_->HandleError(this);
- }
+ HandleIssueError();
return false;
}
diff --git a/runtime/bin/eventhandler_win.h b/runtime/bin/eventhandler_win.h
index 1aa2339..7b4902f 100644
--- a/runtime/bin/eventhandler_win.h
+++ b/runtime/bin/eventhandler_win.h
@@ -217,6 +217,7 @@
Handle(HANDLE handle, Dart_Port port);
virtual void AfterClose() = 0;
+ virtual void HandleIssueError();
Type type_;
HANDLE handle_;
@@ -260,6 +261,8 @@
explicit SocketHandle(SOCKET s) : Handle(reinterpret_cast<HANDLE>(s)) {}
SocketHandle(SOCKET s, Dart_Port port)
: Handle(reinterpret_cast<HANDLE>(s), port) {}
+
+ virtual void HandleIssueError();
};
diff --git a/runtime/bin/socket.h b/runtime/bin/socket.h
index 1f21746..31e55a3 100644
--- a/runtime/bin/socket.h
+++ b/runtime/bin/socket.h
@@ -40,6 +40,7 @@
static void GetError(intptr_t fd, OSError* os_error);
static int GetType(intptr_t fd);
static intptr_t GetStdioHandle(int num);
+ static void Close(intptr_t fd);
// Perform a IPv4 hostname lookup. Returns the hostname string in
// IPv4 dotted-decimal format.
diff --git a/runtime/bin/socket_android.cc b/runtime/bin/socket_android.cc
index cffae9f..3e41242 100644
--- a/runtime/bin/socket_android.cc
+++ b/runtime/bin/socket_android.cc
@@ -248,3 +248,15 @@
}
return socket;
}
+
+
+void Socket::Close(intptr_t fd) {
+ ASSERT(fd >= 0);
+ int err = TEMP_FAILURE_RETRY(close(fd));
+ if (err != 0) {
+ const int kBufferSize = 1024;
+ char error_message[kBufferSize];
+ strerror_r(errno, error_message, kBufferSize);
+ Log::PrintErr("%s\n", error_message);
+ }
+}
diff --git a/runtime/bin/socket_linux.cc b/runtime/bin/socket_linux.cc
index 4740771..ff6c191 100644
--- a/runtime/bin/socket_linux.cc
+++ b/runtime/bin/socket_linux.cc
@@ -264,3 +264,15 @@
}
return socket;
}
+
+
+void Socket::Close(intptr_t fd) {
+ ASSERT(fd >= 0);
+ int err = TEMP_FAILURE_RETRY(close(fd));
+ if (err != 0) {
+ const int kBufferSize = 1024;
+ char error_message[kBufferSize];
+ strerror_r(errno, error_message, kBufferSize);
+ Log::PrintErr("%s\n", error_message);
+ }
+}
diff --git a/runtime/bin/socket_macos.cc b/runtime/bin/socket_macos.cc
index 07a9edd..20364cb 100644
--- a/runtime/bin/socket_macos.cc
+++ b/runtime/bin/socket_macos.cc
@@ -250,3 +250,15 @@
}
return socket;
}
+
+
+void Socket::Close(intptr_t fd) {
+ ASSERT(fd >= 0);
+ int err = TEMP_FAILURE_RETRY(close(fd));
+ if (err != 0) {
+ const int kBufferSize = 1024;
+ char error_message[kBufferSize];
+ strerror_r(errno, error_message, kBufferSize);
+ Log::PrintErr("%s\n", error_message);
+ }
+}
diff --git a/runtime/bin/socket_win.cc b/runtime/bin/socket_win.cc
index b252cff..a33d703 100644
--- a/runtime/bin/socket_win.cc
+++ b/runtime/bin/socket_win.cc
@@ -273,3 +273,9 @@
ListenSocket* listen_socket = new ListenSocket(s);
return reinterpret_cast<intptr_t>(listen_socket);
}
+
+
+void Socket::Close(intptr_t fd) {
+ ClientSocket* client_socket = reinterpret_cast<ClientSocket*>(fd);
+ client_socket->close();
+}
diff --git a/runtime/embedders/openglui/build_skia.sh b/runtime/embedders/openglui/build_skia.sh
index 34b0bb9..92b30ea 100755
--- a/runtime/embedders/openglui/build_skia.sh
+++ b/runtime/embedders/openglui/build_skia.sh
@@ -1,4 +1,4 @@
-#!/bin/sh
+#!/bin/bash
function usage {
echo "usage: $0 [ --help ] [ --android ] [ --arm | --x86] [--clean] [<Dart directory>]"
diff --git a/runtime/lib/array.dart b/runtime/lib/array.dart
index 3b457fa..3ce453b 100644
--- a/runtime/lib/array.dart
+++ b/runtime/lib/array.dart
@@ -116,6 +116,10 @@
return IterableMixinWorkaround.where(this, f);
}
+ Iterable expand(Iterable f(E element)) {
+ return IterableMixinWorkaround.expand(this, f);
+ }
+
Iterable<E> take(int n) {
return IterableMixinWorkaround.takeList(this, n);
}
@@ -350,6 +354,10 @@
return IterableMixinWorkaround.where(this, f);
}
+ Iterable expand(Iterable f(E element)) {
+ return IterableMixinWorkaround.expand(this, f);
+ }
+
Iterable<E> take(int n) {
return IterableMixinWorkaround.takeList(this, n);
}
diff --git a/runtime/lib/byte_array.dart b/runtime/lib/byte_array.dart
index 906259c..14b1b17 100644
--- a/runtime/lib/byte_array.dart
+++ b/runtime/lib/byte_array.dart
@@ -246,10 +246,14 @@
return IterableMixinWorkaround.reduce(this, initialValue, combine);
}
- Collection where(bool f(element)) {
+ Collection where(bool f(int element)) {
return IterableMixinWorkaround.where(this, f);
}
+ Iterable expand(Iterable f(int element)) {
+ return IterableMixinWorkaround.expand(this, f);
+ }
+
Iterable<int> take(int n) {
return IterableMixinWorkaround.takeList(this, n);
}
diff --git a/runtime/lib/double.cc b/runtime/lib/double.cc
index 2d3c5f8..e133681 100644
--- a/runtime/lib/double.cc
+++ b/runtime/lib/double.cc
@@ -79,12 +79,13 @@
args.SetAt(0, String::Handle(String::New(error_msg)));
Exceptions::ThrowByType(Exceptions::kUnsupported, args);
}
- if ((Smi::kMinValue <= val) && (val <= Smi::kMaxValue)) {
- return Smi::New(static_cast<intptr_t>(val));
- } else if ((Mint::kMinValue <= val) && (val <= Mint::kMaxValue)) {
- return Mint::New(static_cast<int64_t>(val));
+ const Bigint& big = Bigint::Handle(BigintOperations::NewFromDouble(val));
+ if (BigintOperations::FitsIntoSmi(big)) {
+ return BigintOperations::ToSmi(big);
+ } else if (BigintOperations::FitsIntoMint(big)) {
+ return Mint::New(BigintOperations::ToMint(big));
} else {
- return BigintOperations::NewFromDouble(val);
+ return big.raw();
}
}
diff --git a/runtime/lib/growable_array.dart b/runtime/lib/growable_array.dart
index 137a583..bb87177 100644
--- a/runtime/lib/growable_array.dart
+++ b/runtime/lib/growable_array.dart
@@ -258,6 +258,10 @@
return IterableMixinWorkaround.where(this, f);
}
+ Iterable expand(Iterable f(T element)) {
+ return IterableMixinWorkaround.expand(this, f);
+ }
+
Iterable<T> take(int n) {
return IterableMixinWorkaround.takeList(this, n);
}
diff --git a/runtime/lib/isolate.cc b/runtime/lib/isolate.cc
index 7ed2000..e7edbe0 100644
--- a/runtime/lib/isolate.cc
+++ b/runtime/lib/isolate.cc
@@ -477,7 +477,6 @@
if (!CanonicalizeUri(arguments->isolate(), root_lib, uri,
&canonical_uri, &error)) {
const String& msg = String::Handle(String::New(error));
- free(error);
ThrowIsolateSpawnException(msg);
}
diff --git a/runtime/lib/stopwatch_patch.dart b/runtime/lib/stopwatch_patch.dart
index 19645d1..2bdc2c5 100644
--- a/runtime/lib/stopwatch_patch.dart
+++ b/runtime/lib/stopwatch_patch.dart
@@ -4,7 +4,7 @@
// A VM patch of the stopwatch part of dart:core.
-patch class _StopwatchImpl {
+patch class Stopwatch {
// Returns the current clock tick.
/* patch */ static int _now() native "Stopwatch_now";
diff --git a/runtime/tests/vm/dart/byte_array_optimized_test.dart b/runtime/tests/vm/dart/byte_array_optimized_test.dart
new file mode 100644
index 0000000..803944d
--- /dev/null
+++ b/runtime/tests/vm/dart/byte_array_optimized_test.dart
@@ -0,0 +1,2214 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Library tag to be able to run in html test framework.
+library byte_array_test;
+
+import 'dart:scalarlist';
+
+// This test exercises optimized [] and []= operators
+// on byte array views.
+class OptimizedByteArrayTest {
+ static testInt8ListImpl(Int8List array) {
+ Expect.isTrue(array is List<int>);
+ Expect.equals(10, array.length);
+ Expect.equals(1, array.bytesPerElement());
+ Expect.equals(10, array.lengthInBytes());
+ Expect.listEquals([0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0],
+ array);
+ Expect.throws(() { array[-1] = 0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { return array[-1]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { array[10]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { array[10] = 0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { array.add(0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.addAll([0]); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.addLast(0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.clear(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.insertRange(0, array.length, 0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.length = 0; },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.removeLast(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.removeRange(0, array.length - 1); },
+ (e) { return e is UnsupportedError; });
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = 1 + i;
+ }
+ Expect.listEquals([1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10],
+ array);
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = 0x100 + i;
+ }
+ Expect.listEquals([0, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9],
+ array);
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = -10 + i;
+ }
+ Expect.listEquals([-10, -9, -8, -7, -6,
+ -5, -4, -3, -2, -1],
+ array);
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = 0x7F - i;
+ }
+ Expect.listEquals([127, 126, 125, 124, 123,
+ 122, 121, 120, 119, 118],
+ array);
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = -0x80 + i;
+ }
+ Expect.listEquals([-128, -127, -126, -125, -124,
+ -123, -122, -121, -120, -119],
+ array);
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = i;
+ }
+ var copy = array.getRange(0, array.length);
+ Expect.isFalse(copy === array);
+ Expect.isTrue(copy is Int8List);
+ Expect.equals(10, copy.length);
+ Expect.listEquals(array, copy);
+ var empty = array.getRange(array.length, 0);
+ Expect.equals(0, empty.length);
+ var region = array.getRange(3, array.length - 6);
+ Expect.isTrue(copy is Int8List);
+ Expect.equals(4, region.length);
+ Expect.listEquals([3, 4, 5, 6], region);
+ array.setRange(3, 4, [-128, 0, 1, 127]);
+ Expect.listEquals([0, 1, 2, -128, 0, 1, 127, 7, 8, 9],
+ array);
+ }
+ static testInt8List() {
+ Expect.throws(() { new Int8List(-1); },
+ (e) { return e is ArgumentError; });
+ var array = new Int8List(10);
+ testInt8ListImpl(array);
+ }
+
+ static testUint8ListImpl(Uint8List array) {
+ Expect.isTrue(array is List<int>);
+ Expect.equals(10, array.length);
+ Expect.equals(1, array.bytesPerElement());
+ Expect.equals(10, array.lengthInBytes());
+ Expect.listEquals([0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0],
+ array);
+ Expect.throws(() { array[-1] = 0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { return array[-1]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { array[10]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { array[10] = 0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { array.add(0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.addAll([0]); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.addLast(0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.clear(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.insertRange(0, array.length, 0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.length = 0; },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.removeLast(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.removeRange(0, array.length - 1); },
+ (e) { return e is UnsupportedError; });
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = 1 + i;
+ }
+ Expect.listEquals([1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10],
+ array);
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = 0x100 + i;
+ }
+ Expect.listEquals([0, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9],
+ array);
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = 0xFF - i;
+ }
+ Expect.listEquals([0xFF, 0xFE, 0xFD, 0xFC, 0xFB,
+ 0xFA, 0xF9, 0xF8, 0xF7, 0xF6],
+ array);
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = i;
+ }
+ var copy = array.getRange(0, array.length);
+ Expect.isFalse(copy === array);
+ Expect.isTrue(copy is Uint8List);
+ Expect.equals(10, copy.length);
+ Expect.listEquals(array, copy);
+ var empty = array.getRange(array.length, 0);
+ Expect.equals(0, empty.length);
+ var region = array.getRange(3, array.length - 6);
+ Expect.isTrue(copy is Uint8List);
+ Expect.equals(4, region.length);
+ Expect.listEquals([3, 4, 5, 6], region);
+ array.setRange(3, 4, [257, 0, 1, 255]);
+ Expect.listEquals([0, 1, 2, 1, 0, 1, 255, 7, 8, 9],
+ array);
+ }
+
+ static testUint8List() {
+ Expect.throws(() { new Uint8List(-1); },
+ (e) { return e is ArgumentError; });
+ var array = new Uint8List(10);
+ testUint8ListImpl(array);
+ }
+
+ static testInt16ListImpl(Int16List array) {
+ Expect.isTrue(array is List<int>);
+ Expect.equals(10, array.length);
+ Expect.equals(2, array.bytesPerElement());
+ Expect.equals(20, array.lengthInBytes());
+ Expect.listEquals([0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0],
+ array);
+ Expect.throws(() { array[-1] = 0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { return array[-1]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { array[10]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { array[10] = 0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { array.add(0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.addAll([0]); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.addLast(0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.clear(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.insertRange(0, array.length, 0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.length = 0; },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.removeLast(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.removeRange(0, array.length - 1); },
+ (e) { return e is UnsupportedError; });
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = 1 + i;
+ }
+ Expect.listEquals([1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10],
+ array);
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = 0x10000 + i;
+ }
+ Expect.listEquals([0, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9],
+ array);
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = -10 + i;
+ }
+ Expect.listEquals([-10, -9, -8, -7, -6,
+ -5, -4, -3, -2, -1],
+ array);
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = 0x7FFF - i;
+ }
+ Expect.listEquals([0x7FFF, 0x7FFE, 0x7FFD, 0x7FFC, 0x7FFB,
+ 0x7FFA, 0x7FF9, 0x7FF8, 0x7FF7, 0x7FF6],
+ array);
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = -0x8000 + i;
+ }
+ Expect.listEquals([-0x8000, -0x7FFF, -0x7FFE, -0x7FFD, -0x7FFC,
+ -0x7FFB, -0x7FFA, -0x7FF9, -0x7FF8, -0x7FF7],
+ array);
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = i;
+ }
+ var copy = array.getRange(0, array.length);
+ Expect.isFalse(copy === array);
+ Expect.isTrue(copy is Int16List);
+ Expect.equals(10, copy.length);
+ Expect.listEquals(array, copy);
+ var empty = array.getRange(array.length, 0);
+ Expect.equals(0, empty.length);
+ var region = array.getRange(3, array.length - 6);
+ Expect.isTrue(copy is Int16List);
+ Expect.equals(4, region.length);
+ Expect.listEquals([3, 4, 5, 6], region);
+ array.setRange(3, 4, [-32768, 0, 1, 32767]);
+ Expect.listEquals([0, 1, 2, -32768, 0, 1, 32767, 7, 8, 9],
+ array);
+ }
+
+ static testInt16List() {
+ Expect.throws(() { new Int16List(-1); },
+ (e) { return e is ArgumentError; });
+ var array = new Int16List(10);
+ testInt16ListImpl(array);
+ }
+
+ static testUint16ListImpl(Uint16List array) {
+ Expect.isTrue(array is List<int>);
+ Expect.equals(10, array.length);
+ Expect.equals(2, array.bytesPerElement());
+ Expect.equals(20, array.lengthInBytes());
+ Expect.listEquals([0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0],
+ array);
+ Expect.throws(() { array[-1] = 0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { return array[-1]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { array[10]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { array[10] = 0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { array.add(0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.addAll([0]); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.addLast(0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.clear(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.insertRange(0, array.length, 0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.length = 0; },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.removeLast(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.removeRange(0, array.length - 1); },
+ (e) { return e is UnsupportedError; });
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = 1 + i;
+ }
+ Expect.listEquals([1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10],
+ array);
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = 0x10000 + i;
+ }
+ Expect.listEquals([0, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9],
+ array);
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = 0xFFFF - i;
+ }
+ Expect.listEquals([0xFFFF, 0xFFFE, 0xFFFD, 0xFFFC, 0xFFFB,
+ 0xFFFA, 0xFFF9, 0xFFF8, 0xFFF7, 0xFFF6],
+ array);
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = i;
+ }
+ var copy = array.getRange(0, array.length);
+ Expect.isFalse(copy === array);
+ Expect.isTrue(copy is Uint16List);
+ Expect.equals(10, copy.length);
+ Expect.listEquals(array, copy);
+ var empty = array.getRange(array.length, 0);
+ Expect.equals(0, empty.length);
+ var region = array.getRange(3, array.length - 6);
+ Expect.isTrue(copy is Uint16List);
+ Expect.equals(4, region.length);
+ Expect.listEquals([3, 4, 5, 6], region);
+ array.setRange(3, 4, [0x10001, 0, 1, 0xFFFF]);
+ Expect.listEquals([0, 1, 2, 1, 0, 1, 0xFFFF, 7, 8, 9],
+ array);
+ }
+
+ static testUint16List() {
+ Expect.throws(() { new Uint16List(-1); },
+ (e) { return e is ArgumentError; });
+ var array = new Uint16List(10);
+ testUint16ListImpl(array);
+ }
+
+ static testInt32ListImpl(Int32List array) {
+ Expect.isTrue(array is List<int>);
+ Expect.equals(10, array.length);
+ Expect.equals(4, array.bytesPerElement());
+ Expect.equals(40, array.lengthInBytes());
+ Expect.listEquals([0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0],
+ array);
+ Expect.throws(() { array[-1] = 0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { return array[-1]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { array[10]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { array[10] = 0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { array.add(0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.addAll([0]); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.addLast(0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.clear(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.insertRange(0, array.length, 0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.length = 0; },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.removeLast(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.removeRange(0, array.length - 1); },
+ (e) { return e is UnsupportedError; });
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = 1 + i;
+ }
+ Expect.listEquals([1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10],
+ array);
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = 0x100000000 + i;
+ }
+ Expect.listEquals([0, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9],
+ array);
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = -10 + i;
+ }
+ Expect.listEquals([-10, -9, -8, -7, -6,
+ -5, -4, -3, -2, -1],
+ array);
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = 0x7FFFFFFF - i;
+ }
+ Expect.listEquals([0x7FFFFFFF, 0x7FFFFFFE,
+ 0x7FFFFFFD, 0x7FFFFFFC,
+ 0x7FFFFFFB, 0x7FFFFFFA,
+ 0x7FFFFFF9, 0x7FFFFFF8,
+ 0x7FFFFFF7, 0x7FFFFFF6],
+ array);
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = -0x80000000 + i;
+ }
+ Expect.listEquals([-0x80000000, -0x7FFFFFFF,
+ -0x7FFFFFFE, -0x7FFFFFFD,
+ -0x7FFFFFFC, -0x7FFFFFFB,
+ -0x7FFFFFFA, -0x7FFFFFF9,
+ -0x7FFFFFF8, -0x7FFFFFF7],
+ array);
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = i;
+ }
+ var copy = array.getRange(0, array.length);
+ Expect.isFalse(copy === array);
+ Expect.isTrue(copy is Int32List);
+ Expect.equals(10, copy.length);
+ Expect.listEquals(array, copy);
+ var empty = array.getRange(array.length, 0);
+ Expect.equals(0, empty.length);
+ var region = array.getRange(3, array.length - 6);
+ Expect.isTrue(copy is Int32List);
+ Expect.equals(4, region.length);
+ Expect.listEquals([3, 4, 5, 6], region);
+ array.setRange(3, 4, [-0x80000000, 0, 1, 0x7FFFFFFF]);
+ Expect.listEquals([0, 1, 2, -0x80000000, 0, 1, 0x7FFFFFFF, 7, 8, 9],
+ array);
+ }
+
+ static testInt32List() {
+ Expect.throws(() { new Int32List(-1); },
+ (e) { return e is ArgumentError; });
+ var array = new Int32List(10);
+ testInt32ListImpl(array);
+ }
+
+ static testUint32ListImpl(Uint32List array) {
+ Expect.isTrue(array is List<int>);
+ Expect.equals(10, array.length);
+ Expect.equals(4, array.bytesPerElement());
+ Expect.equals(40, array.lengthInBytes());
+ Expect.listEquals([0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0],
+ array);
+ Expect.throws(() { array[-1] = 0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { return array[-1]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { array[10]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { array[10] = 0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { array.add(0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.addAll([0]); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.addLast(0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.clear(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.insertRange(0, array.length, 0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.length = 0; },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.removeLast(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.removeRange(0, array.length - 1); },
+ (e) { return e is UnsupportedError; });
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = 1 + i;
+ }
+ Expect.listEquals([1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10],
+ array);
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = 0x100000000 + i;
+ }
+ Expect.listEquals([0, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9],
+ array);
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = 0xFFFFFFFF - i;
+ }
+ Expect.listEquals([0xFFFFFFFF, 0xFFFFFFFE,
+ 0xFFFFFFFD, 0xFFFFFFFC,
+ 0xFFFFFFFB, 0xFFFFFFFA,
+ 0xFFFFFFF9, 0xFFFFFFF8,
+ 0xFFFFFFF7, 0xFFFFFFF6],
+ array);
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = i;
+ }
+ var copy = array.getRange(0, array.length);
+ Expect.isFalse(copy === array);
+ Expect.isTrue(copy is Uint32List);
+ Expect.equals(10, copy.length);
+ Expect.listEquals(array, copy);
+ var empty = array.getRange(array.length, 0);
+ Expect.equals(0, empty.length);
+ var region = array.getRange(3, array.length - 6);
+ Expect.isTrue(copy is Uint32List);
+ Expect.equals(4, region.length);
+ Expect.listEquals([3, 4, 5, 6], region);
+ array.setRange(3, 4, [0x100000001, 0, 1, 0xFFFFFFFF]);
+ Expect.listEquals([0, 1, 2, 1, 0, 1, 0xFFFFFFFF, 7, 8, 9],
+ array);
+ }
+
+ static testUint32List() {
+ Expect.throws(() { new Uint32List(-1); },
+ (e) { return e is ArgumentError; });
+ Expect.throws(() { new Uint32List(-1); },
+ (e) { return e is ArgumentError; });
+ var array = new Uint32List(10);
+ testUint32ListImpl(array);
+
+ }
+
+ static testInt64ListImpl(Int64List array) {
+ Expect.isTrue(array is List<int>);
+ Expect.equals(10, array.length);
+ Expect.equals(8, array.bytesPerElement());
+ Expect.equals(80, array.lengthInBytes());
+ Expect.listEquals([0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0],
+ array);
+ Expect.throws(() { array[-1] = 0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { return array[-1]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { array[10]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { array[10] = 0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { array.add(0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.addAll([0]); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.addLast(0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.clear(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.insertRange(0, array.length, 0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.length = 0; },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.removeLast(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.removeRange(0, array.length - 1); },
+ (e) { return e is UnsupportedError; });
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = 1 + i;
+ }
+ Expect.listEquals([1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10],
+ array);
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = 0x10000000000000000 + i;
+ }
+ Expect.listEquals([0, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9],
+ array);
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = -10 + i;
+ }
+ Expect.listEquals([-10, -9, -8, -7, -6,
+ -5, -4, -3, -2, -1],
+ array);
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = 0x7FFFFFFFFFFFFFFF - i;
+ }
+ Expect.listEquals([0x7FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFE,
+ 0x7FFFFFFFFFFFFFFD, 0x7FFFFFFFFFFFFFFC,
+ 0x7FFFFFFFFFFFFFFB, 0x7FFFFFFFFFFFFFFA,
+ 0x7FFFFFFFFFFFFFF9, 0x7FFFFFFFFFFFFFF8,
+ 0x7FFFFFFFFFFFFFF7, 0x7FFFFFFFFFFFFFF6],
+ array);
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = -0x8000000000000000 + i;
+ }
+ Expect.listEquals([-0x8000000000000000, -0x7FFFFFFFFFFFFFFF,
+ -0x7FFFFFFFFFFFFFFE, -0x7FFFFFFFFFFFFFFD,
+ -0x7FFFFFFFFFFFFFFC, -0x7FFFFFFFFFFFFFFB,
+ -0x7FFFFFFFFFFFFFFA, -0x7FFFFFFFFFFFFFF9,
+ -0x7FFFFFFFFFFFFFF8, -0x7FFFFFFFFFFFFFF7],
+ array);
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = i;
+ }
+ var copy = array.getRange(0, array.length);
+ Expect.isFalse(copy === array);
+ Expect.isTrue(copy is Int64List);
+ Expect.equals(10, copy.length);
+ Expect.listEquals(array, copy);
+ var empty = array.getRange(array.length, 0);
+ Expect.equals(0, empty.length);
+ var region = array.getRange(3, array.length - 6);
+ Expect.isTrue(copy is Int64List);
+ Expect.equals(4, region.length);
+ Expect.listEquals([3, 4, 5, 6], region);
+ array.setRange(3, 4, [-0x8000000000000000, 0, 1, 0x7FFFFFFFFFFFFFFF]);
+ Expect.listEquals([0, 1, 2, -0x8000000000000000, 0,
+ 1, 0x7FFFFFFFFFFFFFFF, 7, 8, 9],
+ array);
+ }
+
+ static testInt64List() {
+ Expect.throws(() { new Int64List(-1); },
+ (e) { return e is ArgumentError; });
+ var array = new Int64List(10);
+ testInt64ListImpl(array);
+ }
+
+ static testUint64ListImpl(Uint64List array) {
+ Expect.isTrue(array is List<int>);
+ Expect.equals(10, array.length);
+ Expect.equals(8, array.bytesPerElement());
+ Expect.equals(80, array.lengthInBytes());
+ Expect.listEquals([0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0],
+ array);
+ Expect.throws(() { array[-1] = 0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { return array[-1]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { array[10]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { array[10] = 0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { array.add(0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.addAll([0]); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.addLast(0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.clear(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.insertRange(0, array.length, 0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.length = 0; },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.removeLast(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.removeRange(0, array.length - 1); },
+ (e) { return e is UnsupportedError; });
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = 1 + i;
+ }
+ Expect.listEquals([1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10],
+ array);
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = 0x10000000000000000 + i;
+ }
+ Expect.listEquals([0, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9],
+ array);
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = 0xFFFFFFFFFFFFFFFF - i;
+ }
+ Expect.listEquals([0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFE,
+ 0xFFFFFFFFFFFFFFFD, 0xFFFFFFFFFFFFFFFC,
+ 0xFFFFFFFFFFFFFFFB, 0xFFFFFFFFFFFFFFFA,
+ 0xFFFFFFFFFFFFFFF9, 0xFFFFFFFFFFFFFFF8,
+ 0xFFFFFFFFFFFFFFF7, 0xFFFFFFFFFFFFFFF6],
+ array);
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = i;
+ }
+ var copy = array.getRange(0, array.length);
+ Expect.isFalse(copy === array);
+ Expect.isTrue(copy is Uint64List);
+ Expect.equals(10, copy.length);
+ Expect.listEquals(array, copy);
+ var empty = array.getRange(array.length, 0);
+ Expect.equals(0, empty.length);
+ var region = array.getRange(3, array.length - 6);
+ Expect.isTrue(copy is Uint64List);
+ Expect.equals(4, region.length);
+ Expect.listEquals([3, 4, 5, 6], region);
+ array.setRange(3, 4, [0x10000000000000001, 0, 1, 0xFFFFFFFFFFFFFFFF]);
+ Expect.listEquals([0, 1, 2, 1, 0, 1, 0xFFFFFFFFFFFFFFFF, 7, 8, 9],
+ array);
+ }
+
+ static testUint64List() {
+ Expect.throws(() { new Uint64List(-1); },
+ (e) { return e is ArgumentError; });
+ var array = new Uint64List(10);
+ testUint64ListImpl(array);
+ }
+
+ static testFloat32ListImpl(Float32List array) {
+ Expect.isTrue(array is List<double>);
+ Expect.equals(10, array.length);
+ Expect.equals(4, array.bytesPerElement());
+ Expect.equals(40, array.lengthInBytes());
+ Expect.listEquals([0.0, 0.0, 0.0, 0.0, 0.0,
+ 0.0, 0.0, 0.0, 0.0, 0.0],
+ array);
+ Expect.throws(() { array[-1] = 0.0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { return array[-1]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { array[10]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { array[10] = 0.0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { array.add(0.0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.addAll([0]); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.addLast(0.0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.clear(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.insertRange(0, array.length, 0.0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.length = 0; },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.removeLast(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.removeRange(0, array.length - 1); },
+ (e) { return e is UnsupportedError; });
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = 1.0 + i;
+ }
+ Expect.listEquals([1.0, 2.0, 3.0, 4.0, 5.0,
+ 6.0, 7.0, 8.0, 9.0, 10.0],
+ array);
+ // TODO: min, max, and round
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = i * 1.0;
+ }
+ var copy = array.getRange(0, array.length);
+ Expect.isFalse(copy === array);
+ Expect.isTrue(copy is Float32List);
+ Expect.equals(10, copy.length);
+ Expect.listEquals(array, copy);
+ var empty = array.getRange(array.length, 0);
+ Expect.equals(0, empty.length);
+ var region = array.getRange(3, array.length - 6);
+ Expect.isTrue(copy is Float32List);
+ Expect.equals(4, region.length);
+ Expect.listEquals([3.0, 4.0, 5.0, 6.0], region);
+ array.setRange(3, 4, [double.NEGATIVE_INFINITY, 0.0, 1.0, double.INFINITY]);
+ Expect.listEquals([0.0, 1.0, 2.0, double.NEGATIVE_INFINITY, 0.0,
+ 1.0, double.INFINITY, 7.0, 8.0, 9.0],
+ array);
+ }
+
+ static testFloat32List() {
+ Expect.throws(() { new Float32List(-1); },
+ (e) { return e is ArgumentError; });
+ var array = new Float32List(10);
+ testFloat32ListImpl(array);
+ }
+
+ static testFloat64ListImpl(Float64List array) {
+ Expect.isTrue(array is List<double>);
+ Expect.equals(10, array.length);
+ Expect.equals(8, array.bytesPerElement());
+ Expect.equals(80, array.lengthInBytes());
+ Expect.listEquals([0.0, 0.0, 0.0, 0.0, 0.0,
+ 0.0, 0.0, 0.0, 0.0, 0.0],
+ array);
+ Expect.throws(() { array[-1] = 0.0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { return array[-1]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { array[10]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { array[10] = 0.0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { array.add(0.0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.addAll([0]); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.addLast(0.0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.clear(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.insertRange(0, array.length, 0.0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.length = 0; },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.removeLast(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.removeRange(0, array.length - 1); },
+ (e) { return e is UnsupportedError; });
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = 1.0 + i;
+ }
+ Expect.listEquals([1.0, 2.0, 3.0, 4.0, 5.0,
+ 6.0, 7.0, 8.0, 9.0, 10.0],
+ array);
+ // TODO: min, max
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = i * 1.0;
+ }
+ var copy = array.getRange(0, array.length);
+ Expect.isFalse(copy === array);
+ Expect.isTrue(copy is Float64List);
+ Expect.equals(10, copy.length);
+ Expect.listEquals(array, copy);
+ var empty = array.getRange(array.length, 0);
+ Expect.equals(0, empty.length);
+ var region = array.getRange(3, array.length - 6);
+ Expect.isTrue(copy is Float64List);
+ Expect.equals(4, region.length);
+ Expect.listEquals([3.0, 4.0, 5.0, 6.0], region);
+ array.setRange(3, 4, [double.NEGATIVE_INFINITY, 0.0, 1.0, double.INFINITY]);
+ Expect.listEquals([0.0, 1.0, 2.0, double.NEGATIVE_INFINITY, 0.0,
+ 1.0, double.INFINITY, 7.0, 8.0, 9.0],
+ array);
+ }
+
+ static testFloat64List() {
+ Expect.throws(() { new Float64List(-1); },
+ (e) { return e is ArgumentError; });
+ var array = new Float64List(10);
+ testFloat64ListImpl(array);
+ }
+
+ static testInt8ListViewImpl(var array) {
+ Expect.equals(12, array.length);
+ Expect.equals(1, array.bytesPerElement());
+ Expect.equals(12, array.lengthInBytes());
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = 0xFF;
+ }
+ Expect.throws(() { new Int8List.view(array.asByteArray(), -1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Int8List.view(array.asByteArray(), 0, -1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Int8List.view(array.asByteArray(),
+ array.lengthInBytes() + 1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Int8List.view(array.asByteArray(),
+ 0, array.length + 1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Int8List.view(array.asByteArray(),
+ array.length - 1, 2); },
+ (e) { return e is RangeError; });
+ var empty = new Int8List.view(array.asByteArray(),
+ array.lengthInBytes());
+ Expect.isTrue(empty is List<int>);
+ Expect.isTrue(empty is Int8List);
+ Expect.equals(0, empty.length);
+ var whole = new Int8List.view(array.asByteArray());
+ Expect.isTrue(whole is List<int>);
+ Expect.isTrue(whole is Int8List);
+ Expect.equals(12, whole.length);
+ var view = new Int8List.view(array.asByteArray(), 1, array.length - 2);
+ Expect.isTrue(view is List<int>);
+ Expect.isTrue(view is Int8List);
+ Expect.equals(10, view.length);
+ Expect.equals(1, view.bytesPerElement());
+ Expect.equals(10, view.lengthInBytes());
+ Expect.listEquals([-1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1],
+ view);
+ Expect.throws(() { view[-1] = 0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { return view[-1]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { view[view.length]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { view[10] = 0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { view.add(0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.addAll([0]); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.addLast(0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.clear(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.insertRange(0, view.length, 0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.length = 0; },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.removeLast(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.removeRange(0, view.length - 1); },
+ (e) { return e is UnsupportedError; });
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = 1 + i;
+ }
+ Expect.listEquals([1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10],
+ view);
+ Expect.listEquals([0xFF, 1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10, 0xFF],
+ array);
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = 0x100 + i;
+ }
+ Expect.listEquals([0, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9],
+ view);
+ Expect.listEquals([0xFF, 0, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 0xFF],
+ array);
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = -10 + i;
+ }
+ Expect.listEquals([-10, -9, -8, -7, -6,
+ -5, -4, -3, -2, -1],
+ view);
+ Expect.listEquals([0xFF, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA,
+ 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0xFF],
+ array);
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = 0x7F - i;
+ }
+ Expect.listEquals([127, 126, 125, 124, 123,
+ 122, 121, 120, 119, 118],
+ view);
+ Expect.listEquals([0xFF, 127, 126, 125, 124, 123,
+ 122, 121, 120, 119, 118, 0xFF],
+ array);
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = -0x80 + i;
+ }
+ Expect.listEquals([-128, -127, -126, -125, -124,
+ -123, -122, -121, -120, -119],
+ view);
+ Expect.listEquals([0xFF, 0x80, 0x81, 0x82, 0x83, 0x84,
+ 0x85, 0x86, 0x87, 0x88, 0x89, 0xFF],
+ array);
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = i;
+ }
+ var copy = view.getRange(0, view.length);
+ Expect.isFalse(copy === view);
+ Expect.isTrue(copy is Int8List);
+ Expect.equals(10, copy.length);
+ Expect.listEquals(view, copy);
+ var region = view.getRange(3, view.length - 6);
+ Expect.isTrue(copy is Int8List);
+ Expect.equals(4, region.length);
+ Expect.listEquals([3, 4, 5, 6], region);
+ view.setRange(3, 4, [-128, 0, 1, 127]);
+ Expect.listEquals([0, 1, 2, -128, 0, 1, 127, 7, 8, 9],
+ view);
+ Expect.listEquals([0xFF, 0, 1, 2, 128, 0, 1, 127, 7, 8, 9, 0xFF],
+ array);
+ }
+ static testInt8ListView() {
+ var array = new Uint8List(12);
+ testInt8ListViewImpl(array);
+ }
+
+ static testUint8ListViewImpl(var array) {
+ Expect.isTrue(array is List<int>);
+ Expect.equals(12, array.length);
+ Expect.equals(1, array.bytesPerElement());
+ Expect.equals(12, array.lengthInBytes());
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = -1;
+ }
+ Expect.throws(() { new Uint8List.view(array.asByteArray(), -1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Uint8List.view(array.asByteArray(), 0, -1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Uint8List.view(array.asByteArray(),
+ array.lengthInBytes() + 1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Uint8List.view(array.asByteArray(),
+ 0, array.length + 1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Uint8List.view(array.asByteArray(),
+ array.length - 1, 2); },
+ (e) { return e is RangeError; });
+ var empty = new Uint8List.view(array.asByteArray(),
+ array.lengthInBytes());
+ Expect.isTrue(empty is List<int>);
+ Expect.isTrue(empty is Uint8List);
+ Expect.equals(0, empty.length);
+ var whole = new Uint8List.view(array.asByteArray());
+ Expect.isTrue(whole is List<int>);
+ Expect.isTrue(whole is Uint8List);
+ Expect.equals(12, whole.length);
+ var view = new Uint8List.view(array.asByteArray(), 1, array.length - 2);
+ Expect.isTrue(view is List<int>);
+ Expect.isTrue(view is Uint8List);
+ Expect.equals(10, view.length);
+ Expect.equals(1, view.bytesPerElement());
+ Expect.equals(10, view.lengthInBytes());
+ Expect.listEquals([0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
+ view);
+ Expect.throws(() { view[-1] = 0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { return view[-1]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { view[view.length]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { view[view.length] = 0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { view.add(0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.addAll([0]); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.addLast(0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.clear(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.insertRange(0, view.length, 0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.length = 0; },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.removeLast(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.removeRange(0, view.length - 1); },
+ (e) { return e is UnsupportedError; });
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = 1 + i;
+ }
+ Expect.listEquals([1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10],
+ view);
+ Expect.listEquals([-1, 1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10, -1],
+ array);
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = 0x100 + i;
+ }
+ Expect.listEquals([0, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9],
+ view);
+ Expect.listEquals([-1, 0, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, -1],
+ array);
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = 0xFF - i;
+ }
+ Expect.listEquals([0xFF, 0xFE, 0xFD, 0xFC, 0xFB,
+ 0xFA, 0xF9, 0xF8, 0xF7, 0xF6],
+ view);
+ Expect.listEquals([-1, -1, -2, -3, -4, -5,
+ -6, -7, -8, -9, -10, -1],
+ array);
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = i;
+ }
+ var copy = view.getRange(0, view.length);
+ Expect.isFalse(copy === view);
+ Expect.isTrue(copy is Uint8List);
+ Expect.equals(10, copy.length);
+ Expect.listEquals(view, copy);
+ var region = view.getRange(3, view.length - 6);
+ Expect.isTrue(copy is Uint8List);
+ Expect.equals(4, region.length);
+ Expect.listEquals([3, 4, 5, 6], region);
+ view.setRange(3, 4, [257, 0, 1, 255]);
+ Expect.listEquals([0, 1, 2, 1, 0, 1, 255, 7, 8, 9],
+ view);
+ }
+
+ static testUint8ListView() {
+ var array = new Int8List(12);
+ testUint8ListViewImpl(array);
+ }
+
+ static testInt16ListViewImpl(var array) {
+ Expect.equals(24, array.length);
+ Expect.equals(1, array.bytesPerElement());
+ Expect.equals(24, array.lengthInBytes());
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = 0xFF;
+ }
+ Expect.throws(() { new Int16List.view(array.asByteArray(), -1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Int16List.view(array.asByteArray(), 0, -1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Int16List.view(array.asByteArray(),
+ array.lengthInBytes() + 1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Int16List.view(array.asByteArray(),
+ 0, array.length + 1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Int16List.view(array.asByteArray(),
+ array.length - 1, 2); },
+ (e) { return e is RangeError; });
+ var empty = new Int16List.view(array.asByteArray(),
+ array.lengthInBytes());
+ Expect.isTrue(empty is List<int>);
+ Expect.isTrue(empty is Int16List);
+ Expect.equals(0, empty.length);
+ var whole = new Int16List.view(array.asByteArray());
+ Expect.isTrue(whole is List<int>);
+ Expect.isTrue(whole is Int16List);
+ Expect.equals(12, whole.length);
+ var view = new Int16List.view(array.asByteArray(), 2, 10);
+ Expect.isTrue(view is List<int>);
+ Expect.isTrue(view is Int16List);
+ Expect.equals(10, view.length);
+ Expect.equals(2, view.bytesPerElement());
+ Expect.equals(20, view.lengthInBytes());
+ Expect.listEquals([-1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1],
+ view);
+ Expect.throws(() { view[-1] = 0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { return view[-1]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { view[view.length]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { view[10] = 0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { view.add(0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.addAll([0]); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.addLast(0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.clear(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.insertRange(0, view.length, 0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.length = 0; },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.removeLast(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.removeRange(0, view.length - 1); },
+ (e) { return e is UnsupportedError; });
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = 1 + i;
+ }
+ Expect.listEquals([1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10],
+ view);
+ Expect.listEquals([0xFF, 0xFF, 0x01, 0x00, 0x02, 0x00, 0x03, 0x00,
+ 0x04, 0x00, 0x05, 0x00, 0x06, 0x00, 0x07, 0x00,
+ 0x08, 0x00, 0x09, 0x00, 0x0A, 0x00, 0xFF, 0xFF],
+ array);
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = 0x10000 + i;
+ }
+ Expect.listEquals([0, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9],
+ view);
+ Expect.listEquals([0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00,
+ 0x03, 0x00, 0x04, 0x00, 0x05, 0x00, 0x06, 0x00,
+ 0x07, 0x00, 0x08, 0x00, 0x09, 0x00, 0xFF, 0xFF],
+ array);
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = -10 + i;
+ }
+ Expect.listEquals([-10, -9, -8, -7, -6,
+ -5, -4, -3, -2, -1],
+ view);
+ Expect.listEquals([0xFF, 0xFF, 0xF6, 0xFF, 0xF7, 0xFF, 0xF8, 0xFF,
+ 0xF9, 0xFF, 0xFA, 0xFF, 0xFB, 0xFF, 0xFC, 0xFF,
+ 0xFD, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
+ array);
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = 0x7FFF - i;
+ }
+ Expect.listEquals([0x7FFF, 0x7FFE, 0x7FFD, 0x7FFC, 0x7FFB,
+ 0x7FFA, 0x7FF9, 0x7FF8, 0x7FF7, 0x7FF6],
+ view);
+ Expect.listEquals([0xFF, 0xFF, 0xFF, 0x7F, 0xFE, 0x7F, 0xFD, 0x7F,
+ 0xFC, 0x7F, 0xFB, 0x7F, 0xFA, 0x7F, 0xF9, 0x7F,
+ 0xF8, 0x7F, 0xF7, 0x7F, 0xF6, 0x7F, 0xFF, 0xFF],
+ array);
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = -0x8000 + i;
+ }
+ Expect.listEquals([-0x8000, -0x7FFF, -0x7FFE, -0x7FFD, -0x7FFC,
+ -0x7FFB, -0x7FFA, -0x7FF9, -0x7FF8, -0x7FF7],
+ view);
+ Expect.listEquals([0xFF, 0xFF, 0x00, 0x80, 0x01, 0x80, 0x02, 0x80,
+ 0x03, 0x80, 0x04, 0x80, 0x05, 0x80, 0x06, 0x80,
+ 0x07, 0x80, 0x08, 0x80, 0x09, 0x80, 0xFF, 0xFF],
+ array);
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = i;
+ }
+ var copy = view.getRange(0, view.length);
+ Expect.isFalse(copy === view);
+ Expect.isTrue(copy is Int16List);
+ Expect.equals(10, copy.length);
+ Expect.listEquals(view, copy);
+ var region = view.getRange(3, view.length - 6);
+ Expect.isTrue(copy is Int16List);
+ Expect.equals(4, region.length);
+ Expect.listEquals([3, 4, 5, 6], region);
+ view.setRange(3, 4, [-32768, 0, 1, 32767]);
+ Expect.listEquals([0, 1, 2, -32768, 0, 1, 32767, 7, 8, 9],
+ view);
+ Expect.listEquals([0xFF, 0xFF, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00,
+ 0x00, 0x80, 0x00, 0x00, 0x01, 0x00, 0xFF, 0x7F,
+ 0x07, 0x00, 0x08, 0x00, 0x09, 0x00, 0xFF, 0xFF],
+ array);
+ }
+
+ static testInt16ListView() {
+ var array = new Uint8List(24);
+ testInt16ListViewImpl(array);
+ }
+
+ static testUint16ListViewImpl(var array) {
+ Expect.isTrue(array is List<int>);
+ Expect.equals(24, array.length);
+ Expect.equals(1, array.bytesPerElement());
+ Expect.equals(24, array.lengthInBytes());
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = -1;
+ }
+ Expect.throws(() { new Uint16List.view(array.asByteArray(), -1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Uint16List.view(array.asByteArray(), 0, -1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Uint16List.view(array.asByteArray(),
+ array.lengthInBytes() + 1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Uint16List.view(array.asByteArray(),
+ 0, array.length + 1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Uint16List.view(array.asByteArray(),
+ array.length - 1, 2); },
+ (e) { return e is RangeError; });
+ var empty = new Uint16List.view(array.asByteArray(),
+ array.lengthInBytes());
+ Expect.isTrue(empty is List<int>);
+ Expect.isTrue(empty is Uint16List);
+ Expect.equals(0, empty.length);
+ var whole = new Uint16List.view(array.asByteArray());
+ Expect.isTrue(whole is List<int>);
+ Expect.isTrue(whole is Uint16List);
+ Expect.equals(12, whole.length);
+ var view = new Uint16List.view(array.asByteArray(), 2, 10);
+ Expect.isTrue(view is List<int>);
+ Expect.isTrue(view is Uint16List);
+ Expect.equals(10, view.length);
+ Expect.equals(2, view.bytesPerElement());
+ Expect.equals(20, view.lengthInBytes());
+ Expect.listEquals([0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
+ 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF],
+ view);
+ Expect.throws(() { view[-1] = 0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { return view[-1]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { view[view.length]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { view[view.length] = 0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { view.add(0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.addAll([0]); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.addLast(0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.clear(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.insertRange(0, view.length, 0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.length = 0; },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.removeLast(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.removeRange(0, view.length - 1); },
+ (e) { return e is UnsupportedError; });
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = 1 + i;
+ }
+ Expect.listEquals([1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10],
+ view);
+ Expect.listEquals([-1, -1, 1, 0, 2, 0, 3, 0, 4, 0, 5, 0,
+ 6, 0, 7, 0, 8, 0, 9, 0, 10, 0, -1, -1],
+ array);
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = 0x10000 + i;
+ }
+ Expect.listEquals([0, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9],
+ view);
+ Expect.listEquals([-1, -1, 0, 0, 1, 0, 2, 0, 3, 0, 4, 0,
+ 5, 0, 6, 0, 7, 0, 8, 0, 9, 0, -1, -1],
+ array);
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = 0xFFFF - i;
+ }
+ Expect.listEquals([0xFFFF, 0xFFFE, 0xFFFD, 0xFFFC, 0xFFFB,
+ 0xFFFA, 0xFFF9, 0xFFF8, 0xFFF7, 0xFFF6],
+ view);
+ Expect.listEquals([-1, -1, -1, -1, -2, -1, -3, -1,
+ -4, -1, -5, -1, -6, -1, -7, -1,
+ -8, -1, -9, -1, -10, -1, -1, -1],
+ array);
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = i;
+ }
+ var copy = view.getRange(0, view.length);
+ Expect.isFalse(copy === view);
+ Expect.isTrue(copy is Uint16List);
+ Expect.equals(10, copy.length);
+ Expect.listEquals(view, copy);
+ var region = view.getRange(3, view.length - 6);
+ Expect.isTrue(copy is Uint16List);
+ Expect.equals(4, region.length);
+ Expect.listEquals([3, 4, 5, 6], region);
+ view.setRange(3, 4, [0x10001, 0, 1, 0xFFFF]);
+ Expect.listEquals([0, 1, 2, 1, 0, 1, 0xFFFF, 7, 8, 9],
+ view);
+ Expect.listEquals([-1, -1, 0, 0, 1, 0, 2, 0,
+ 1, 0, 0, 0, 1, 0, -1, -1,
+ 7, 0, 8, 0, 9, 0, -1, -1],
+ array);
+ }
+
+ static testUint16ListView() {
+ var array = new Int8List(24);
+ testUint16ListViewImpl(array);
+ }
+
+ static testInt32ListView() {
+ var array = new Uint8List(48);
+ Expect.equals(48, array.length);
+ Expect.equals(1, array.bytesPerElement());
+ Expect.equals(48, array.lengthInBytes());
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = 0xFF;
+ }
+ Expect.throws(() { new Int32List.view(array.asByteArray(), -1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Int32List.view(array.asByteArray(), 0, -1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Int32List.view(array.asByteArray(),
+ array.lengthInBytes() + 1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Int32List.view(array.asByteArray(),
+ 0, array.length + 1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Int32List.view(array.asByteArray(),
+ array.length - 1, 2); },
+ (e) { return e is RangeError; });
+ var empty = new Int32List.view(array.asByteArray(),
+ array.lengthInBytes());
+ Expect.isTrue(empty is List<int>);
+ Expect.isTrue(empty is Int32List);
+ Expect.equals(0, empty.length);
+ var whole = new Int32List.view(array.asByteArray());
+ Expect.isTrue(whole is List<int>);
+ Expect.isTrue(whole is Int32List);
+ Expect.equals(12, whole.length);
+ var view = new Int32List.view(array.asByteArray(), 4, 10);
+ Expect.isTrue(view is List<int>);
+ Expect.isTrue(view is Int32List);
+ Expect.equals(10, view.length);
+ Expect.equals(4, view.bytesPerElement());
+ Expect.equals(40, view.lengthInBytes());
+ Expect.listEquals([-1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1],
+ view);
+ Expect.throws(() { view[-1] = 0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { return view[-1]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { view[view.length]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { view[10] = 0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { view.add(0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.addAll([0]); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.addLast(0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.clear(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.insertRange(0, view.length, 0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.length = 0; },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.removeLast(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.removeRange(0, view.length - 1); },
+ (e) { return e is UnsupportedError; });
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = 1 + i;
+ }
+ Expect.listEquals([1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10],
+ view);
+ Expect.listEquals([0xFF, 0xFF, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00,
+ 0x0A, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF],
+ array);
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = 0x100000000 + i;
+ }
+ Expect.listEquals([0, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9],
+ view);
+ Expect.listEquals([0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF],
+ array);
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = -10 + i;
+ }
+ Expect.listEquals([-10, -9, -8, -7, -6,
+ -5, -4, -3, -2, -1],
+ view);
+ Expect.listEquals([0xFF, 0xFF, 0xFF, 0xFF, 0xF6, 0xFF, 0xFF, 0xFF,
+ 0xF7, 0xFF, 0xFF, 0xFF, 0xF8, 0xFF, 0xFF, 0xFF,
+ 0xF9, 0xFF, 0xFF, 0xFF, 0xFA, 0xFF, 0xFF, 0xFF,
+ 0xFB, 0xFF, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF,
+ 0xFD, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
+ array);
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = 0x7FFFFFFF - i;
+ }
+ Expect.listEquals([0x7FFFFFFF, 0x7FFFFFFE,
+ 0x7FFFFFFD, 0x7FFFFFFC,
+ 0x7FFFFFFB, 0x7FFFFFFA,
+ 0x7FFFFFF9, 0x7FFFFFF8,
+ 0x7FFFFFF7, 0x7FFFFFF6],
+ view);
+ Expect.listEquals([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,
+ 0xFE, 0xFF, 0xFF, 0x7F, 0xFD, 0xFF, 0xFF, 0x7F,
+ 0xFC, 0xFF, 0xFF, 0x7F, 0xFB, 0xFF, 0xFF, 0x7F,
+ 0xFA, 0xFF, 0xFF, 0x7F, 0xF9, 0xFF, 0xFF, 0x7F,
+ 0xF8, 0xFF, 0xFF, 0x7F, 0xF7, 0xFF, 0xFF, 0x7F,
+ 0xF6, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF],
+ array);
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = -0x80000000 + i;
+ }
+ Expect.listEquals([-0x80000000, -0x7FFFFFFF,
+ -0x7FFFFFFE, -0x7FFFFFFD,
+ -0x7FFFFFFC, -0x7FFFFFFB,
+ -0x7FFFFFFA, -0x7FFFFFF9,
+ -0x7FFFFFF8, -0x7FFFFFF7],
+ view);
+ Expect.listEquals([0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x80,
+ 0x01, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x80,
+ 0x03, 0x00, 0x00, 0x80, 0x04, 0x00, 0x00, 0x80,
+ 0x05, 0x00, 0x00, 0x80, 0x06, 0x00, 0x00, 0x80,
+ 0x07, 0x00, 0x00, 0x80, 0x08, 0x00, 0x00, 0x80,
+ 0x09, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFF, 0xFF],
+ array);
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = i;
+ }
+ var copy = view.getRange(0, view.length);
+ Expect.isFalse(copy === view);
+ Expect.isTrue(copy is Int32List);
+ Expect.equals(10, copy.length);
+ Expect.listEquals(view, copy);
+ var region = view.getRange(3, view.length - 6);
+ Expect.isTrue(copy is Int32List);
+ Expect.equals(4, region.length);
+ Expect.listEquals([3, 4, 5, 6], region);
+ view.setRange(3, 4, [-0x80000000, 0, 1, 0x7FFFFFFF]);
+ Expect.listEquals([0, 1, 2, -0x80000000, 0, 1, 0x7FFFFFFF, 7, 8, 9],
+ view);
+ Expect.listEquals([0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x7F,
+ 0x07, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF],
+ array);
+ }
+
+ static testUint32ListViewImpl(var array) {
+ Expect.isTrue(array is List<int>);
+ Expect.equals(48, array.length);
+ Expect.equals(1, array.bytesPerElement());
+ Expect.equals(48, array.lengthInBytes());
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = -1;
+ }
+ Expect.throws(() { new Uint32List.view(array.asByteArray(), -1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Uint32List.view(array.asByteArray(), 0, -1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Uint32List.view(array.asByteArray(),
+ array.lengthInBytes() + 1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Uint32List.view(array.asByteArray(),
+ 0, array.length + 1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Uint32List.view(array.asByteArray(),
+ array.length - 1, 2); },
+ (e) { return e is RangeError; });
+ var empty = new Uint32List.view(array.asByteArray(),
+ array.lengthInBytes());
+ Expect.isTrue(empty is List<int>);
+ Expect.isTrue(empty is Uint32List);
+ Expect.equals(0, empty.length);
+ var whole = new Uint32List.view(array.asByteArray());
+ Expect.isTrue(whole is List<int>);
+ Expect.isTrue(whole is Uint32List);
+ Expect.equals(12, whole.length);
+ var view = new Uint32List.view(array.asByteArray(), 4, 10);
+ Expect.isTrue(view is List<int>);
+ Expect.isTrue(view is Uint32List);
+ Expect.equals(10, view.length);
+ Expect.equals(4, view.bytesPerElement());
+ Expect.equals(40, view.lengthInBytes());
+ Expect.listEquals([0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF,
+ 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF],
+ view);
+ Expect.throws(() { view[-1] = 0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { return view[-1]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { view[view.length]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { view[view.length] = 0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { view.add(0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.addAll([0]); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.addLast(0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.clear(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.insertRange(0, view.length, 0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.length = 0; },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.removeLast(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.removeRange(0, view.length - 1); },
+ (e) { return e is UnsupportedError; });
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = 1 + i;
+ }
+ Expect.listEquals([1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10],
+ view);
+ Expect.listEquals([-1, -1, -1, -1, 1, 0, 0, 0,
+ 2, 0, 0, 0, 3, 0, 0, 0,
+ 4, 0, 0, 0, 5, 0, 0, 0,
+ 6, 0, 0, 0, 7, 0, 0, 0,
+ 8, 0, 0, 0, 9, 0, 0, 0,
+ 10, 0, 0, 0, -1, -1, -1, -1],
+ array);
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = 0x100000000 + i;
+ }
+ Expect.listEquals([0, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9],
+ view);
+ Expect.listEquals([-1, -1, -1, -1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 2, 0, 0, 0,
+ 3, 0, 0, 0, 4, 0, 0, 0,
+ 5, 0, 0, 0, 6, 0, 0, 0,
+ 7, 0, 0, 0, 8, 0, 0, 0,
+ 9, 0, 0, 0, -1, -1, -1, -1],
+ array);
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = 0xFFFFFFFF - i;
+ }
+ Expect.listEquals([0xFFFFFFFF, 0xFFFFFFFE,
+ 0xFFFFFFFD, 0xFFFFFFFC,
+ 0xFFFFFFFB, 0xFFFFFFFA,
+ 0xFFFFFFF9, 0xFFFFFFF8,
+ 0xFFFFFFF7, 0xFFFFFFF6],
+ view);
+ Expect.listEquals([-1, -1, -1, -1, -1, -1, -1, -1,
+ -2, -1, -1, -1, -3, -1, -1, -1,
+ -4, -1, -1, -1, -5, -1, -1, -1,
+ -6, -1, -1, -1, -7, -1, -1, -1,
+ -8, -1, -1, -1, -9, -1, -1, -1,
+ -10, -1, -1, -1, -1, -1, -1, -1],
+ array);
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = i;
+ }
+ var copy = view.getRange(0, view.length);
+ Expect.isFalse(copy === view);
+ Expect.isTrue(copy is Uint32List);
+ Expect.equals(10, copy.length);
+ Expect.listEquals(view, copy);
+ var region = view.getRange(3, view.length - 6);
+ Expect.isTrue(copy is Uint32List);
+ Expect.equals(4, region.length);
+ Expect.listEquals([3, 4, 5, 6], region);
+ view.setRange(3, 4, [0x100000001, 0, 1, 0xFFFFFFFF]);
+ Expect.listEquals([0, 1, 2, 1, 0, 1, 0xFFFFFFFF, 7, 8, 9],
+ view);
+ Expect.listEquals([-1, -1, -1, -1, 0, 0, 0, 0,
+ 1, 0, 0, 0, 2, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, -1, -1, -1, -1,
+ 7, 0, 0, 0, 8, 0, 0, 0,
+ 9, 0, 0, 0, -1, -1, -1, -1],
+ array);
+ }
+
+ static testUint32ListView() {
+ var array = new Int8List(48);
+ testUint32ListViewImpl(array);
+ }
+
+ static testInt64ListViewImpl(var array) {
+ Expect.equals(96, array.length);
+ Expect.equals(1, array.bytesPerElement());
+ Expect.equals(96, array.lengthInBytes());
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = 0xFF;
+ }
+ Expect.throws(() { new Int64List.view(array.asByteArray(), -1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Int64List.view(array.asByteArray(), 0, -1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Int64List.view(array.asByteArray(),
+ array.lengthInBytes() + 1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Int64List.view(array.asByteArray(),
+ 0, array.length + 1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Int64List.view(array.asByteArray(),
+ array.length - 1, 2); },
+ (e) { return e is RangeError; });
+ var empty = new Int64List.view(array.asByteArray(),
+ array.lengthInBytes());
+ Expect.isTrue(empty is List<int>);
+ Expect.isTrue(empty is Int64List);
+ Expect.equals(0, empty.length);
+ var whole = new Int64List.view(array.asByteArray());
+ Expect.isTrue(whole is List<int>);
+ Expect.isTrue(whole is Int64List);
+ Expect.equals(12, whole.length);
+ var view = new Int64List.view(array.asByteArray(), 8, 10);
+ Expect.isTrue(view is List<int>);
+ Expect.isTrue(view is Int64List);
+ Expect.equals(10, view.length);
+ Expect.equals(8, view.bytesPerElement());
+ Expect.equals(80, view.lengthInBytes());
+ Expect.listEquals([-1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1],
+ view);
+ Expect.throws(() { view[-1] = 0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { return view[-1]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { view[view.length]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { view[10] = 0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { view.add(0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.addAll([0]); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.addLast(0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.clear(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.insertRange(0, view.length, 0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.length = 0; },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.removeLast(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.removeRange(0, view.length - 1); },
+ (e) { return e is UnsupportedError; });
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = 1 + i;
+ }
+ Expect.listEquals([1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10],
+ view);
+ Expect.listEquals([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
+ array);
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = 0x10000000000000000 + i;
+ }
+ Expect.listEquals([0, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9],
+ view);
+ Expect.listEquals([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
+ array);
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = -10 + i;
+ }
+ Expect.listEquals([-10, -9, -8, -7, -6,
+ -5, -4, -3, -2, -1],
+ view);
+ Expect.listEquals([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xF6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
+ array);
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = 0x7FFFFFFFFFFFFFFF - i;
+ }
+ Expect.listEquals([0x7FFFFFFFFFFFFFFF, 0x7FFFFFFFFFFFFFFE,
+ 0x7FFFFFFFFFFFFFFD, 0x7FFFFFFFFFFFFFFC,
+ 0x7FFFFFFFFFFFFFFB, 0x7FFFFFFFFFFFFFFA,
+ 0x7FFFFFFFFFFFFFF9, 0x7FFFFFFFFFFFFFF8,
+ 0x7FFFFFFFFFFFFFF7, 0x7FFFFFFFFFFFFFF6],
+ view);
+ Expect.listEquals([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,
+ 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,
+ 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,
+ 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,
+ 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,
+ 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,
+ 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,
+ 0xF8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,
+ 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,
+ 0xF6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
+ array);
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = -0x8000000000000000 + i;
+ }
+ Expect.listEquals([-0x8000000000000000, -0x7FFFFFFFFFFFFFFF,
+ -0x7FFFFFFFFFFFFFFE, -0x7FFFFFFFFFFFFFFD,
+ -0x7FFFFFFFFFFFFFFC, -0x7FFFFFFFFFFFFFFB,
+ -0x7FFFFFFFFFFFFFFA, -0x7FFFFFFFFFFFFFF9,
+ -0x7FFFFFFFFFFFFFF8, -0x7FFFFFFFFFFFFFF7],
+ view);
+ Expect.listEquals([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
+ array);
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = i;
+ }
+ var copy = view.getRange(0, view.length);
+ Expect.isFalse(copy === view);
+ Expect.isTrue(copy is Int64List);
+ Expect.equals(10, copy.length);
+ Expect.listEquals(view, copy);
+ var region = view.getRange(3, view.length - 6);
+ Expect.isTrue(copy is Int64List);
+ Expect.equals(4, region.length);
+ Expect.listEquals([3, 4, 5, 6], region);
+ view.setRange(3, 4, [-0x8000000000000000, 0, 1, 0x7FFFFFFFFFFFFFFF]);
+ Expect.listEquals([0, 1, 2, -0x8000000000000000, 0,
+ 1, 0x7FFFFFFFFFFFFFFF, 7, 8, 9],
+ view);
+ Expect.listEquals([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,
+ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF],
+ array);
+ }
+
+ static testInt64ListView() {
+ var array = new Uint8List(96);
+ testInt64ListViewImpl(array);
+ }
+
+ static testUint64ListViewImpl(var array) {
+ Expect.isTrue(array is List<int>);
+ Expect.equals(96, array.length);
+ Expect.equals(1, array.bytesPerElement());
+ Expect.equals(96, array.lengthInBytes());
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = -1;
+ }
+ Expect.throws(() { new Uint64List.view(array.asByteArray(), -1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Uint64List.view(array.asByteArray(), 0, -1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Uint64List.view(array.asByteArray(),
+ array.lengthInBytes() + 1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Uint64List.view(array.asByteArray(),
+ 0, array.length + 1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Uint64List.view(array.asByteArray(),
+ array.length - 1, 2); },
+ (e) { return e is RangeError; });
+ var empty = new Uint64List.view(array.asByteArray(),
+ array.lengthInBytes());
+ Expect.isTrue(empty is List<int>);
+ Expect.isTrue(empty is Uint64List);
+ Expect.equals(0, empty.length);
+ var whole = new Uint64List.view(array.asByteArray());
+ Expect.isTrue(whole is List<int>);
+ Expect.isTrue(whole is Uint64List);
+ Expect.equals(12, whole.length);
+ var view = new Uint64List.view(array.asByteArray(), 8, 10);
+ Expect.isTrue(view is List<int>);
+ Expect.isTrue(view is Uint64List);
+ Expect.equals(10, view.length);
+ Expect.equals(8, view.bytesPerElement());
+ Expect.equals(80, view.lengthInBytes());
+ Expect.listEquals([0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF,
+ 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF],
+ view);
+ Expect.throws(() { view[-1] = 0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { return view[-1]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { view[view.length]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { view[view.length] = 0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { view.add(0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.addAll([0]); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.addLast(0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.clear(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.insertRange(0, view.length, 0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.length = 0; },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.removeLast(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { view.removeRange(0, view.length - 1); },
+ (e) { return e is UnsupportedError; });
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = 1 + i;
+ }
+ Expect.listEquals([1, 2, 3, 4, 5,
+ 6, 7, 8, 9, 10],
+ view);
+ Expect.listEquals([-1, -1, -1, -1, -1, -1, -1, -1,
+ 1, 0, 0, 0, 0, 0, 0, 0,
+ 2, 0, 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 0, 0, 0, 0,
+ 4, 0, 0, 0, 0, 0, 0, 0,
+ 5, 0, 0, 0, 0, 0, 0, 0,
+ 6, 0, 0, 0, 0, 0, 0, 0,
+ 7, 0, 0, 0, 0, 0, 0, 0,
+ 8, 0, 0, 0, 0, 0, 0, 0,
+ 9, 0, 0, 0, 0, 0, 0, 0,
+ 10, 0, 0, 0, 0, 0, 0, 0,
+ -1, -1, -1, -1, -1, -1, -1, -1],
+ array);
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = 0x10000000000000000 + i;
+ }
+ Expect.listEquals([0, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9],
+ view);
+ Expect.listEquals([-1, -1, -1, -1, -1, -1, -1, -1,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0,
+ 2, 0, 0, 0, 0, 0, 0, 0,
+ 3, 0, 0, 0, 0, 0, 0, 0,
+ 4, 0, 0, 0, 0, 0, 0, 0,
+ 5, 0, 0, 0, 0, 0, 0, 0,
+ 6, 0, 0, 0, 0, 0, 0, 0,
+ 7, 0, 0, 0, 0, 0, 0, 0,
+ 8, 0, 0, 0, 0, 0, 0, 0,
+ 9, 0, 0, 0, 0, 0, 0, 0,
+ -1, -1, -1, -1, -1, -1, -1, -1],
+ array);
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = 0xFFFFFFFFFFFFFFFF - i;
+ }
+ Expect.listEquals([0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFE,
+ 0xFFFFFFFFFFFFFFFD, 0xFFFFFFFFFFFFFFFC,
+ 0xFFFFFFFFFFFFFFFB, 0xFFFFFFFFFFFFFFFA,
+ 0xFFFFFFFFFFFFFFF9, 0xFFFFFFFFFFFFFFF8,
+ 0xFFFFFFFFFFFFFFF7, 0xFFFFFFFFFFFFFFF6],
+ view);
+ Expect.listEquals([-1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ -2, -1, -1, -1, -1, -1, -1, -1,
+ -3, -1, -1, -1, -1, -1, -1, -1,
+ -4, -1, -1, -1, -1, -1, -1, -1,
+ -5, -1, -1, -1, -1, -1, -1, -1,
+ -6, -1, -1, -1, -1, -1, -1, -1,
+ -7, -1, -1, -1, -1, -1, -1, -1,
+ -8, -1, -1, -1, -1, -1, -1, -1,
+ -9, -1, -1, -1, -1, -1, -1, -1,
+ -10, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1],
+ array);
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = i;
+ }
+ var copy = view.getRange(0, view.length);
+ Expect.isFalse(copy === view);
+ Expect.isTrue(copy is Uint64List);
+ Expect.equals(10, copy.length);
+ Expect.listEquals(view, copy);
+ var region = view.getRange(3, view.length - 6);
+ Expect.isTrue(copy is Uint64List);
+ Expect.equals(4, region.length);
+ Expect.listEquals([3, 4, 5, 6], region);
+ view.setRange(3, 4, [0x10000000000000001, 0, 1, 0xFFFFFFFFFFFFFFFF]);
+ Expect.listEquals([0, 1, 2, 1, 0, 1, 0xFFFFFFFFFFFFFFFF, 7, 8, 9],
+ view);
+ Expect.listEquals([-1, -1, -1, -1, -1, -1, -1, -1,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0,
+ 2, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 0, 0, 0, 0, 0, 0, 0,
+ -1, -1, -1, -1, -1, -1, -1, -1,
+ 7, 0, 0, 0, 0, 0, 0, 0,
+ 8, 0, 0, 0, 0, 0, 0, 0,
+ 9, 0, 0, 0, 0, 0, 0, 0,
+ -1, -1, -1, -1, -1, -1, -1, -1],
+ array);
+ }
+
+ static testUint64ListView() {
+ var array = new Int8List(96);
+ testUint64ListViewImpl(array);
+ }
+
+ static testFloat32ListViewImpl(var array) {
+ Expect.isTrue(array is List<int>);
+ Expect.equals(12, array.length);
+ Expect.equals(4, array.bytesPerElement());
+ Expect.equals(48, array.lengthInBytes());
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = 0xBF800000;
+ }
+ Expect.throws(() { new Float32List.view(array.asByteArray(), -1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Float32List.view(array.asByteArray(), 0, -1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Float32List.view(array.asByteArray(),
+ array.lengthInBytes() + 1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Float32List.view(array.asByteArray(),
+ 0, array.lengthInBytes() + 1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Float32List.view(array.asByteArray(),
+ array.lengthInBytes() - 1, 2); },
+ (e) { return e is RangeError; });
+ var empty = new Float32List.view(array.asByteArray(),
+ array.lengthInBytes());
+ Expect.isTrue(empty is List<double>);
+ Expect.isTrue(empty is Float32List);
+ Expect.equals(0, empty.length);
+ var whole = new Float32List.view(array.asByteArray());
+ Expect.isTrue(whole is List<double>);
+ Expect.isTrue(whole is Float32List);
+ Expect.equals(12, whole.length);
+ var view = new Float32List.view(array.asByteArray(), 4, 10);
+ Expect.isTrue(view is List<double>);
+ Expect.isTrue(view is Float32List);
+ Expect.equals(10, view.length);
+ Expect.equals(4, view.bytesPerElement());
+ Expect.equals(40, view.lengthInBytes());
+ Expect.listEquals([-1.0, -1.0, -1.0, -1.0, -1.0,
+ -1.0, -1.0, -1.0, -1.0, -1.0],
+ view);
+ Expect.throws(() { view[-1] = 0.0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { return view[-1]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { view[10]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { view[10] = 0.0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { array.add(0.0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.addAll([0]); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.addLast(0.0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.clear(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.insertRange(0, array.length, 0.0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.length = 0; },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.removeLast(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.removeRange(0, array.length - 1); },
+ (e) { return e is UnsupportedError; });
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = 1.0 + i;
+ }
+ Expect.listEquals([1.0, 2.0, 3.0, 4.0, 5.0,
+ 6.0, 7.0, 8.0, 9.0, 10.0],
+ view);
+ Expect.listEquals([0xBF800000, 0x3F800000,
+ 0x40000000, 0x40400000,
+ 0x40800000, 0x40A00000,
+ 0x40C00000, 0x40E00000,
+ 0x41000000, 0x41100000,
+ 0x41200000, 0xBF800000],
+ array);
+ // TODO: min, max, and round
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = i * 1.0;
+ }
+ var copy = view.getRange(0, view.length);
+ Expect.isFalse(copy === view);
+ Expect.isTrue(copy is Float32List);
+ Expect.equals(10, copy.length);
+ Expect.listEquals(view, copy);
+ var region = view.getRange(3, view.length - 6);
+ Expect.isTrue(copy is Float32List);
+ Expect.equals(4, region.length);
+ Expect.listEquals([3.0, 4.0, 5.0, 6.0], region);
+ view.setRange(3, 4, [double.NEGATIVE_INFINITY, 0.0, 1.0, double.INFINITY]);
+ Expect.listEquals([0.0, 1.0, 2.0, double.NEGATIVE_INFINITY, 0.0,
+ 1.0, double.INFINITY, 7.0, 8.0, 9.0],
+ view);
+ Expect.listEquals([0xBF800000, 0x00000000,
+ 0x3F800000, 0x40000000,
+ 0xFF800000, 0x00000000,
+ 0x3F800000, 0x7F800000,
+ 0x40E00000, 0x41000000,
+ 0x41100000, 0xBF800000],
+ array);
+ }
+
+ static testFloat32ListView() {
+ var array = new Uint32List(12);
+ testFloat32ListViewImpl(array);
+ }
+
+ static testFloat64ListViewImpl(var array) {
+ Expect.isTrue(array is List<int>);
+ Expect.equals(12, array.length);
+ Expect.equals(8, array.bytesPerElement());
+ Expect.equals(96, array.lengthInBytes());
+ for (int i = 0; i < array.length; ++i) {
+ array[i] = 0xBFF0000000000000;
+ }
+ Expect.throws(() { new Float64List.view(array.asByteArray(), -1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Float64List.view(array.asByteArray(), 0, -1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Float64List.view(array.asByteArray(),
+ array.lengthInBytes() + 1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Float64List.view(array.asByteArray(),
+ 0, array.lengthInBytes() + 1); },
+ (e) { return e is RangeError; });
+ Expect.throws(() { new Float64List.view(array.asByteArray(),
+ array.lengthInBytes() - 1, 2); },
+ (e) { return e is RangeError; });
+ var empty = new Float64List.view(array.asByteArray(),
+ array.lengthInBytes());
+ Expect.isTrue(empty is List<double>);
+ Expect.isTrue(empty is Float64List);
+ Expect.equals(0, empty.length);
+ var whole = new Float64List.view(array.asByteArray());
+ Expect.isTrue(whole is List<double>);
+ Expect.isTrue(whole is Float64List);
+ Expect.equals(12, whole.length);
+ var view = new Float64List.view(array.asByteArray(), 8, 10);
+ Expect.isTrue(view is List<double>);
+ Expect.isTrue(view is Float64List);
+ Expect.equals(10, view.length);
+ Expect.equals(8, view.bytesPerElement());
+ Expect.equals(80, view.lengthInBytes());
+ Expect.listEquals([-1.0, -1.0, -1.0, -1.0, -1.0,
+ -1.0, -1.0, -1.0, -1.0, -1.0],
+ view);
+ Expect.throws(() { view[-1] = 0.0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { return view[-1]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { view[10]; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { view[10] = 0.0; },
+ (e) { return e is RangeError; });
+ Expect.throws(() { array.add(0.0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.addAll([0]); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.addLast(0.0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.clear(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.insertRange(0, array.length, 0.0); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.length = 0; },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.removeLast(); },
+ (e) { return e is UnsupportedError; });
+ Expect.throws(() { array.removeRange(0, array.length - 1); },
+ (e) { return e is UnsupportedError; });
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = 1.0 + i;
+ }
+ Expect.listEquals([1.0, 2.0, 3.0, 4.0, 5.0,
+ 6.0, 7.0, 8.0, 9.0, 10.0],
+ view);
+ Expect.listEquals([0xBFF0000000000000, 0x3FF0000000000000,
+ 0x4000000000000000, 0x4008000000000000,
+ 0x4010000000000000, 0x4014000000000000,
+ 0x4018000000000000, 0x401C000000000000,
+ 0x4020000000000000, 0x4022000000000000,
+ 0x4024000000000000, 0xBFF0000000000000],
+ array);
+ // TODO: min, max
+ for (int i = 0; i < view.length; ++i) {
+ view[i] = i * 1.0;
+ }
+ var copy = view.getRange(0, view.length);
+ Expect.isFalse(copy === view);
+ Expect.isTrue(copy is Float64List);
+ Expect.equals(10, copy.length);
+ Expect.listEquals(view, copy);
+ var region = view.getRange(3, view.length - 6);
+ Expect.isTrue(copy is Float64List);
+ Expect.equals(4, region.length);
+ Expect.listEquals([3.0, 4.0, 5.0, 6.0], region);
+ view.setRange(3, 4, [double.NEGATIVE_INFINITY, 0.0, 1.0, double.INFINITY]);
+ Expect.listEquals([0.0, 1.0, 2.0, double.NEGATIVE_INFINITY, 0.0,
+ 1.0, double.INFINITY, 7.0, 8.0, 9.0],
+ view);
+ Expect.listEquals([0xBFF0000000000000, 0x0000000000000000,
+ 0x3FF0000000000000, 0x4000000000000000,
+ 0xFFF0000000000000, 0x0000000000000000,
+ 0x3FF0000000000000, 0x7FF0000000000000,
+ 0x401C000000000000, 0x4020000000000000,
+ 0x4022000000000000, 0xBFF0000000000000],
+ array);
+ }
+
+ static testFloat64ListView() {
+ var array = new Uint64List(12);
+ testFloat64ListViewImpl(array);
+ }
+
+ static testMain() {
+ testInt8List();
+ testUint8List();
+ testInt16List();
+ testUint16List();
+ testInt32List();
+ testUint32List();
+ testInt64List();
+ testUint64List();
+ testFloat32List();
+ testFloat64List();
+ //testByteList();
+ testInt8ListView();
+ testUint8ListView();
+ testInt16ListView();
+ testUint16ListView();
+ testInt32ListView();
+ testUint32ListView();
+ testInt64ListView();
+ testUint64ListView();
+ testFloat32ListView();
+ testFloat64ListView();
+ }
+}
+
+main() {
+ for (var i=0; i<1000; i++) {
+ OptimizedByteArrayTest.testMain();
+ }
+}
diff --git a/runtime/tests/vm/dart/byte_array_test.dart b/runtime/tests/vm/dart/byte_array_test.dart
index d984365..8ebe03c 100644
--- a/runtime/tests/vm/dart/byte_array_test.dart
+++ b/runtime/tests/vm/dart/byte_array_test.dart
@@ -2405,5 +2405,7 @@
}
main() {
- ByteArrayTest.testMain();
+ for (var i=0; i<1000; i++) {
+ ByteArrayTest.testMain();
+ }
}
diff --git a/runtime/tests/vm/vm.status b/runtime/tests/vm/vm.status
index c944645..5d7f315 100644
--- a/runtime/tests/vm/vm.status
+++ b/runtime/tests/vm/vm.status
@@ -32,6 +32,7 @@
[ $compiler == dart2js || $compiler == dartc ]
dart/isolate_mirror*: Skip # compilers not aware of dart:mirrors
dart/byte_array_test: Skip # compilers not aware of byte arrays
+dart/byte_array_optimized_test: Skip # compilers not aware of byte arrays
dart/isolate_unhandled*: Skip
[ $compiler == dart2js ]
@@ -65,7 +66,6 @@
cc/IcDataAccess: Skip
cc/Jump: Skip
cc/PatchStaticCall: Skip
-cc/Simple: Skip
cc/UseDartApi: Skip
# Tests needing Dart execution.
dart/*: Skip
diff --git a/runtime/vm/assembler_arm.cc b/runtime/vm/assembler_arm.cc
index 817a58f..183e164 100644
--- a/runtime/vm/assembler_arm.cc
+++ b/runtime/vm/assembler_arm.cc
@@ -72,7 +72,7 @@
const uint32_t offset_mask = (1 << 12) - 1;
uint32_t offset = encoding_ & offset_mask;
ASSERT(offset < (1 << 10)); // In the range 0 to +1020.
- ASSERT(Utils::Utils::IsAligned(offset, 2)); // Multiple of 4.
+ ASSERT(Utils::IsAligned(offset, 4)); // Multiple of 4.
int mode = encoding_ & ((8|4|1) << 21);
ASSERT((mode == Offset) || (mode == NegOffset));
uint32_t vencoding = (encoding_ & (0xf << kRnShift)) | (offset >> 2);
@@ -83,6 +83,17 @@
}
+void Assembler::InitializeMemoryWithBreakpoints(uword data, int length) {
+ ASSERT(Utils::IsAligned(data, 4));
+ ASSERT(Utils::IsAligned(length, 4));
+ const uword end = data + length;
+ while (data < end) {
+ *reinterpret_cast<int32_t*>(data) = Instr::kBreakPointInstruction;
+ data += 4;
+ }
+}
+
+
void Assembler::Emit(int32_t value) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
buffer_.Emit<int32_t>(value);
@@ -1020,7 +1031,18 @@
void Assembler::LoadObject(Register rd, const Object& object) {
- UNIMPLEMENTED();
+ // TODO(regis): If the object is never relocated (null, true, false, ...),
+ // load as immediate.
+ const int32_t offset =
+ Array::data_offset() + 4*AddObject(object) - kHeapObjectTag;
+ if (Address::CanHoldLoadOffset(kLoadWord, offset)) {
+ ldr(rd, Address(CP, offset));
+ } else {
+ int32_t offset12_hi = offset & ~kOffset12Mask; // signed
+ uint32_t offset12_lo = offset & kOffset12Mask; // unsigned
+ AddConstant(rd, CP, offset12_hi);
+ ldr(rd, Address(rd, offset12_lo));
+ }
}
@@ -1139,22 +1161,37 @@
void Assembler::Branch(const ExternalLabel* label) {
- // TODO(regis): Revisit this code sequence.
LoadImmediate(IP, label->address()); // Target address is never patched.
mov(PC, ShifterOperand(IP));
}
void Assembler::BranchLink(const ExternalLabel* label) {
- // TODO(regis): Revisit this code sequence.
- // Make sure that CodePatcher is able to patch this code sequence.
+ // TODO(regis): Make sure that CodePatcher is able to patch the label referred
+ // to by this code sequence.
// For added code robustness, use 'blx lr' in a patchable sequence and
// use 'blx ip' in a non-patchable sequence (see other BranchLink flavors).
- ldr(LR, Address(PC));
- Label skip;
- b(&skip);
- Emit(label->address()); // May get patched.
- Bind(&skip);
+ const int32_t offset =
+ Array::data_offset() + 4*AddExternalLabel(label) - kHeapObjectTag;
+ if (Address::CanHoldLoadOffset(kLoadWord, offset)) {
+ ldr(LR, Address(CP, offset));
+ } else {
+ int32_t offset12_hi = offset & ~kOffset12Mask; // signed
+ uint32_t offset12_lo = offset & kOffset12Mask; // unsigned
+ // Inline a simplified version of AddConstant(LR, CP, offset12_hi).
+ ShifterOperand shifter_op;
+ if (ShifterOperand::CanHold(offset12_hi, &shifter_op)) {
+ add(LR, CP, shifter_op);
+ } else {
+ movw(LR, Utils::Low16Bits(offset12_hi));
+ const uint16_t value_high = Utils::High16Bits(offset12_hi);
+ if (value_high != 0) {
+ movt(LR, value_high);
+ }
+ add(LR, CP, ShifterOperand(LR));
+ }
+ ldr(LR, Address(LR, offset12_lo));
+ }
blx(LR); // Use blx instruction so that the return branch prediction works.
}
@@ -1494,6 +1531,29 @@
return ((((inst & kBranchOffsetMask) << 8) >> 6) + 8);
}
+
+int32_t Assembler::AddObject(const Object& obj) {
+ for (int i = 0; i < object_pool_.Length(); i++) {
+ if (object_pool_.At(i) == obj.raw()) {
+ return i;
+ }
+ }
+ object_pool_.Add(obj);
+ return object_pool_.Length();
+}
+
+
+int32_t Assembler::AddExternalLabel(const ExternalLabel* label) {
+ const uword address = label->address();
+ ASSERT(Utils::IsAligned(address, 4));
+ // The address is stored in the object array as a RawSmi.
+ const Smi& smi = Smi::Handle(Smi::New(address >> kSmiTagShift));
+ // Do not reuse an existing entry, since each reference may be patched
+ // independently.
+ object_pool_.Add(smi);
+ return object_pool_.Length();
+}
+
} // namespace dart
#endif // defined TARGET_ARCH_ARM
diff --git a/runtime/vm/assembler_arm.h b/runtime/vm/assembler_arm.h
index b998894e..1b45703 100644
--- a/runtime/vm/assembler_arm.h
+++ b/runtime/vm/assembler_arm.h
@@ -262,7 +262,11 @@
class Assembler : public ValueObject {
public:
- Assembler() : buffer_(), prologue_offset_(-1), comments_() { }
+ Assembler()
+ : buffer_(),
+ object_pool_(GrowableObjectArray::Handle(GrowableObjectArray::New())),
+ prologue_offset_(-1),
+ comments_() { }
~Assembler() { }
void PopRegister(Register r) { Pop(r); }
@@ -273,11 +277,16 @@
int CodeSize() const { return buffer_.Size(); }
int prologue_offset() const { return prologue_offset_; }
const ZoneGrowableArray<int>& GetPointerOffsets() const {
+ ASSERT(buffer_.pointer_offsets().length() == 0); // No pointers in code.
return buffer_.pointer_offsets();
}
+ const GrowableObjectArray& object_pool() const {
+ return object_pool_;
+ }
void FinalizeInstructions(const MemoryRegion& region) {
buffer_.FinalizeInstructions(region);
+ ASSERT(object_pool_.Length() == 0); // TODO(regis): Otherwise, more work.
}
// Debugging and bringup support.
@@ -286,9 +295,7 @@
void Untested(const char* message);
void Unreachable(const char* message);
- static void InitializeMemoryWithBreakpoints(uword data, int length) {
- UNIMPLEMENTED();
- }
+ static void InitializeMemoryWithBreakpoints(uword data, int length);
void Comment(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
@@ -525,9 +532,12 @@
void Emit(int32_t value);
private:
- AssemblerBuffer buffer_;
- ZoneGrowableArray<int>* pointer_offsets_;
- int prologue_offset_;
+ AssemblerBuffer buffer_; // Contains position independent code.
+ const GrowableObjectArray& object_pool_; // Objects and jump targets.
+ int32_t prologue_offset_;
+
+ int32_t AddObject(const Object& obj);
+ int32_t AddExternalLabel(const ExternalLabel* label);
class CodeComment : public ZoneAllocated {
public:
diff --git a/runtime/vm/assembler_arm_test.cc b/runtime/vm/assembler_arm_test.cc
index 856f212..9d92c48 100644
--- a/runtime/vm/assembler_arm_test.cc
+++ b/runtime/vm/assembler_arm_test.cc
@@ -16,13 +16,14 @@
ASSEMBLER_TEST_GENERATE(Simple, assembler) {
- UNIMPLEMENTED();
+ __ mov(R0, ShifterOperand(42));
+ __ mov(PC, ShifterOperand(LR));
}
ASSEMBLER_TEST_RUN(Simple, entry) {
typedef int (*SimpleCode)();
- EXPECT_EQ(42, reinterpret_cast<SimpleCode>(entry)());
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(SimpleCode, entry));
}
} // namespace dart
diff --git a/runtime/vm/assembler_mips_test.cc b/runtime/vm/assembler_mips_test.cc
index 7321a8b..8e263f5 100644
--- a/runtime/vm/assembler_mips_test.cc
+++ b/runtime/vm/assembler_mips_test.cc
@@ -22,7 +22,7 @@
ASSEMBLER_TEST_RUN(Simple, entry) {
typedef int (*SimpleCode)();
- EXPECT_EQ(42, reinterpret_cast<SimpleCode>(entry)());
+ EXPECT_EQ(42, EXECUTE_TEST_CODE_INT32(SimpleCode, entry));
}
} // namespace dart
diff --git a/runtime/vm/bootstrap.cc b/runtime/vm/bootstrap.cc
index 5720b0a..27f949b 100644
--- a/runtime/vm/bootstrap.cc
+++ b/runtime/vm/bootstrap.cc
@@ -49,7 +49,8 @@
RawScript* Bootstrap::LoadCollectionDevScript(bool patch) {
- const char* url = patch ? "dart:collection-dev-patch" : "dart:collection-dev";
+ const char* url =
+ patch ? "dart:_collection-dev-patch" : "dart:_collection-dev";
const char* source = patch ? collection_dev_source_ : collection_dev_source_;
return LoadScript(url, source, patch);
}
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index e0324f0..babed80 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -196,10 +196,8 @@
propagator.PropagateTypes();
}
- // Verify that the use lists are still valid.
- DEBUG_ASSERT(flow_graph->ValidateUseLists());
-
// Propagate sminess from CheckSmi to phis.
+ flow_graph->ComputeUseLists();
optimizer.PropagateSminess();
// Use propagated class-ids to optimize further.
@@ -244,7 +242,6 @@
// We have to perform range analysis after LICM because it
// optimistically moves CheckSmi through phis into loop preheaders
// making some phis smi.
- flow_graph->ComputeUseLists();
optimizer.InferSmiRanges();
}
diff --git a/runtime/vm/constants_arm.h b/runtime/vm/constants_arm.h
index 4d477db..747b9a8 100644
--- a/runtime/vm/constants_arm.h
+++ b/runtime/vm/constants_arm.h
@@ -295,6 +295,8 @@
kPCReadOffset = 8
};
+ static const int32_t kBreakPointInstruction = // svc #kBreakpointSvcCode
+ ((AL << kConditionShift) | (0xf << 24) | kBreakpointSvcCode);
static const int kBreakPointInstructionSize = kInstrSize;
bool IsBreakPoint() {
return IsBkpt();
diff --git a/runtime/vm/debugger.cc b/runtime/vm/debugger.cc
index a10d329..7a68fc2 100644
--- a/runtime/vm/debugger.cc
+++ b/runtime/vm/debugger.cc
@@ -134,12 +134,11 @@
}
-ActivationFrame::ActivationFrame(uword pc, uword fp, uword sp,
- const Context& ctx)
+ActivationFrame::ActivationFrame(uword pc, uword fp, uword sp, const Code& code)
: pc_(pc), fp_(fp), sp_(sp),
- ctx_(Context::ZoneHandle(ctx.raw())),
- function_(Function::ZoneHandle()),
- code_(Code::ZoneHandle()),
+ ctx_(Context::ZoneHandle()),
+ code_(Code::ZoneHandle(code.raw())),
+ function_(Function::ZoneHandle(code.function())),
token_pos_(-1),
pc_desc_index_(-1),
line_number_(-1),
@@ -151,24 +150,6 @@
}
-const Code& ActivationFrame::DartCode() {
- if (code_.IsNull()) {
- Isolate* isolate = Isolate::Current();
- ASSERT(isolate != NULL);
- code_ = Code::LookupCode(pc_);
- }
- return code_;
-}
-
-
-const Function& ActivationFrame::DartFunction() {
- if (function_.IsNull()) {
- function_ = DartCode().function();
- }
- return function_;
-}
-
-
void Debugger::SignalIsolateEvent(EventType type) {
if (event_handler_ != NULL) {
Debugger* debugger = Isolate::Current()->debugger();
@@ -241,8 +222,7 @@
RawString* ActivationFrame::QualifiedFunctionName() {
- const Function& func = DartFunction();
- return String::New(Debugger::QualifiedFunctionName(func));
+ return String::New(Debugger::QualifiedFunctionName(function()));
}
@@ -253,23 +233,19 @@
RawScript* ActivationFrame::SourceScript() {
- const Function& func = DartFunction();
- return func.script();
+ return function().script();
}
RawLibrary* ActivationFrame::Library() {
- const Function& func = DartFunction();
- const Class& cls = Class::Handle(func.Owner());
+ const Class& cls = Class::Handle(function().Owner());
return cls.library();
}
void ActivationFrame::GetPcDescriptors() {
if (pc_desc_.IsNull()) {
- const Code& code = DartCode();
- ASSERT(!code.IsNull());
- pc_desc_ = code.pc_descriptors();
+ pc_desc_ = code().pc_descriptors();
ASSERT(!pc_desc_.IsNull());
}
}
@@ -320,8 +296,7 @@
void ActivationFrame::GetVarDescriptors() {
if (var_descriptors_.IsNull()) {
- const Code& code = DartCode();
- var_descriptors_ = code.var_descriptors();
+ var_descriptors_ = code().var_descriptors();
ASSERT(!var_descriptors_.IsNull());
}
}
@@ -363,7 +338,7 @@
}
-RawContext* ActivationFrame::CallerContext() {
+RawContext* ActivationFrame::GetSavedContext() {
GetVarDescriptors();
intptr_t var_desc_len = var_descriptors_.Length();
for (int i = 0; i < var_desc_len; i++) {
@@ -373,8 +348,8 @@
return reinterpret_cast<RawContext*>(GetLocalVarValue(var_info.index));
}
}
- // Caller uses same context chain.
- return ctx_.raw();
+ UNREACHABLE();
+ return Context::null();
}
@@ -388,8 +363,7 @@
ActivationFrame* frame = trace_[frame_index];
intptr_t try_index = frame->TryIndex();
if (try_index < 0) continue;
- const Code& code = frame->DartCode();
- handlers = code.exception_handlers();
+ handlers = frame->code().exception_handlers();
ASSERT(!handlers.IsNull());
intptr_t num_handlers_checked = 0;
while (try_index >= 0) {
@@ -426,7 +400,7 @@
// Rather than potentially displaying incorrect values, we
// pretend that there are no variables in the frame.
// We should be more clever about this in the future.
- if (DartCode().is_optimized()) {
+ if (code().is_optimized()) {
vars_initialized_ = true;
return;
}
@@ -563,10 +537,9 @@
const char* ActivationFrame::ToCString() {
const char* kFormat = "Function: '%s' url: '%s' line: %d";
- const Function& func = DartFunction();
const String& url = String::Handle(SourceUrl());
intptr_t line = LineNumber();
- const char* func_name = Debugger::QualifiedFunctionName(func);
+ const char* func_name = Debugger::QualifiedFunctionName(function());
intptr_t len =
OS::SNPrint(NULL, 0, kFormat, func_name, url.ToCString(), line);
@@ -880,17 +853,31 @@
DebuggerStackTrace* Debugger::CollectStackTrace() {
+ Isolate* isolate = Isolate::Current();
DebuggerStackTrace* stack_trace = new DebuggerStackTrace(8);
- Context& ctx = Context::Handle(Isolate::Current()->top_context());
- DartFrameIterator iterator;
+ Context& ctx = Context::Handle(isolate->top_context());
+ Code& code = Code::Handle(isolate);
+ StackFrameIterator iterator(false);
StackFrame* frame = iterator.NextFrame();
+ bool get_saved_context = false;
while (frame != NULL) {
ASSERT(frame->IsValid());
- ASSERT(frame->IsDartFrame());
- ActivationFrame* activation =
- new ActivationFrame(frame->pc(), frame->fp(), frame->sp(), ctx);
- ctx = activation->CallerContext();
- stack_trace->AddActivation(activation);
+ if (frame->IsDartFrame()) {
+ code = frame->LookupDartCode();
+ ActivationFrame* activation = new ActivationFrame(frame->pc(),
+ frame->fp(),
+ frame->sp(),
+ code);
+ if (get_saved_context) {
+ ctx = activation->GetSavedContext();
+ }
+ activation->SetContext(ctx);
+ stack_trace->AddActivation(activation);
+ get_saved_context = activation->function().IsClosureFunction();
+ } else if (frame->IsEntryFrame()) {
+ ctx = reinterpret_cast<EntryFrame*>(frame)->SavedContext();
+ get_saved_context = false;
+ }
frame = iterator.NextFrame();
}
return stack_trace;
@@ -1486,7 +1473,7 @@
// If we are at the function return, do a StepOut action.
if (stack_trace->Length() > 1) {
ActivationFrame* caller_frame = stack_trace->ActivationFrameAt(1);
- func_to_instrument = caller_frame->DartFunction().raw();
+ func_to_instrument = caller_frame->function().raw();
}
}
} else if (resume_action_ == kStepInto) {
@@ -1526,7 +1513,7 @@
// Treat like stepping out to caller.
if (stack_trace->Length() > 1) {
ActivationFrame* caller_frame = stack_trace->ActivationFrameAt(1);
- func_to_instrument = caller_frame->DartFunction().raw();
+ func_to_instrument = caller_frame->function().raw();
}
}
} else {
@@ -1534,7 +1521,7 @@
// Set stepping breakpoints in the caller.
if (stack_trace->Length() > 1) {
ActivationFrame* caller_frame = stack_trace->ActivationFrameAt(1);
- func_to_instrument = caller_frame->DartFunction().raw();
+ func_to_instrument = caller_frame->function().raw();
}
}
diff --git a/runtime/vm/debugger.h b/runtime/vm/debugger.h
index b85cfc7..2d7cbe8 100644
--- a/runtime/vm/debugger.h
+++ b/runtime/vm/debugger.h
@@ -119,20 +119,27 @@
// on the call stack.
class ActivationFrame : public ZoneAllocated {
public:
- explicit ActivationFrame(uword pc, uword fp, uword sp, const Context& ctx);
+ ActivationFrame(uword pc, uword fp, uword sp, const Code& code);
uword pc() const { return pc_; }
uword fp() const { return fp_; }
uword sp() const { return sp_; }
+ const Function& function() const {
+ ASSERT(!function_.IsNull());
+ return function_;
+ }
+ const Code& code() const {
+ ASSERT(!code_.IsNull());
+ return code_;
+ }
- const Function& DartFunction();
- const Code& DartCode();
RawString* QualifiedFunctionName();
RawString* SourceUrl();
RawScript* SourceScript();
RawLibrary* Library();
intptr_t TokenPos();
intptr_t LineNumber();
+ void SetContext(const Context& ctx) { ctx_ = ctx.raw(); }
// The context level of a frame is the context level at the
// PC/token index of the frame. It determines the depth of the context
@@ -150,7 +157,7 @@
Instance* value);
RawArray* GetLocalVariables();
- RawContext* CallerContext();
+ RawContext* GetSavedContext();
private:
intptr_t PcDescIndex();
@@ -166,10 +173,9 @@
uword sp_;
// The anchor of the context chain for this function.
- const Context& ctx_;
-
- Function& function_;
- Code& code_;
+ Context& ctx_;
+ const Code& code_;
+ const Function& function_;
intptr_t token_pos_;
intptr_t pc_desc_index_;
intptr_t line_number_;
diff --git a/runtime/vm/debugger_api_impl_test.cc b/runtime/vm/debugger_api_impl_test.cc
index 20f0e3f..bcde541 100644
--- a/runtime/vm/debugger_api_impl_test.cc
+++ b/runtime/vm/debugger_api_impl_test.cc
@@ -169,7 +169,9 @@
}
-static void VerifyListEquals(Dart_Handle expected, Dart_Handle got) {
+static void VerifyListEquals(Dart_Handle expected,
+ Dart_Handle got,
+ bool skip_null_expects) {
EXPECT(Dart_IsList(expected));
EXPECT(Dart_IsList(got));
Dart_Handle res;
@@ -188,14 +190,15 @@
bool equals;
res = Dart_ObjectEquals(expected_elem, got_elem, &equals);
EXPECT_VALID(res);
- EXPECT(equals);
+ EXPECT(equals || (Dart_IsNull(expected_elem) && skip_null_expects));
}
}
static void VerifyStackFrame(Dart_ActivationFrame frame,
const char* expected_name,
- Dart_Handle expected_locals) {
+ Dart_Handle expected_locals,
+ bool skip_null_expects) {
Dart_Handle func_name;
Dart_Handle res;
res = Dart_ActivationFrameInfo(frame, &func_name, NULL, NULL, NULL);
@@ -204,13 +207,13 @@
const char* func_name_chars;
Dart_StringToCString(func_name, &func_name_chars);
if (expected_name != NULL) {
- EXPECT_STREQ(func_name_chars, expected_name);
+ EXPECT_SUBSTRING(expected_name, func_name_chars);
}
if (!Dart_IsNull(expected_locals)) {
Dart_Handle locals = Dart_GetLocalVariables(frame);
EXPECT_VALID(locals);
- VerifyListEquals(expected_locals, locals);
+ VerifyListEquals(expected_locals, locals, skip_null_expects);
}
}
@@ -218,7 +221,8 @@
static void VerifyStackTrace(Dart_StackTrace trace,
const char* func_names[],
Dart_Handle local_vars[],
- int expected_frames) {
+ int expected_frames,
+ bool skip_null_expects) {
intptr_t trace_len;
Dart_Handle res = Dart_StackTraceLength(trace, &trace_len);
EXPECT_VALID(res);
@@ -227,9 +231,9 @@
res = Dart_GetActivationFrame(trace, i, &frame);
EXPECT_VALID(res);
if (i < expected_frames) {
- VerifyStackFrame(frame, func_names[i], local_vars[i]);
+ VerifyStackFrame(frame, func_names[i], local_vars[i], skip_null_expects);
} else {
- VerifyStackFrame(frame, NULL, Dart_Null());
+ VerifyStackFrame(frame, NULL, Dart_Null(), skip_null_expects);
}
}
}
@@ -639,7 +643,7 @@
Dart_Handle expected_locals[] = {add_locals, Dart_Null()};
breakpoint_hit_counter++;
PrintStackTrace(trace);
- VerifyStackTrace(trace, expected_trace, expected_locals, 2);
+ VerifyStackTrace(trace, expected_trace, expected_locals, 2, false);
}
@@ -1228,6 +1232,321 @@
EXPECT(interrupt_isolate_id == ILLEGAL_ISOLATE_ID);
}
+
+static void StackTraceDump1BreakpointHandler(Dart_IsolateId isolate_id,
+ Dart_Breakpoint bpt,
+ Dart_StackTrace trace) {
+ const int kStackTraceLen = 4;
+ static const char* expected_trace[kStackTraceLen] = {
+ "local_to_main",
+ "Test.local1_to_func1",
+ "Test.func1",
+ "main"
+ };
+
+ intptr_t trace_len;
+ Dart_Handle res = Dart_StackTraceLength(trace, &trace_len);
+ EXPECT_VALID(res);
+ EXPECT_EQ(kStackTraceLen, trace_len);
+
+ // Frame 0 corresponding to "local_to_main".
+ Dart_Handle frame0_locals = Dart_NewList(8);
+ Dart_ListSetAt(frame0_locals, 0, NewString("i"));
+ Dart_ListSetAt(frame0_locals, 1, Dart_NewInteger(76));
+ Dart_ListSetAt(frame0_locals, 2, NewString("j"));
+ Dart_ListSetAt(frame0_locals, 3, Dart_NewInteger(119));
+ Dart_ListSetAt(frame0_locals, 4, NewString("k"));
+ Dart_ListSetAt(frame0_locals, 5, Dart_NewInteger(66));
+ Dart_ListSetAt(frame0_locals, 6, NewString("l"));
+ Dart_ListSetAt(frame0_locals, 7, Dart_NewInteger(99));
+
+ // Frame 1 corresponding to "Test.local1_to_func1".
+ Dart_Handle frame1_locals = Dart_NewList(14);
+ Dart_ListSetAt(frame1_locals, 0, NewString("i"));
+ Dart_ListSetAt(frame1_locals, 1, Dart_NewInteger(11));
+ Dart_ListSetAt(frame1_locals, 2, NewString("j"));
+ Dart_ListSetAt(frame1_locals, 3, Dart_NewInteger(22));
+ Dart_ListSetAt(frame1_locals, 4, NewString("k"));
+ Dart_ListSetAt(frame1_locals, 5, Dart_NewInteger(33));
+ Dart_ListSetAt(frame1_locals, 6, NewString("l"));
+ Dart_ListSetAt(frame1_locals, 7, Dart_NewInteger(44));
+ Dart_ListSetAt(frame1_locals, 8, NewString("m"));
+ Dart_ListSetAt(frame1_locals, 9, Dart_NewInteger(55));
+ Dart_ListSetAt(frame1_locals, 10, NewString("func"));
+ Dart_ListSetAt(frame1_locals, 11, Dart_Null());
+ Dart_ListSetAt(frame1_locals, 12, NewString("n"));
+ Dart_ListSetAt(frame1_locals, 13, Dart_Null());
+
+ // Frame 2 corresponding to "Test.func1".
+ Dart_Handle frame2_locals = Dart_NewList(18);
+ Dart_ListSetAt(frame2_locals, 0, NewString("this"));
+ Dart_ListSetAt(frame2_locals, 1, Dart_Null());
+ Dart_ListSetAt(frame2_locals, 2, NewString("func"));
+ Dart_ListSetAt(frame2_locals, 3, Dart_Null());
+ Dart_ListSetAt(frame2_locals, 4, NewString("i"));
+ Dart_ListSetAt(frame2_locals, 5, Dart_NewInteger(11));
+ Dart_ListSetAt(frame2_locals, 6, NewString("j"));
+ Dart_ListSetAt(frame2_locals, 7, Dart_NewInteger(22));
+ Dart_ListSetAt(frame2_locals, 8, NewString("k"));
+ Dart_ListSetAt(frame2_locals, 9, Dart_NewInteger(33));
+ Dart_ListSetAt(frame2_locals, 10, NewString("l"));
+ Dart_ListSetAt(frame2_locals, 11, Dart_NewInteger(44));
+ Dart_ListSetAt(frame2_locals, 12, NewString("m"));
+ Dart_ListSetAt(frame2_locals, 13, Dart_NewInteger(55));
+ Dart_ListSetAt(frame2_locals, 14, NewString("local1_to_func1"));
+ Dart_ListSetAt(frame2_locals, 15, Dart_Null());
+ Dart_ListSetAt(frame2_locals, 16, NewString("sum"));
+ Dart_ListSetAt(frame2_locals, 17, Dart_NewInteger(0));
+
+ // Frame 3 corresponding to "main".
+ Dart_Handle frame3_locals = Dart_NewList(14);
+ Dart_ListSetAt(frame3_locals, 0, NewString("i"));
+ Dart_ListSetAt(frame3_locals, 1, Dart_NewInteger(76));
+ Dart_ListSetAt(frame3_locals, 2, NewString("j"));
+ Dart_ListSetAt(frame3_locals, 3, Dart_NewInteger(119));
+ Dart_ListSetAt(frame3_locals, 4, NewString("local_to_main"));
+ Dart_ListSetAt(frame3_locals, 5, Dart_Null());
+ Dart_ListSetAt(frame3_locals, 6, NewString("sum"));
+ Dart_ListSetAt(frame3_locals, 7, Dart_NewInteger(0));
+ Dart_ListSetAt(frame3_locals, 8, NewString("value"));
+ Dart_ListSetAt(frame3_locals, 9, Dart_Null());
+ Dart_ListSetAt(frame3_locals, 10, NewString("func1"));
+ Dart_ListSetAt(frame3_locals, 11, Dart_Null());
+ Dart_ListSetAt(frame3_locals, 12, NewString("main_local"));
+ Dart_ListSetAt(frame3_locals, 13, Dart_Null());
+
+ Dart_Handle expected_locals[] = {
+ frame0_locals,
+ frame1_locals,
+ frame2_locals,
+ frame3_locals
+ };
+ breakpoint_hit_counter++;
+ VerifyStackTrace(trace, expected_trace, expected_locals,
+ kStackTraceLen, true);
+}
+
+
+TEST_CASE(Debug_StackTraceDump1) {
+ const char* kScriptChars =
+ "class Test {\n"
+ " Test(int local);\n"
+ "\n"
+ " int func1(int func(int i, int j)) {\n"
+ " var i = 0;\n"
+ " var j = 0;\n"
+ " var k = 0;\n"
+ " var l = 0;\n"
+ " var m = 0;\n"
+ " int local1_to_func1(int func(int i, int j)) {\n"
+ " // Capture i and j here.\n"
+ " i = 11;\n"
+ " j = 22;\n"
+ " k = 33;\n"
+ " l = 44;\n"
+ " m = 55;\n"
+ " var n = func(i + j + k, l + m);\n"
+ " return n;\n"
+ " }\n"
+ " var sum = 0;\n"
+ " return local1_to_func1(func);\n"
+ " }\n"
+ "\n"
+ " int local;\n"
+ "}\n"
+ "\n"
+ "int main() {\n"
+ " var i = 10;\n"
+ " var j = 20;\n"
+ " int local_to_main(int k, int l) {\n"
+ " // Capture i and j here.\n"
+ " i = i + k;\n"
+ " j = j + l;\n"
+ " return i + j;\n"
+ " }\n"
+ " var sum = 0;\n"
+ " Test value = new Test(10);\n"
+ " var func1 = value.func1;\n"
+ " var main_local = local_to_main;\n"
+ " return func1(main_local);\n"
+ "}\n";
+
+ LoadScript(kScriptChars);
+ Dart_SetBreakpointHandler(&StackTraceDump1BreakpointHandler);
+
+ Dart_Handle script_url = NewString(TestCase::url());
+ intptr_t line_no = 34; // In closure 'local_to_main'.
+ Dart_Handle res = Dart_SetBreakpoint(script_url, line_no);
+ EXPECT_VALID(res);
+ EXPECT(Dart_IsInteger(res));
+
+ breakpoint_hit_counter = 0;
+ Dart_Handle retval = Invoke("main");
+ EXPECT_VALID(retval);
+ int64_t int_value = 0;
+ Dart_IntegerToInt64(retval, &int_value);
+ EXPECT_EQ(195, int_value);
+ EXPECT_EQ(1, breakpoint_hit_counter);
+}
+
+
+static void StackTraceDump2ExceptionHandler(Dart_IsolateId isolate_id,
+ Dart_Handle exception_object,
+ Dart_StackTrace trace) {
+ const int kStackTraceLen = 5;
+ static const char* expected_trace[kStackTraceLen] = {
+ "Object._noSuchMethod",
+ "Object.noSuchMethod",
+ "Test.local1_to_func1",
+ "Test.func1",
+ "main"
+ };
+
+ intptr_t trace_len;
+ Dart_Handle res = Dart_StackTraceLength(trace, &trace_len);
+ EXPECT_VALID(res);
+ EXPECT_EQ(kStackTraceLen, trace_len);
+
+ // Frame 0 corresponding to "Object._noSuchMethod".
+ Dart_Handle frame0_locals = Dart_NewList(10);
+ Dart_ListSetAt(frame0_locals, 0, NewString("this"));
+ Dart_ListSetAt(frame0_locals, 1, Dart_Null());
+ Dart_ListSetAt(frame0_locals, 2, NewString("isMethod"));
+ Dart_ListSetAt(frame0_locals, 3, Dart_Null());
+ Dart_ListSetAt(frame0_locals, 4, NewString("memberName"));
+ Dart_ListSetAt(frame0_locals, 5, Dart_Null());
+ Dart_ListSetAt(frame0_locals, 6, NewString("arguments"));
+ Dart_ListSetAt(frame0_locals, 7, Dart_Null());
+ Dart_ListSetAt(frame0_locals, 8, NewString("namedArguments"));
+ Dart_ListSetAt(frame0_locals, 9, Dart_Null());
+
+ // Frame 1 corresponding to "Object.noSuchMethod".
+ Dart_Handle frame1_locals = Dart_NewList(4);
+ Dart_ListSetAt(frame1_locals, 0, NewString("this"));
+ Dart_ListSetAt(frame1_locals, 1, Dart_Null());
+ Dart_ListSetAt(frame1_locals, 2, NewString("invocation"));
+ Dart_ListSetAt(frame1_locals, 3, Dart_Null());
+
+ // Frame 2 corresponding to "Test.local1_to_func1".
+ Dart_Handle frame2_locals = Dart_NewList(16);
+ Dart_ListSetAt(frame2_locals, 0, NewString("i"));
+ Dart_ListSetAt(frame2_locals, 1, Dart_NewInteger(11));
+ Dart_ListSetAt(frame2_locals, 2, NewString("j"));
+ Dart_ListSetAt(frame2_locals, 3, Dart_NewInteger(22));
+ Dart_ListSetAt(frame2_locals, 4, NewString("k"));
+ Dart_ListSetAt(frame2_locals, 5, Dart_NewInteger(33));
+ Dart_ListSetAt(frame2_locals, 6, NewString("l"));
+ Dart_ListSetAt(frame2_locals, 7, Dart_NewInteger(44));
+ Dart_ListSetAt(frame2_locals, 8, NewString("m"));
+ Dart_ListSetAt(frame2_locals, 9, Dart_NewInteger(55));
+ Dart_ListSetAt(frame2_locals, 10, NewString("this"));
+ Dart_ListSetAt(frame2_locals, 11, Dart_Null());
+ Dart_ListSetAt(frame2_locals, 12, NewString("func"));
+ Dart_ListSetAt(frame2_locals, 13, Dart_Null());
+ Dart_ListSetAt(frame2_locals, 14, NewString("n"));
+ Dart_ListSetAt(frame2_locals, 15, Dart_Null());
+
+ // Frame 3 corresponding to "Test.func1".
+ Dart_Handle frame3_locals = Dart_NewList(18);
+ Dart_ListSetAt(frame3_locals, 0, NewString("this"));
+ Dart_ListSetAt(frame3_locals, 1, Dart_Null());
+ Dart_ListSetAt(frame3_locals, 2, NewString("func"));
+ Dart_ListSetAt(frame3_locals, 3, Dart_Null());
+ Dart_ListSetAt(frame3_locals, 4, NewString("i"));
+ Dart_ListSetAt(frame3_locals, 5, Dart_NewInteger(11));
+ Dart_ListSetAt(frame3_locals, 6, NewString("j"));
+ Dart_ListSetAt(frame3_locals, 7, Dart_NewInteger(22));
+ Dart_ListSetAt(frame3_locals, 8, NewString("k"));
+ Dart_ListSetAt(frame3_locals, 9, Dart_NewInteger(33));
+ Dart_ListSetAt(frame3_locals, 10, NewString("l"));
+ Dart_ListSetAt(frame3_locals, 11, Dart_NewInteger(44));
+ Dart_ListSetAt(frame3_locals, 12, NewString("m"));
+ Dart_ListSetAt(frame3_locals, 13, Dart_NewInteger(55));
+ Dart_ListSetAt(frame3_locals, 14, NewString("local1_to_func1"));
+ Dart_ListSetAt(frame3_locals, 15, Dart_Null());
+ Dart_ListSetAt(frame3_locals, 16, NewString("sum"));
+ Dart_ListSetAt(frame3_locals, 17, Dart_NewInteger(0));
+
+ // Frame 4 corresponding to "main".
+ Dart_Handle frame4_locals = Dart_NewList(12);
+ Dart_ListSetAt(frame4_locals, 0, NewString("i"));
+ Dart_ListSetAt(frame4_locals, 1, Dart_NewInteger(10));
+ Dart_ListSetAt(frame4_locals, 2, NewString("j"));
+ Dart_ListSetAt(frame4_locals, 3, Dart_NewInteger(20));
+ Dart_ListSetAt(frame4_locals, 4, NewString("local_to_main"));
+ Dart_ListSetAt(frame4_locals, 5, Dart_Null());
+ Dart_ListSetAt(frame4_locals, 6, NewString("sum"));
+ Dart_ListSetAt(frame4_locals, 7, Dart_NewInteger(0));
+ Dart_ListSetAt(frame4_locals, 8, NewString("value"));
+ Dart_ListSetAt(frame4_locals, 9, Dart_Null());
+ Dart_ListSetAt(frame4_locals, 10, NewString("func1"));
+ Dart_ListSetAt(frame4_locals, 11, Dart_Null());
+
+ Dart_Handle expected_locals[] = {
+ frame0_locals,
+ frame1_locals,
+ frame2_locals,
+ frame3_locals,
+ frame4_locals
+ };
+ breakpoint_hit_counter++;
+ VerifyStackTrace(trace, expected_trace, expected_locals,
+ kStackTraceLen, true);
+}
+
+
+TEST_CASE(Debug_StackTraceDump2) {
+ const char* kScriptChars =
+ "class Test {\n"
+ " Test(int local);\n"
+ "\n"
+ " int func1(int func(int i, int j)) {\n"
+ " var i = 0;\n"
+ " var j = 0;\n"
+ " var k = 0;\n"
+ " var l = 0;\n"
+ " var m = 0;\n"
+ " int local1_to_func1(int func(int i, int j)) {\n"
+ " // Capture i and j here.\n"
+ " i = 11;\n"
+ " j = 22;\n"
+ " k = 33;\n"
+ " l = 44;\n"
+ " m = 55;\n"
+ " var n = junk(i + j + k, l + m);\n"
+ " return n;\n"
+ " }\n"
+ " var sum = 0;\n"
+ " return local1_to_func1(func);\n"
+ " }\n"
+ "\n"
+ " int local;\n"
+ "}\n"
+ "\n"
+ "int main() {\n"
+ " var i = 10;\n"
+ " var j = 20;\n"
+ " int local_to_main(int k, int l) {\n"
+ " // Capture i and j here.\n"
+ " return i + j;\n"
+ " }\n"
+ " var sum = 0;\n"
+ " Test value = new Test(10);\n"
+ " var func1 = value.func1;\n"
+ " return func1(local_to_main);\n"
+ "}\n";
+
+ LoadScript(kScriptChars);
+ Dart_SetExceptionThrownHandler(&StackTraceDump2ExceptionHandler);
+ breakpoint_hit_counter = 0;
+ Dart_SetExceptionPauseInfo(kPauseOnAllExceptions);
+
+ Dart_Handle retval = Invoke("main");
+ EXPECT(Dart_IsError(retval));
+ EXPECT(Dart_IsUnhandledExceptionError(retval));
+ EXPECT_EQ(1, breakpoint_hit_counter);
+}
+
#endif // defined(TARGET_ARCH_IA32) || defined(TARGET_ARCH_X64).
} // namespace dart
diff --git a/runtime/vm/flow_graph.cc b/runtime/vm/flow_graph.cc
index 58ae9ac..ea66a5a 100644
--- a/runtime/vm/flow_graph.cc
+++ b/runtime/vm/flow_graph.cc
@@ -169,7 +169,11 @@
while (curr != NULL) {
ASSERT(prev == curr->previous_use());
ASSERT(defn == curr->definition());
- ASSERT(curr == curr->instruction()->InputAt(curr->use_index()));
+ Instruction* instr = curr->instruction();
+ // The instruction should not be removed from the graph (phis are not
+ // removed until register allocation.)
+ ASSERT(instr->IsPhi() || (instr->previous() != NULL));
+ ASSERT(curr == instr->InputAt(curr->use_index()));
prev = curr;
curr = curr->next_use();
}
@@ -179,8 +183,11 @@
while (curr != NULL) {
ASSERT(prev == curr->previous_use());
ASSERT(defn == curr->definition());
- ASSERT(curr ==
- curr->instruction()->env()->ValueAtUseIndex(curr->use_index()));
+ Instruction* instr = curr->instruction();
+ ASSERT(curr == instr->env()->ValueAtUseIndex(curr->use_index()));
+ // The instruction should not be removed from the graph (phis are not
+ // removed until register allocation.)
+ ASSERT(instr->IsPhi() || (instr->previous() != NULL));
prev = curr;
curr = curr->next_use();
}
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index 88c7c9e..236c4d9 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -692,9 +692,9 @@
intptr_t current_context_level = owner()->context_level();
ASSERT(current_context_level >= 0);
- if (owner()->parsed_function().saved_context_var() != NULL) {
+ if (owner()->parsed_function().saved_entry_context_var() != NULL) {
// CTX on entry was saved, but not linked as context parent.
- BuildLoadContext(*owner()->parsed_function().saved_context_var());
+ BuildLoadContext(*owner()->parsed_function().saved_entry_context_var());
} else {
while (current_context_level-- > 0) {
UnchainContext();
@@ -1870,7 +1870,8 @@
BuildPushArguments(*node->arguments(), arguments);
// Save context around the call.
- BuildStoreContext(*owner()->parsed_function().expression_temp_var());
+ ASSERT(owner()->parsed_function().saved_current_context_var() != NULL);
+ BuildStoreContext(*owner()->parsed_function().saved_current_context_var());
return new ClosureCallInstr(node, arguments);
}
@@ -1878,14 +1879,16 @@
void EffectGraphVisitor::VisitClosureCallNode(ClosureCallNode* node) {
Do(BuildClosureCall(node));
// Restore context from saved location.
- BuildLoadContext(*owner()->parsed_function().expression_temp_var());
+ ASSERT(owner()->parsed_function().saved_current_context_var() != NULL);
+ BuildLoadContext(*owner()->parsed_function().saved_current_context_var());
}
void ValueGraphVisitor::VisitClosureCallNode(ClosureCallNode* node) {
Value* result = Bind(BuildClosureCall(node));
// Restore context from temp.
- BuildLoadContext(*owner()->parsed_function().expression_temp_var());
+ ASSERT(owner()->parsed_function().saved_current_context_var() != NULL);
+ BuildLoadContext(*owner()->parsed_function().saved_current_context_var());
ReturnValue(result);
}
@@ -2763,7 +2766,7 @@
bool EffectGraphVisitor::MustSaveRestoreContext(SequenceNode* node) const {
return (node == owner()->parsed_function().node_sequence()) &&
- (owner()->parsed_function().saved_context_var() != NULL);
+ (owner()->parsed_function().saved_entry_context_var() != NULL);
}
@@ -2803,7 +2806,7 @@
// In this case, the parser pre-allocates a variable to save the context.
if (MustSaveRestoreContext(node)) {
Value* current_context = Bind(new CurrentContextInstr());
- Do(BuildStoreTemp(*owner()->parsed_function().saved_context_var(),
+ Do(BuildStoreTemp(*owner()->parsed_function().saved_entry_context_var(),
current_context));
Value* null_context = Bind(new ConstantInstr(Object::ZoneHandle()));
AddInstruction(new StoreContextInstr(null_context));
@@ -2902,7 +2905,7 @@
if (is_open()) {
if (MustSaveRestoreContext(node)) {
ASSERT(num_context_variables > 0);
- BuildLoadContext(*owner()->parsed_function().saved_context_var());
+ BuildLoadContext(*owner()->parsed_function().saved_entry_context_var());
} else if (num_context_variables > 0) {
UnchainContext();
}
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index 11349ad..880b3eb 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -903,6 +903,8 @@
return TwoByteString::kBytesPerElement;
case kExternalUint8ArrayCid:
return ExternalUint8Array::kBytesPerElement;
+ case kExternalUint8ClampedArrayCid:
+ return ExternalUint8ClampedArray::kBytesPerElement;
default:
UNIMPLEMENTED();
return 0;
diff --git a/runtime/vm/flow_graph_compiler.h b/runtime/vm/flow_graph_compiler.h
index eb7181f..f7d3f34 100644
--- a/runtime/vm/flow_graph_compiler.h
+++ b/runtime/vm/flow_graph_compiler.h
@@ -384,15 +384,19 @@
static intptr_t DataOffsetFor(intptr_t cid);
static intptr_t ElementSizeFor(intptr_t cid);
static FieldAddress ElementAddressForIntIndex(intptr_t cid,
+ intptr_t index_scale,
Register array,
intptr_t offset);
static FieldAddress ElementAddressForRegIndex(intptr_t cid,
+ intptr_t index_scale,
Register array,
Register index);
static Address ExternalElementAddressForIntIndex(intptr_t cid,
+ intptr_t index_scale,
Register array,
intptr_t offset);
static Address ExternalElementAddressForRegIndex(intptr_t cid,
+ intptr_t index_scale,
Register array,
Register index);
diff --git a/runtime/vm/flow_graph_compiler_arm.cc b/runtime/vm/flow_graph_compiler_arm.cc
index 38b9901..d8b220c 100644
--- a/runtime/vm/flow_graph_compiler_arm.cc
+++ b/runtime/vm/flow_graph_compiler_arm.cc
@@ -304,6 +304,7 @@
FieldAddress FlowGraphCompiler::ElementAddressForIntIndex(intptr_t cid,
+ intptr_t index_scale,
Register array,
intptr_t index) {
UNIMPLEMENTED();
@@ -312,6 +313,7 @@
FieldAddress FlowGraphCompiler::ElementAddressForRegIndex(intptr_t cid,
+ intptr_t index_scale,
Register array,
Register index) {
UNIMPLEMENTED();
@@ -319,17 +321,21 @@
}
-Address FlowGraphCompiler::ExternalElementAddressForIntIndex(intptr_t cid,
- Register array,
- intptr_t index) {
+Address FlowGraphCompiler::ExternalElementAddressForIntIndex(
+ intptr_t cid,
+ intptr_t index_scale,
+ Register array,
+ intptr_t index) {
UNIMPLEMENTED();
return FieldAddress(array, index);
}
-Address FlowGraphCompiler::ExternalElementAddressForRegIndex(intptr_t cid,
- Register array,
- Register index) {
+Address FlowGraphCompiler::ExternalElementAddressForRegIndex(
+ intptr_t cid,
+ intptr_t index_scale,
+ Register array,
+ Register index) {
UNIMPLEMENTED();
return FieldAddress(array, index);
}
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index 102f205..efb9b7b 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -1504,70 +1504,62 @@
FieldAddress FlowGraphCompiler::ElementAddressForIntIndex(intptr_t cid,
+ intptr_t index_scale,
Register array,
intptr_t index) {
const int64_t disp =
- static_cast<int64_t>(index) * ElementSizeFor(cid) + DataOffsetFor(cid);
+ static_cast<int64_t>(index) * index_scale + DataOffsetFor(cid);
ASSERT(Utils::IsInt(32, disp));
return FieldAddress(array, static_cast<int32_t>(disp));
}
-FieldAddress FlowGraphCompiler::ElementAddressForRegIndex(intptr_t cid,
- Register array,
- Register index) {
- // Note that index is smi-tagged, (i.e, times 2) for all arrays with element
- // size > 1. For Uint8Array and OneByteString the index is expected to be
- // untagged before accessing.
+static ScaleFactor ToScaleFactor(intptr_t index_scale) {
+ // Note that index is expected smi-tagged, (i.e, times 2) for all arrays with
+ // index scale factor > 1. E.g., for Uint8Array and OneByteString the index is
+ // expected to be untagged before accessing.
ASSERT(kSmiTagShift == 1);
- switch (cid) {
- case kArrayCid:
- case kImmutableArrayCid:
- return FieldAddress(
- array, index, TIMES_HALF_WORD_SIZE, Array::data_offset());
- case kFloat32ArrayCid:
- return FieldAddress(array, index, TIMES_2, Float32Array::data_offset());
- case kFloat64ArrayCid:
- return FieldAddress(array, index, TIMES_4, Float64Array::data_offset());
- case kInt8ArrayCid:
- return FieldAddress(array, index, TIMES_1, Int8Array::data_offset());
- case kUint8ArrayCid:
- return FieldAddress(array, index, TIMES_1, Uint8Array::data_offset());
- case kUint8ClampedArrayCid:
- return
- FieldAddress(array, index, TIMES_1, Uint8ClampedArray::data_offset());
- case kInt16ArrayCid:
- return FieldAddress(array, index, TIMES_1, Int16Array::data_offset());
- case kUint16ArrayCid:
- return FieldAddress(array, index, TIMES_1, Uint16Array::data_offset());
- case kInt32ArrayCid:
- return FieldAddress(array, index, TIMES_2, Int32Array::data_offset());
- case kUint32ArrayCid:
- return FieldAddress(array, index, TIMES_2, Uint32Array::data_offset());
- case kOneByteStringCid:
- return FieldAddress(array, index, TIMES_1, OneByteString::data_offset());
- case kTwoByteStringCid:
- return FieldAddress(array, index, TIMES_1, TwoByteString::data_offset());
+ switch (index_scale) {
+ case 1: return TIMES_1;
+ case 2: return TIMES_1;
+ case 4: return TIMES_2;
+ case 8: return TIMES_4;
default:
- UNIMPLEMENTED();
- return FieldAddress(SPREG, 0);
+ UNREACHABLE();
+ return TIMES_1;
}
}
-Address FlowGraphCompiler::ExternalElementAddressForIntIndex(intptr_t cid,
- Register array,
- intptr_t index) {
- return Address(array, index * ElementSizeFor(cid));
+FieldAddress FlowGraphCompiler::ElementAddressForRegIndex(intptr_t cid,
+ intptr_t index_scale,
+ Register array,
+ Register index) {
+ return FieldAddress(array,
+ index,
+ ToScaleFactor(index_scale),
+ DataOffsetFor(cid));
}
-Address FlowGraphCompiler::ExternalElementAddressForRegIndex(intptr_t cid,
- Register array,
- Register index) {
+Address FlowGraphCompiler::ExternalElementAddressForIntIndex(
+ intptr_t cid,
+ intptr_t index_scale,
+ Register array,
+ intptr_t index) {
+ return Address(array, index * index_scale);
+}
+
+
+Address FlowGraphCompiler::ExternalElementAddressForRegIndex(
+ intptr_t cid,
+ intptr_t index_scale,
+ Register array,
+ Register index) {
switch (cid) {
case kExternalUint8ArrayCid:
- return Address(array, index, TIMES_1, 0);
+ case kExternalUint8ClampedArrayCid:
+ return Address(array, index, ToScaleFactor(index_scale), 0);
default:
UNIMPLEMENTED();
return Address(SPREG, 0);
diff --git a/runtime/vm/flow_graph_compiler_mips.cc b/runtime/vm/flow_graph_compiler_mips.cc
index 6ff3a8c..e3c0cd6 100644
--- a/runtime/vm/flow_graph_compiler_mips.cc
+++ b/runtime/vm/flow_graph_compiler_mips.cc
@@ -304,6 +304,7 @@
FieldAddress FlowGraphCompiler::ElementAddressForIntIndex(intptr_t cid,
+ intptr_t index_scale,
Register array,
intptr_t index) {
UNIMPLEMENTED();
@@ -312,6 +313,7 @@
FieldAddress FlowGraphCompiler::ElementAddressForRegIndex(intptr_t cid,
+ intptr_t index_scale,
Register array,
Register index) {
UNIMPLEMENTED();
@@ -319,17 +321,21 @@
}
-Address FlowGraphCompiler::ExternalElementAddressForIntIndex(intptr_t cid,
- Register array,
- intptr_t index) {
+Address FlowGraphCompiler::ExternalElementAddressForIntIndex(
+ intptr_t cid,
+ intptr_t index_scale,
+ Register array,
+ intptr_t index) {
UNIMPLEMENTED();
return FieldAddress(array, index);
}
-Address FlowGraphCompiler::ExternalElementAddressForRegIndex(intptr_t cid,
- Register array,
- Register index) {
+Address FlowGraphCompiler::ExternalElementAddressForRegIndex(
+ intptr_t cid,
+ intptr_t index_scale,
+ Register array,
+ Register index) {
UNIMPLEMENTED();
return FieldAddress(array, index);
}
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index 4e1b9aa..76e976e 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -1508,70 +1508,62 @@
FieldAddress FlowGraphCompiler::ElementAddressForIntIndex(intptr_t cid,
+ intptr_t index_scale,
Register array,
intptr_t index) {
const int64_t disp =
- static_cast<int64_t>(index) * ElementSizeFor(cid) + DataOffsetFor(cid);
+ static_cast<int64_t>(index) * index_scale + DataOffsetFor(cid);
ASSERT(Utils::IsInt(32, disp));
return FieldAddress(array, static_cast<int32_t>(disp));
}
-FieldAddress FlowGraphCompiler::ElementAddressForRegIndex(intptr_t cid,
- Register array,
- Register index) {
- // Note that index is smi-tagged, (i.e, times 2) for all arrays with element
- // size > 1. For Uint8Array and OneByteString the index is expected to be
- // untagged before accessing.
+static ScaleFactor ToScaleFactor(intptr_t index_scale) {
+ // Note that index is expected smi-tagged, (i.e, times 2) for all arrays with
+ // index scale factor > 1. E.g., for Uint8Array and OneByteString the index is
+ // expected to be untagged before accessing.
ASSERT(kSmiTagShift == 1);
- switch (cid) {
- case kArrayCid:
- case kImmutableArrayCid:
- return FieldAddress(
- array, index, TIMES_HALF_WORD_SIZE, Array::data_offset());
- case kFloat32ArrayCid:
- return FieldAddress(array, index, TIMES_2, Float32Array::data_offset());
- case kFloat64ArrayCid:
- return FieldAddress(array, index, TIMES_4, Float64Array::data_offset());
- case kInt8ArrayCid:
- return FieldAddress(array, index, TIMES_1, Int8Array::data_offset());
- case kUint8ArrayCid:
- return FieldAddress(array, index, TIMES_1, Uint8Array::data_offset());
- case kUint8ClampedArrayCid:
- return
- FieldAddress(array, index, TIMES_1, Uint8ClampedArray::data_offset());
- case kInt16ArrayCid:
- return FieldAddress(array, index, TIMES_1, Int16Array::data_offset());
- case kUint16ArrayCid:
- return FieldAddress(array, index, TIMES_1, Uint16Array::data_offset());
- case kInt32ArrayCid:
- return FieldAddress(array, index, TIMES_2, Int32Array::data_offset());
- case kUint32ArrayCid:
- return FieldAddress(array, index, TIMES_2, Uint32Array::data_offset());
- case kOneByteStringCid:
- return FieldAddress(array, index, TIMES_1, OneByteString::data_offset());
- case kTwoByteStringCid:
- return FieldAddress(array, index, TIMES_1, TwoByteString::data_offset());
+ switch (index_scale) {
+ case 1: return TIMES_1;
+ case 2: return TIMES_1;
+ case 4: return TIMES_2;
+ case 8: return TIMES_4;
default:
- UNIMPLEMENTED();
- return FieldAddress(SPREG, 0);
+ UNREACHABLE();
+ return TIMES_1;
}
}
-Address FlowGraphCompiler::ExternalElementAddressForIntIndex(intptr_t cid,
- Register array,
- intptr_t index) {
- return Address(array, index * ElementSizeFor(cid));
+FieldAddress FlowGraphCompiler::ElementAddressForRegIndex(intptr_t cid,
+ intptr_t index_scale,
+ Register array,
+ Register index) {
+ return FieldAddress(array,
+ index,
+ ToScaleFactor(index_scale),
+ DataOffsetFor(cid));
}
-Address FlowGraphCompiler::ExternalElementAddressForRegIndex(intptr_t cid,
- Register array,
- Register index) {
+Address FlowGraphCompiler::ExternalElementAddressForIntIndex(
+ intptr_t cid,
+ intptr_t index_scale,
+ Register array,
+ intptr_t index) {
+ return Address(array, index * index_scale);
+}
+
+
+Address FlowGraphCompiler::ExternalElementAddressForRegIndex(
+ intptr_t cid,
+ intptr_t index_scale,
+ Register array,
+ Register index) {
switch (cid) {
case kExternalUint8ArrayCid:
- return Address(array, index, TIMES_1, 0);
+ case kExternalUint8ClampedArrayCid:
+ return Address(array, index, ToScaleFactor(index_scale), 0);
default:
UNIMPLEMENTED();
return Address(SPREG, 0);
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index 3ce5318..b1a10b8 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -176,7 +176,7 @@
}
-static void ReplaceCurrentInstruction(ForwardInstructionIterator* it,
+static void ReplaceCurrentInstruction(ForwardInstructionIterator* iterator,
Instruction* current,
Instruction* replacement,
FlowGraph* graph) {
@@ -200,7 +200,8 @@
OS::Print("Removing v%"Pd".\n", current_defn->ssa_temp_index());
}
}
- it->RemoveCurrentFromGraph();
+ current->UnuseAllInputs();
+ iterator->RemoveCurrentFromGraph();
}
@@ -555,7 +556,8 @@
}
if (!skip_check) {
// Insert array length load and bounds check.
- const bool is_immutable = (class_id != kGrowableObjectArrayCid);
+ const bool is_immutable =
+ CheckArrayBoundInstr::IsFixedLengthArrayType(class_id);
LoadFieldInstr* length = new LoadFieldInstr(
(*array)->Copy(),
CheckArrayBoundInstr::LengthOffsetFor(class_id),
@@ -758,6 +760,7 @@
case kUint8ArrayCid:
case kUint8ClampedArrayCid:
case kExternalUint8ArrayCid:
+ case kExternalUint8ClampedArrayCid:
case kInt16ArrayCid:
case kUint16ArrayCid:
break;
@@ -784,7 +787,11 @@
Value* index = NULL;
intptr_t array_cid = PrepareIndexedOp(call, class_id, &array, &index);
Definition* array_op =
- new LoadIndexedInstr(array, index, array_cid, deopt_id);
+ new LoadIndexedInstr(array,
+ index,
+ FlowGraphCompiler::ElementSizeFor(array_cid),
+ array_cid,
+ deopt_id);
call->ReplaceWith(array_op, current_iterator());
RemovePushArguments(call);
return true;
@@ -1256,7 +1263,9 @@
return false;
}
const bool is_immutable =
- (recognized_kind != MethodRecognizer::kGrowableArrayLength);
+ (recognized_kind == MethodRecognizer::kObjectArrayLength) ||
+ (recognized_kind == MethodRecognizer::kImmutableArrayLength) ||
+ (recognized_kind == MethodRecognizer::kByteArrayBaseLength);
InlineArrayLengthGetter(call,
OffsetForLengthGetter(recognized_kind),
is_immutable,
@@ -1329,7 +1338,11 @@
call->env(),
Definition::kEffect);
}
- return new LoadIndexedInstr(str, index, cid, Isolate::kNoDeoptId);
+ return new LoadIndexedInstr(str,
+ index,
+ FlowGraphCompiler::ElementSizeFor(cid),
+ cid,
+ Isolate::kNoDeoptId); // Can't deoptimize.
}
@@ -1349,6 +1362,24 @@
}
+static bool IsSupportedByteArrayCid(intptr_t cid) {
+ switch (cid) {
+ case kInt8ArrayCid:
+ case kUint8ArrayCid:
+ case kUint8ClampedArrayCid:
+ case kInt16ArrayCid:
+ case kUint16ArrayCid:
+ case kInt32ArrayCid:
+ case kUint32ArrayCid:
+ case kFloat32ArrayCid:
+ case kFloat64ArrayCid:
+ return true;
+ default:
+ return false;
+ }
+}
+
+
// Inline only simple, frequently called core library methods.
bool FlowGraphOptimizer::TryInlineInstanceMethod(InstanceCallInstr* call) {
ASSERT(call->HasICData());
@@ -1440,10 +1471,98 @@
}
}
+ if (IsSupportedByteArrayCid(class_ids[0]) &&
+ (ic_data.NumberOfChecks() == 1)) {
+ Definition* array_op = NULL;
+ switch (recognized_kind) {
+ case MethodRecognizer::kByteArrayBaseGetInt8:
+ array_op = BuildByteArrayViewLoad(call, class_ids[0], kInt8ArrayCid);
+ break;
+ case MethodRecognizer::kByteArrayBaseGetUint8:
+ array_op = BuildByteArrayViewLoad(call, class_ids[0], kUint8ArrayCid);
+ break;
+ case MethodRecognizer::kByteArrayBaseGetInt16:
+ array_op = BuildByteArrayViewLoad(call, class_ids[0], kInt16ArrayCid);
+ break;
+ case MethodRecognizer::kByteArrayBaseGetUint16:
+ array_op = BuildByteArrayViewLoad(call, class_ids[0], kUint16ArrayCid);
+ break;
+ case MethodRecognizer::kByteArrayBaseGetInt32:
+ array_op = BuildByteArrayViewLoad(call, class_ids[0], kInt32ArrayCid);
+ break;
+ case MethodRecognizer::kByteArrayBaseGetUint32:
+ array_op = BuildByteArrayViewLoad(call, class_ids[0], kUint32ArrayCid);
+ break;
+ case MethodRecognizer::kByteArrayBaseGetFloat32:
+ array_op = BuildByteArrayViewLoad(call, class_ids[0], kFloat32ArrayCid);
+ break;
+ case MethodRecognizer::kByteArrayBaseGetFloat64:
+ array_op = BuildByteArrayViewLoad(call, class_ids[0], kFloat64ArrayCid);
+ break;
+ default:
+ // Unsupported method.
+ return false;
+ }
+ ASSERT(array_op != NULL);
+ call->ReplaceWith(array_op, current_iterator());
+ RemovePushArguments(call);
+ return true;
+ }
return false;
}
+LoadIndexedInstr* FlowGraphOptimizer::BuildByteArrayViewLoad(
+ InstanceCallInstr* call,
+ intptr_t receiver_cid,
+ intptr_t view_cid) {
+ Value* array = call->ArgumentAt(0)->value();
+ Value* byte_index = call->ArgumentAt(1)->value();
+
+ AddCheckClass(call, array->Copy());
+ const bool is_immutable = true;
+ LoadFieldInstr* length = new LoadFieldInstr(
+ array->Copy(),
+ CheckArrayBoundInstr::LengthOffsetFor(receiver_cid),
+ Type::ZoneHandle(Type::SmiType()),
+ is_immutable);
+ length->set_result_cid(kSmiCid);
+ length->set_recognized_kind(
+ LoadFieldInstr::RecognizedKindFromArrayCid(receiver_cid));
+ InsertBefore(call, length, NULL, Definition::kValue);
+
+ // len_in_bytes = length * kBytesPerElement(receiver)
+ intptr_t element_size = FlowGraphCompiler::ElementSizeFor(receiver_cid);
+ ConstantInstr* bytes_per_element =
+ new ConstantInstr(Smi::Handle(Smi::New(element_size)));
+ InsertBefore(call, bytes_per_element, NULL, Definition::kValue);
+ BinarySmiOpInstr* len_in_bytes =
+ new BinarySmiOpInstr(Token::kMUL,
+ call,
+ new Value(length),
+ new Value(bytes_per_element));
+ InsertBefore(call, len_in_bytes, call->env(), Definition::kValue);
+
+ // Check byte_index < len_in_bytes.
+ InsertBefore(call,
+ new CheckArrayBoundInstr(new Value(len_in_bytes),
+ byte_index->Copy(),
+ receiver_cid,
+ call),
+ call->env(),
+ Definition::kEffect);
+
+ // TODO(fschneider): Optimistically build smi load for Int32 and Uint32
+ // loads on ia32 like we do for normal array loads, and only revert to
+ // mint case after deoptimizing here.
+ return new LoadIndexedInstr(array,
+ byte_index,
+ 1, // Index scale.
+ view_cid,
+ Isolate::kNoDeoptId); // Can't deoptimize.
+}
+
+
// Returns a Boolean constant if all classes in ic_data yield the same type-test
// result and the type tests do not depend on type arguments. Otherwise return
// Bool::null().
@@ -2562,7 +2681,10 @@
CheckArrayBoundInstr* check = current->AsCheckArrayBound();
RangeBoundary array_length =
RangeBoundary::FromDefinition(check->length()->definition());
- if (check->IsRedundant(array_length)) it.RemoveCurrentFromGraph();
+ if (check->IsRedundant(array_length)) {
+ current->UnuseAllInputs();
+ it.RemoveCurrentFromGraph();
+ }
}
}
@@ -2602,7 +2724,7 @@
def = def->AsConstraint()->value()->definition();
}
constraints_[i]->ReplaceUsesWith(def);
- constraints_[i]->RemoveDependency();
+ constraints_[i]->UnuseAllInputs();
constraints_[i]->RemoveFromGraph();
}
}
@@ -2914,6 +3036,7 @@
}
if (phi->GetPropagatedCid() == kSmiCid) {
+ current->UnuseAllInputs();
it->RemoveCurrentFromGraph();
return;
}
@@ -3322,6 +3445,7 @@
}
defn->ReplaceUsesWith(replacement);
+ defn->UnuseAllInputs();
instr_it.RemoveCurrentFromGraph();
continue;
} else if (!kill->Contains(expr_id)) {
@@ -3533,6 +3657,7 @@
}
load->ReplaceUsesWith(replacement);
+ load->UnuseAllInputs();
load->RemoveFromGraph();
load->SetReplacement(replacement);
}
diff --git a/runtime/vm/flow_graph_optimizer.h b/runtime/vm/flow_graph_optimizer.h
index 53159fc..b53054e 100644
--- a/runtime/vm/flow_graph_optimizer.h
+++ b/runtime/vm/flow_graph_optimizer.h
@@ -75,6 +75,10 @@
LoadIndexedInstr* BuildStringCharCodeAt(InstanceCallInstr* call,
intptr_t cid);
+ LoadIndexedInstr* BuildByteArrayViewLoad(InstanceCallInstr* call,
+ intptr_t receiver_cid,
+ intptr_t view_cid);
+
void AddCheckClass(InstanceCallInstr* call, Value* value);
void InsertAfter(Instruction* prev,
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index 11b2713..7b8e997 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -696,6 +696,16 @@
}
+void Instruction::UnuseAllInputs() {
+ for (intptr_t i = InputCount() - 1; i >= 0; --i) {
+ InputAt(i)->RemoveFromUseList();
+ }
+ for (Environment::DeepIterator it(env()); !it.Done(); it.Advance()) {
+ it.CurrentValue()->RemoveFromUseList();
+ }
+}
+
+
void Definition::ReplaceWith(Definition* other,
ForwardInstructionIterator* iterator) {
if ((iterator != NULL) && (this == iterator->Current())) {
@@ -1219,6 +1229,7 @@
case kUint8ArrayCid:
case kUint8ClampedArrayCid:
case kExternalUint8ArrayCid:
+ case kExternalUint8ClampedArrayCid:
case kInt16ArrayCid:
case kUint16ArrayCid:
case kInt32ArrayCid:
@@ -1715,6 +1726,7 @@
case kUint8ArrayCid:
case kUint8ClampedArrayCid:
case kExternalUint8ArrayCid:
+ case kExternalUint8ClampedArrayCid:
case kInt16ArrayCid:
case kUint16ArrayCid:
case kInt32ArrayCid:
@@ -2129,13 +2141,20 @@
Environment* Environment::DeepCopy() const {
+ return (this == NULL) ? NULL : DeepCopy(Length());
+}
+
+
+Environment* Environment::DeepCopy(intptr_t length) const {
+ ASSERT(length <= values_.length());
+ if (this == NULL) return NULL;
Environment* copy =
- new Environment(values_.length(),
+ new Environment(length,
fixed_parameter_count_,
deopt_id_,
function_,
- (outer_ == NULL) ? NULL : outer_->DeepCopy());
- for (intptr_t i = 0; i < values_.length(); ++i) {
+ outer_->DeepCopy());
+ for (intptr_t i = 0; i < length; ++i) {
copy->values_.Add(values_[i]->Copy());
}
return copy;
@@ -2144,6 +2163,10 @@
// Copies the environment and updates the environment use lists.
void Environment::DeepCopyTo(Instruction* instr) const {
+ for (Environment::DeepIterator it(instr->env()); !it.Done(); it.Advance()) {
+ it.CurrentValue()->RemoveFromUseList();
+ }
+
Environment* copy = DeepCopy();
intptr_t use_index = 0;
for (Environment::DeepIterator it(copy); !it.Done(); it.Advance()) {
@@ -2159,18 +2182,11 @@
// Copies the environment as outer on an inlined instruction and updates the
// environment use lists.
void Environment::DeepCopyToOuter(Instruction* instr) const {
- ASSERT(instr->env()->outer() == NULL);
// Create a deep copy removing caller arguments from the environment.
+ ASSERT(this != NULL);
+ ASSERT(instr->env()->outer() == NULL);
intptr_t argument_count = instr->env()->fixed_parameter_count();
- Environment* copy =
- new Environment(values_.length() - argument_count,
- fixed_parameter_count_,
- deopt_id_,
- function_,
- (outer_ == NULL) ? NULL : outer_->DeepCopy());
- for (intptr_t i = 0; i < values_.length() - argument_count; ++i) {
- copy->values_.Add(values_[i]->Copy());
- }
+ Environment* copy = DeepCopy(values_.length() - argument_count);
intptr_t use_index = instr->env()->Length(); // Start index after inner.
for (Environment::DeepIterator it(copy); !it.Done(); it.Advance()) {
Value* value = it.CurrentValue();
@@ -2498,6 +2514,7 @@
case kUint8ArrayCid:
case kUint8ClampedArrayCid:
case kExternalUint8ArrayCid:
+ case kExternalUint8ClampedArrayCid:
range_ = new Range(RangeBoundary::FromConstant(0),
RangeBoundary::FromConstant(255));
break;
@@ -2777,6 +2794,7 @@
case kFloat64ArrayCid:
case kFloat32ArrayCid:
case kExternalUint8ArrayCid:
+ case kExternalUint8ClampedArrayCid:
return ByteArray::length_offset();
default:
UNREACHABLE();
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index 8c3b695..1d70a29 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -36,6 +36,14 @@
V(_ObjectArray, get:length, ObjectArrayLength, 405297088) \
V(_ImmutableArray, get:length, ImmutableArrayLength, 433698233) \
V(_ByteArrayBase, get:length, ByteArrayBaseLength, 1098081765) \
+ V(_ByteArrayBase, _getInt8, ByteArrayBaseGetInt8, 261365835) \
+ V(_ByteArrayBase, _getUint8, ByteArrayBaseGetUint8, 261365835) \
+ V(_ByteArrayBase, _getInt16, ByteArrayBaseGetInt16, 261365835) \
+ V(_ByteArrayBase, _getUint16, ByteArrayBaseGetUint16, 261365835) \
+ V(_ByteArrayBase, _getInt32, ByteArrayBaseGetInt32, 261365835) \
+ V(_ByteArrayBase, _getUint32, ByteArrayBaseGetUint32, 261365835) \
+ V(_ByteArrayBase, _getFloat32, ByteArrayBaseGetFloat32, 434247298) \
+ V(_ByteArrayBase, _getFloat64, ByteArrayBaseGetFloat64, 434247298) \
V(_GrowableObjectArray, get:length, GrowableArrayLength, 725548050) \
V(_GrowableObjectArray, get:_capacity, GrowableArrayCapacity, 725548050) \
V(_StringBase, get:length, StringBaseLength, 320803993) \
@@ -351,6 +359,10 @@
virtual Value* InputAt(intptr_t i) const = 0;
virtual void SetInputAt(intptr_t i, Value* value) = 0;
+ // Remove all inputs (including in the environment) from their
+ // definition's use lists.
+ void UnuseAllInputs();
+
// Call instructions override this function and return the number of
// pushed arguments.
virtual intptr_t ArgumentCount() const = 0;
@@ -1802,6 +1814,10 @@
DECLARE_INSTRUCTION(Constraint)
+ virtual intptr_t InputCount() const {
+ return (inputs_[1] == NULL) ? 1 : 2;
+ }
+
virtual RawAbstractType* CompileType() const {
return Type::SmiType();
}
@@ -1832,13 +1848,6 @@
set_dependency(val);
}
- void RemoveDependency() {
- if (dependency() != NULL) {
- dependency()->RemoveFromUseList();
- set_dependency(NULL);
- }
- }
-
private:
Value* dependency() {
return inputs_[1];
@@ -2721,9 +2730,10 @@
public:
LoadIndexedInstr(Value* array,
Value* index,
+ intptr_t index_scale,
intptr_t class_id,
intptr_t deopt_id)
- : class_id_(class_id) {
+ : index_scale_(index_scale), class_id_(class_id) {
ASSERT(array != NULL);
ASSERT(index != NULL);
inputs_[0] = array;
@@ -2736,6 +2746,7 @@
Value* array() const { return inputs_[0]; }
Value* index() const { return inputs_[1]; }
+ intptr_t index_scale() const { return index_scale_; }
intptr_t class_id() const { return class_id_; }
virtual bool CanDeoptimize() const {
@@ -2755,6 +2766,7 @@
virtual void InferRange();
private:
+ const intptr_t index_scale_;
const intptr_t class_id_;
DISALLOW_COPY_AND_ASSIGN(LoadIndexedInstr);
@@ -4455,7 +4467,11 @@
function_(function),
outer_(outer) { }
+ // Deep copy the environment. A 'length' parameter can be given, which
+ // may be less than the environment's length in order to drop values
+ // (e.g., passed arguments) from the copy.
Environment* DeepCopy() const;
+ Environment* DeepCopy(intptr_t length) const;
GrowableArray<Value*> values_;
Location* locations_;
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index a698a59..0787527 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -462,7 +462,11 @@
ASSERT((ic_data.GetReceiverClassIdAt(i) != kSmiCid) || (i == 0));
Label next_test;
__ cmpl(temp, Immediate(ic_data.GetReceiverClassIdAt(i)));
- __ j(NOT_EQUAL, &next_test);
+ if (i < len - 1) {
+ __ j(NOT_EQUAL, &next_test);
+ } else {
+ __ j(NOT_EQUAL, deopt);
+ }
const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(i));
if (target.Owner() == object_store->object_class()) {
// Object.== is same as ===.
@@ -497,7 +501,6 @@
__ jmp(&done);
__ Bind(&false_label);
__ LoadObject(EAX, Bool::False());
- __ jmp(&done);
}
} else {
if (branch->is_checked()) {
@@ -507,11 +510,11 @@
branch->EmitBranchOnCondition(compiler, cond);
}
}
- __ jmp(&done);
- __ Bind(&next_test);
+ if (i < len - 1) {
+ __ jmp(&done);
+ __ Bind(&next_test);
+ }
}
- // Fall through leads to deoptimization
- __ jmp(deopt);
__ Bind(&done);
}
@@ -1106,6 +1109,7 @@
case kUint8ArrayCid:
case kUint8ClampedArrayCid:
case kExternalUint8ArrayCid:
+ case kExternalUint8ClampedArrayCid:
case kInt16ArrayCid:
case kUint16ArrayCid:
case kOneByteStringCid:
@@ -1132,6 +1136,7 @@
case kUint8ArrayCid:
case kUint8ClampedArrayCid:
case kExternalUint8ArrayCid:
+ case kExternalUint8ClampedArrayCid:
case kInt16ArrayCid:
case kUint16ArrayCid:
case kOneByteStringCid:
@@ -1177,13 +1182,16 @@
Register array = locs()->in(0).reg();
Location index = locs()->in(1);
- if (class_id() == kExternalUint8ArrayCid) {
+ if ((class_id() == kExternalUint8ArrayCid) ||
+ (class_id() == kExternalUint8ClampedArrayCid)) {
Register result = locs()->out().reg();
const Address& element_address = index.IsRegister()
? FlowGraphCompiler::ExternalElementAddressForRegIndex(
- class_id(), result, index.reg())
+ class_id(), index_scale(), result, index.reg())
: FlowGraphCompiler::ExternalElementAddressForIntIndex(
- class_id(), result, Smi::Cast(index.constant()).Value());
+ class_id(), index_scale(), result,
+ Smi::Cast(index.constant()).Value());
+ ASSERT(index_scale() == 1);
if (index.IsRegister()) {
__ SmiUntag(index.reg());
}
@@ -1199,13 +1207,17 @@
FieldAddress element_address = index.IsRegister()
? FlowGraphCompiler::ElementAddressForRegIndex(
- class_id(), array, index.reg())
+ class_id(), index_scale(), array, index.reg())
: FlowGraphCompiler::ElementAddressForIntIndex(
- class_id(), array, Smi::Cast(index.constant()).Value());
+ class_id(), index_scale(), array,
+ Smi::Cast(index.constant()).Value());
if ((representation() == kUnboxedDouble) ||
(representation() == kUnboxedMint)) {
XmmRegister result = locs()->out().fpu_reg();
+ if ((index_scale() == 1) && index.IsRegister()) {
+ __ SmiUntag(index.reg());
+ }
switch (class_id()) {
case kInt32ArrayCid:
__ movss(result, element_address);
@@ -1224,27 +1236,28 @@
__ movsd(result, element_address);
break;
}
+ if ((index_scale() == 1) && index.IsRegister()) {
+ __ SmiTag(index.reg()); // Re-tag.
+ }
return;
}
Register result = locs()->out().reg();
+ if ((index_scale() == 1) && index.IsRegister()) {
+ __ SmiUntag(index.reg());
+ }
switch (class_id()) {
case kInt8ArrayCid:
case kUint8ArrayCid:
case kUint8ClampedArrayCid:
case kOneByteStringCid:
- if (index.IsRegister()) {
- __ SmiUntag(index.reg());
- }
+ ASSERT(index_scale() == 1);
if (class_id() == kInt8ArrayCid) {
__ movsxb(result, element_address);
} else {
__ movzxb(result, element_address);
}
__ SmiTag(result);
- if (index.IsRegister()) {
- __ SmiTag(index.reg()); // Re-tag.
- }
break;
case kInt16ArrayCid:
__ movsxw(result, element_address);
@@ -1278,6 +1291,9 @@
__ movl(result, element_address);
break;
}
+ if ((index_scale() == 1) && index.IsRegister()) {
+ __ SmiTag(index.reg()); // Re-tag.
+ }
}
@@ -1358,11 +1374,13 @@
Register array = locs()->in(0).reg();
Location index = locs()->in(1);
+ intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(class_id());
+
FieldAddress element_address = index.IsRegister() ?
FlowGraphCompiler::ElementAddressForRegIndex(
- class_id(), array, index.reg()) :
+ class_id(), index_scale, array, index.reg()) :
FlowGraphCompiler::ElementAddressForIntIndex(
- class_id(), array, Smi::Cast(index.constant()).Value());
+ class_id(), index_scale, array, Smi::Cast(index.constant()).Value());
switch (class_id()) {
case kArrayCid:
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index b0d714a..c0e93f9 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -459,7 +459,11 @@
ASSERT((ic_data.GetReceiverClassIdAt(i) != kSmiCid) || (i == 0));
Label next_test;
__ cmpq(temp, Immediate(ic_data.GetReceiverClassIdAt(i)));
- __ j(NOT_EQUAL, &next_test);
+ if (i < len - 1) {
+ __ j(NOT_EQUAL, &next_test);
+ } else {
+ __ j(NOT_EQUAL, deopt);
+ }
const Function& target = Function::ZoneHandle(ic_data.GetTargetAt(i));
if (target.Owner() == object_store->object_class()) {
// Object.== is same as ===.
@@ -495,7 +499,6 @@
__ jmp(&done);
__ Bind(&false_label);
__ LoadObject(RAX, Bool::False());
- __ jmp(&done);
}
} else {
if (branch->is_checked()) {
@@ -505,11 +508,11 @@
branch->EmitBranchOnCondition(compiler, cond);
}
}
- __ jmp(&done);
- __ Bind(&next_test);
+ if (i < len - 1) {
+ __ jmp(&done);
+ __ Bind(&next_test);
+ }
}
- // Fall through leads to deoptimization
- __ jmp(deopt);
__ Bind(&done);
}
@@ -970,6 +973,7 @@
case kUint8ArrayCid:
case kUint8ClampedArrayCid:
case kExternalUint8ArrayCid:
+ case kExternalUint8ClampedArrayCid:
case kInt16ArrayCid:
case kUint16ArrayCid:
case kOneByteStringCid:
@@ -992,6 +996,7 @@
case kUint8ArrayCid:
case kUint8ClampedArrayCid:
case kExternalUint8ArrayCid:
+ case kExternalUint8ClampedArrayCid:
case kInt16ArrayCid:
case kUint16ArrayCid:
case kOneByteStringCid:
@@ -1034,13 +1039,16 @@
Register array = locs()->in(0).reg();
Location index = locs()->in(1);
- if (class_id() == kExternalUint8ArrayCid) {
+ if ((class_id() == kExternalUint8ArrayCid) ||
+ (class_id() == kExternalUint8ClampedArrayCid)) {
Register result = locs()->out().reg();
Address element_address = index.IsRegister()
? FlowGraphCompiler::ExternalElementAddressForRegIndex(
- class_id(), result, index.reg())
+ class_id(), index_scale(), result, index.reg())
: FlowGraphCompiler::ExternalElementAddressForIntIndex(
- class_id(), result, Smi::Cast(index.constant()).Value());
+ class_id(), index_scale(), result,
+ Smi::Cast(index.constant()).Value());
+ ASSERT(index_scale() == 1);
if (index.IsRegister()) {
__ SmiUntag(index.reg());
}
@@ -1054,13 +1062,18 @@
return;
}
- FieldAddress element_address = index.IsRegister() ?
- FlowGraphCompiler::ElementAddressForRegIndex(
- class_id(), array, index.reg()) :
- FlowGraphCompiler::ElementAddressForIntIndex(
- class_id(), array, Smi::Cast(index.constant()).Value());
+ FieldAddress element_address = index.IsRegister()
+ ? FlowGraphCompiler::ElementAddressForRegIndex(
+ class_id(), index_scale(), array, index.reg())
+ : FlowGraphCompiler::ElementAddressForIntIndex(
+ class_id(), index_scale(), array,
+ Smi::Cast(index.constant()).Value());
if (representation() == kUnboxedDouble) {
+ if ((index_scale() == 1) && index.IsRegister()) {
+ __ SmiUntag(index.reg());
+ }
+
XmmRegister result = locs()->out().fpu_reg();
if (class_id() == kFloat32ArrayCid) {
// Load single precision float.
@@ -1071,27 +1084,28 @@
ASSERT(class_id() == kFloat64ArrayCid);
__ movsd(result, element_address);
}
+
+ if ((index_scale() == 1) && index.IsRegister()) {
+ __ SmiTag(index.reg()); // Re-tag.
+ }
return;
}
+ if ((index_scale() == 1) && index.IsRegister()) {
+ __ SmiUntag(index.reg());
+ }
Register result = locs()->out().reg();
switch (class_id()) {
case kInt8ArrayCid:
case kUint8ArrayCid:
case kUint8ClampedArrayCid:
case kOneByteStringCid:
- if (index.IsRegister()) {
- __ SmiUntag(index.reg());
- }
if (class_id() == kInt8ArrayCid) {
__ movsxb(result, element_address);
} else {
__ movzxb(result, element_address);
}
__ SmiTag(result);
- if (index.IsRegister()) {
- __ SmiTag(index.reg()); // Re-tag.
- }
break;
case kInt16ArrayCid:
__ movsxw(result, element_address);
@@ -1115,6 +1129,9 @@
__ movq(result, element_address);
break;
}
+ if ((index_scale() == 1) && index.IsRegister()) {
+ __ SmiTag(index.reg()); // Re-tag.
+ }
}
@@ -1194,11 +1211,14 @@
Register array = locs()->in(0).reg();
Location index = locs()->in(1);
- FieldAddress element_address = index.IsRegister() ?
- FlowGraphCompiler::ElementAddressForRegIndex(
- class_id(), array, index.reg()) :
- FlowGraphCompiler::ElementAddressForIntIndex(
- class_id(), array, Smi::Cast(index.constant()).Value());
+ intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(class_id());
+
+ FieldAddress element_address = index.IsRegister()
+ ? FlowGraphCompiler::ElementAddressForRegIndex(
+ class_id(), index_scale, array, index.reg())
+ : FlowGraphCompiler::ElementAddressForIntIndex(
+ class_id(), index_scale, array,
+ Smi::Cast(index.constant()).Value());
switch (class_id()) {
case kArrayCid:
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index fc20192..a3b4559 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -1787,9 +1787,8 @@
// Shared handles used during the iteration.
String& member_name = String::Handle();
- const Script& patch_script = Script::Handle(patch.script());
- const PatchClass& patch_class = PatchClass::Handle(
- PatchClass::New(*this, patch_script));
+ const PatchClass& patch_class =
+ PatchClass::Handle(PatchClass::New(*this, patch));
Array& orig_list = Array::Handle(functions());
intptr_t orig_len = orig_list.Length();
@@ -1853,6 +1852,10 @@
new_list.SetAt(patch_len + i, field);
}
SetFields(new_list);
+
+ // The functions and fields in the patch class are no longer needed.
+ patch.SetFunctions(Object::empty_array());
+ patch.SetFields(Object::empty_array());
return NULL;
}
@@ -3246,10 +3249,10 @@
RawPatchClass* PatchClass::New(const Class& patched_class,
- const Script& script) {
+ const Class& source_class) {
const PatchClass& result = PatchClass::Handle(PatchClass::New());
result.set_patched_class(patched_class);
- result.set_script(script);
+ result.set_source_class(source_class);
return result.raw();
}
@@ -3263,13 +3266,19 @@
}
+RawScript* PatchClass::Script() const {
+ const Class& source_class = Class::Handle(this->source_class());
+ return source_class.script();
+}
+
+
void PatchClass::set_patched_class(const Class& value) const {
StorePointer(&raw_ptr()->patched_class_, value.raw());
}
-void PatchClass::set_script(const Script& value) const {
- StorePointer(&raw_ptr()->script_, value.raw());
+void PatchClass::set_source_class(const Class& value) const {
+ StorePointer(&raw_ptr()->source_class_, value.raw());
}
@@ -4375,7 +4384,7 @@
return Class::Cast(obj).script();
}
ASSERT(obj.IsPatchClass());
- return PatchClass::Cast(obj).script();
+ return PatchClass::Cast(obj).Script();
}
@@ -6207,7 +6216,7 @@
void Library::InitASyncLibrary(Isolate* isolate) {
- const String& url = String::Handle(Symbols::New("dart:async"));
+ const String& url = Symbols::DartAsync();
const Library& lib = Library::Handle(Library::NewLibraryHelper(url, true));
lib.Register();
isolate->object_store()->set_async_library(lib);
@@ -6215,7 +6224,7 @@
void Library::InitCoreLibrary(Isolate* isolate) {
- const String& core_lib_url = String::Handle(Symbols::New("dart:core"));
+ const String& core_lib_url = Symbols::DartCore();
const Library& core_lib =
Library::Handle(Library::NewLibraryHelper(core_lib_url, false));
core_lib.Register();
@@ -6248,7 +6257,7 @@
void Library::InitCollectionLibrary(Isolate* isolate) {
- const String& url = String::Handle(Symbols::New("dart:collection"));
+ const String& url = Symbols::DartCollection();
const Library& lib = Library::Handle(Library::NewLibraryHelper(url, true));
lib.Register();
const Library& math_lib = Library::Handle(Library::MathLibrary());
@@ -6265,7 +6274,7 @@
void Library::InitCollectionDevLibrary(Isolate* isolate) {
- const String& url = String::Handle(Symbols::New("dart:collection-dev"));
+ const String& url = Symbols::DartCollectionDev();
const Library& lib = Library::Handle(Library::NewLibraryHelper(url, true));
lib.Register();
isolate->object_store()->set_collection_dev_library(lib);
@@ -6273,7 +6282,7 @@
void Library::InitMathLibrary(Isolate* isolate) {
- const String& url = String::Handle(Symbols::New("dart:math"));
+ const String& url = Symbols::DartMath();
const Library& lib = Library::Handle(Library::NewLibraryHelper(url, true));
lib.Register();
isolate->object_store()->set_math_library(lib);
@@ -6281,7 +6290,7 @@
void Library::InitIsolateLibrary(Isolate* isolate) {
- const String& url = String::Handle(Symbols::New("dart:isolate"));
+ const String& url = Symbols::DartIsolate();
const Library& lib = Library::Handle(Library::NewLibraryHelper(url, true));
lib.Register();
const Library& async_lib = Library::Handle(Library::ASyncLibrary());
@@ -6293,7 +6302,7 @@
void Library::InitMirrorsLibrary(Isolate* isolate) {
- const String& url = String::Handle(Symbols::New("dart:mirrors"));
+ const String& url = Symbols::DartMirrors();
const Library& lib = Library::Handle(Library::NewLibraryHelper(url, true));
lib.Register();
const Library& isolate_lib = Library::Handle(Library::IsolateLibrary());
@@ -6314,7 +6323,7 @@
void Library::InitScalarlistLibrary(Isolate* isolate) {
- const String& url = String::Handle(Symbols::New("dart:scalarlist"));
+ const String& url = Symbols::DartScalarlist();
const Library& lib = Library::Handle(Library::NewLibraryHelper(url, true));
lib.Register();
const Library& collection_lib =
@@ -6329,8 +6338,7 @@
void Library::InitNativeWrappersLibrary(Isolate* isolate) {
static const int kNumNativeWrappersClasses = 4;
ASSERT(kNumNativeWrappersClasses > 0 && kNumNativeWrappersClasses < 10);
- const String& native_flds_lib_url = String::Handle(
- Symbols::New("dart:nativewrappers"));
+ const String& native_flds_lib_url = Symbols::DartNativeWrappers();
const Library& native_flds_lib = Library::Handle(
Library::NewLibraryHelper(native_flds_lib_url, false));
native_flds_lib.Register();
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 0a64f79..b10e24c 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -1146,17 +1146,19 @@
class PatchClass : public Object {
public:
RawClass* patched_class() const { return raw_ptr()->patched_class_; }
- RawScript* script() const { return raw_ptr()->script_; }
+ RawClass* source_class() const { return raw_ptr()->source_class_; }
+ RawScript* Script() const;
static intptr_t InstanceSize() {
return RoundedAllocationSize(sizeof(RawPatchClass));
}
- static RawPatchClass* New(const Class& patched_class, const Script& script);
+ static RawPatchClass* New(const Class& patched_class,
+ const Class& source_class);
private:
void set_patched_class(const Class& value) const;
- void set_script(const Script& value) const;
+ void set_source_class(const Class& value) const;
static RawPatchClass* New();
FINAL_HEAP_OBJECT_IMPLEMENTATION(PatchClass, Object);
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index 3513e79..34dee42 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -194,7 +194,7 @@
Type::ZoneHandle(Type::DynamicType()));
context_var->set_index(next_free_frame_index--);
scope->AddVariable(context_var);
- set_saved_context_var(context_var);
+ set_saved_entry_context_var(context_var);
}
}
@@ -265,7 +265,8 @@
current_class_(Class::Handle()),
library_(library),
try_blocks_list_(NULL),
- expression_temp_(NULL) {
+ expression_temp_(NULL),
+ saved_current_context_(NULL) {
ASSERT(tokens_iterator_.IsValid());
ASSERT(!library.IsNull());
}
@@ -287,7 +288,8 @@
current_class_(Class::Handle(current_function_.Owner())),
library_(Library::Handle(current_class_.library())),
try_blocks_list_(NULL),
- expression_temp_(NULL) {
+ expression_temp_(NULL),
+ saved_current_context_(NULL) {
ASSERT(tokens_iterator_.IsValid());
ASSERT(!function.IsNull());
if (FLAG_enable_type_checks) {
@@ -769,6 +771,12 @@
if (parsed_function->has_expression_temp_var()) {
node_sequence->scope()->AddVariable(parsed_function->expression_temp_var());
}
+ if (parser.saved_current_context_ != NULL) {
+ parsed_function->set_saved_current_context_var(
+ parser.saved_current_context_);
+ node_sequence->scope()->AddVariable(
+ parsed_function->saved_current_context_var());
+ }
parsed_function->SetNodeSequence(node_sequence);
// The instantiator may be required at run time for generic type checks or
@@ -1452,7 +1460,7 @@
/* is_super_getter */ true,
super_class,
function_name);
- EnsureExpressionTemp();
+ EnsureSavedCurrentContext();
// 'this' is not passed as parameter to the closure.
ArgumentListNode* closure_arguments = new ArgumentListNode(supercall_pos);
for (int i = 1; i < arguments->length(); i++) {
@@ -4255,6 +4263,13 @@
const Namespace& ns =
Namespace::Handle(Namespace::New(library, show_names, hide_names));
if (is_import) {
+ // Ensure that private dart:_ libraries are only imported into dart:
+ // libraries.
+ const String& lib_url = String::Handle(library_.url());
+ if (canon_url.StartsWith(Symbols::DartSchemePrivate()) &&
+ !lib_url.StartsWith(Symbols::DartScheme())) {
+ ErrorMsg(import_pos, "private library is not accessible");
+ }
if (prefix.IsNull() || (prefix.Length() == 0)) {
library_.AddImport(ns);
} else {
@@ -5792,7 +5807,7 @@
if (condition->IsClosureNode() ||
(condition->IsStoreLocalNode() &&
condition->AsStoreLocalNode()->value()->IsClosureNode())) {
- EnsureExpressionTemp();
+ EnsureSavedCurrentContext();
// Function literal in assert implies a call.
const intptr_t pos = condition->token_pos();
condition = new ClosureCallNode(pos, condition, new ArgumentListNode(pos));
@@ -5931,9 +5946,10 @@
TRACE_PARSER("ParseTryStatement");
// We create three stack slots for exceptions here:
- // ':saved_context_var' - Used to save the context before start of the try
- // block. The context register is restored from this
- // slot before processing the catch block handler.
+ // ':saved_try_context_var' - Used to save the context before start of the try
+ // block. The context register is restored from
+ // this slot before processing the catch block
+ // handler.
// ':exception_var' - Used to save the current exception object that was
// thrown.
// ':stacktrace_var' - Used to save the current stack trace object into which
@@ -5943,10 +5959,10 @@
// and the stacktrace object when an exception is thrown.
// These three implicit variables can never be captured variables.
LocalVariable* context_var =
- current_block_->scope->LocalLookupVariable(Symbols::SavedContextVar());
+ current_block_->scope->LocalLookupVariable(Symbols::SavedTryContextVar());
if (context_var == NULL) {
context_var = new LocalVariable(TokenPos(),
- Symbols::SavedContextVar(),
+ Symbols::SavedTryContextVar(),
Type::ZoneHandle(Type::DynamicType()));
current_block_->scope->AddVariable(context_var);
}
@@ -6782,6 +6798,19 @@
}
+void Parser::EnsureSavedCurrentContext() {
+ // Used later by the flow_graph_builder to save current context.
+ if (saved_current_context_ == NULL) {
+ // Allocate a local variable to save the current context when we call into
+ // any closure function as the call will destroy the current context.
+ saved_current_context_ =
+ new LocalVariable(current_function().token_pos(),
+ Symbols::SavedCurrentContextVar(),
+ Type::ZoneHandle(Type::DynamicType()));
+ }
+}
+
+
LocalVariable* Parser::CreateTempConstVariable(intptr_t token_pos,
const char* s) {
char name[64];
@@ -7222,7 +7251,7 @@
Resolver::kIsQualified);
if (!func.IsNull()) {
ASSERT(func.kind() != RawFunction::kConstImplicitGetter);
- EnsureExpressionTemp();
+ EnsureSavedCurrentContext();
closure = new StaticGetterNode(call_pos,
NULL,
false,
@@ -7231,7 +7260,7 @@
return new ClosureCallNode(call_pos, closure, arguments);
}
} else {
- EnsureExpressionTemp();
+ EnsureSavedCurrentContext();
closure = GenerateStaticFieldLookup(field, call_pos);
return new ClosureCallNode(call_pos, closure, arguments);
}
@@ -7257,7 +7286,7 @@
TRACE_PARSER("ParseClosureCall");
const intptr_t call_pos = TokenPos();
ASSERT(CurrentToken() == Token::kLPAREN);
- EnsureExpressionTemp();
+ EnsureSavedCurrentContext();
ArgumentListNode* arguments = ParseActualParameters(NULL, kAllowConst);
return new ClosureCallNode(call_pos, closure, arguments);
}
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index 5fa2eca..53b3bfc 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -37,7 +37,8 @@
node_sequence_(NULL),
instantiator_(NULL),
default_parameter_values_(Array::ZoneHandle()),
- saved_context_var_(NULL),
+ saved_current_context_var_(NULL),
+ saved_entry_context_var_(NULL),
expression_temp_var_(NULL),
first_parameter_index_(0),
first_stack_local_index_(0),
@@ -65,10 +66,20 @@
default_parameter_values_ = default_parameter_values.raw();
}
- LocalVariable* saved_context_var() const { return saved_context_var_; }
- void set_saved_context_var(LocalVariable* saved_context_var) {
- ASSERT(saved_context_var != NULL);
- saved_context_var_ = saved_context_var;
+ LocalVariable* saved_current_context_var() const {
+ return saved_current_context_var_;
+ }
+ void set_saved_current_context_var(LocalVariable* saved_current_context_var) {
+ ASSERT(saved_current_context_var != NULL);
+ saved_current_context_var_ = saved_current_context_var;
+ }
+
+ LocalVariable* saved_entry_context_var() const {
+ return saved_entry_context_var_;
+ }
+ void set_saved_entry_context_var(LocalVariable* saved_entry_context_var) {
+ ASSERT(saved_entry_context_var != NULL);
+ saved_entry_context_var_ = saved_entry_context_var;
}
// Returns NULL if this function does not save the arguments descriptor on
@@ -100,7 +111,8 @@
SequenceNode* node_sequence_;
AstNode* instantiator_;
Array& default_parameter_values_;
- LocalVariable* saved_context_var_;
+ LocalVariable* saved_current_context_var_;
+ LocalVariable* saved_entry_context_var_;
LocalVariable* expression_temp_var_;
int first_parameter_index_;
@@ -582,6 +594,7 @@
const LocalVariable* GetIncrementTempLocal();
void EnsureExpressionTemp();
+ void EnsureSavedCurrentContext();
AstNode* CreateAssignmentNode(AstNode* original, AstNode* rhs);
AstNode* InsertClosureCallNodes(AstNode* condition);
@@ -631,6 +644,9 @@
// Allocate temporary only once per function.
LocalVariable* expression_temp_;
+ // Allocate saved current context only if needed.
+ LocalVariable* saved_current_context_;
+
DISALLOW_COPY_AND_ASSIGN(Parser);
};
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index b997520..ac66f62 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -527,9 +527,9 @@
return reinterpret_cast<RawObject**>(&ptr()->patched_class_);
}
RawClass* patched_class_;
- RawScript* script_;
+ RawClass* source_class_;
RawObject** to() {
- return reinterpret_cast<RawObject**>(&ptr()->script_);
+ return reinterpret_cast<RawObject**>(&ptr()->source_class_);
}
};
diff --git a/runtime/vm/scopes.cc b/runtime/vm/scopes.cc
index d5bf92a..86dceae 100644
--- a/runtime/vm/scopes.cc
+++ b/runtime/vm/scopes.cc
@@ -259,7 +259,7 @@
desc.info.index = var->index();
vars->Add(desc);
} else if (var->name().Equals(
- Symbols::Name(Symbols::kSavedEntryContextVarId))) {
+ Symbols::Name(Symbols::kSavedCurrentContextVarId))) {
// This is the local variable in which the function saves the
// caller's chain of closure contexts (caller's CTX register).
VarDesc desc;
diff --git a/runtime/vm/simulator_arm.cc b/runtime/vm/simulator_arm.cc
index 0b4d1bc..952ab88 100644
--- a/runtime/vm/simulator_arm.cc
+++ b/runtime/vm/simulator_arm.cc
@@ -37,11 +37,11 @@
class StatsCounter {
public:
explicit StatsCounter(const char* name) {
- UNIMPLEMENTED();
+ // UNIMPLEMENTED();
}
void Increment() {
- UNIMPLEMENTED();
+ // UNIMPLEMENTED();
}
};
@@ -651,7 +651,10 @@
Simulator::~Simulator() {
delete[] stack_;
- Isolate::Current()->set_simulator(NULL);
+ Isolate* isolate = Isolate::Current();
+ if (isolate != NULL) {
+ isolate->set_simulator(NULL);
+ }
}
diff --git a/runtime/vm/simulator_mips.cc b/runtime/vm/simulator_mips.cc
index fe3c275..56d73eb 100644
--- a/runtime/vm/simulator_mips.cc
+++ b/runtime/vm/simulator_mips.cc
@@ -22,13 +22,38 @@
Simulator::~Simulator() {
- UNIMPLEMENTED();
+ Isolate* isolate = Isolate::Current();
+ if (isolate != NULL) {
+ isolate->set_simulator(NULL);
+ }
+}
+
+
+// Get the active Simulator for the current isolate.
+Simulator* Simulator::Current() {
+ Simulator* simulator = Isolate::Current()->simulator();
+ if (simulator == NULL) {
+ simulator = new Simulator();
+ Isolate::Current()->set_simulator(simulator);
+ }
+ return simulator;
}
void Simulator::InitOnce() {
}
+
+int64_t Simulator::Call(int32_t entry,
+ int32_t parameter0,
+ int32_t parameter1,
+ int32_t parameter2,
+ int32_t parameter3,
+ int32_t parameter4) {
+ UNIMPLEMENTED();
+ return 0LL;
+}
+
} // namespace dart
#endif // !defined(HOST_ARCH_MIPS)
diff --git a/runtime/vm/simulator_mips.h b/runtime/vm/simulator_mips.h
index 8541815..b852ebb 100644
--- a/runtime/vm/simulator_mips.h
+++ b/runtime/vm/simulator_mips.h
@@ -23,8 +23,22 @@
Simulator();
~Simulator();
+ // The currently executing Simulator instance, which is associated to the
+ // current isolate
+ static Simulator* Current();
+
// Call on program start.
static void InitOnce();
+
+ // Dart generally calls into generated code with 5 parameters. This is a
+ // convenience function, which sets up the simulator state and grabs the
+ // result on return.
+ int64_t Call(int32_t entry,
+ int32_t parameter0,
+ int32_t parameter1,
+ int32_t parameter2,
+ int32_t parameter3,
+ int32_t parameter4);
};
} // namespace dart
diff --git a/runtime/vm/stack_frame.cc b/runtime/vm/stack_frame.cc
index d4306f5..ca20583 100644
--- a/runtime/vm/stack_frame.cc
+++ b/runtime/vm/stack_frame.cc
@@ -35,6 +35,11 @@
}
+RawContext* EntryFrame::SavedContext() const {
+ return *(reinterpret_cast<RawContext**>(fp() + SavedContextOffset()));
+}
+
+
void EntryFrame::VisitObjectPointers(ObjectPointerVisitor* visitor) {
// Visit objects between SP and (FP - callee_save_area).
ASSERT(visitor != NULL);
diff --git a/runtime/vm/stack_frame.h b/runtime/vm/stack_frame.h
index c4dd50dd..483f212 100644
--- a/runtime/vm/stack_frame.h
+++ b/runtime/vm/stack_frame.h
@@ -13,6 +13,7 @@
// Forward declarations.
class ObjectPointerVisitor;
+class RawContext;
// Generic stack frame.
@@ -118,6 +119,8 @@
bool IsStubFrame() const { return false; }
bool IsEntryFrame() const { return true; }
+ RawContext* SavedContext() const;
+
// Visit objects in the frame.
virtual void VisitObjectPointers(ObjectPointerVisitor* visitor);
@@ -126,7 +129,8 @@
private:
EntryFrame() { }
- intptr_t ExitLinkOffset();
+ intptr_t ExitLinkOffset() const;
+ intptr_t SavedContextOffset() const;
friend class StackFrameIterator;
DISALLOW_COPY_AND_ASSIGN(EntryFrame);
diff --git a/runtime/vm/stack_frame_arm.cc b/runtime/vm/stack_frame_arm.cc
index 1273a01..2d90b32 100644
--- a/runtime/vm/stack_frame_arm.cc
+++ b/runtime/vm/stack_frame_arm.cc
@@ -27,7 +27,13 @@
}
-intptr_t EntryFrame::ExitLinkOffset() {
+intptr_t EntryFrame::ExitLinkOffset() const {
+ UNIMPLEMENTED();
+ return 0;
+}
+
+
+intptr_t EntryFrame::SavedContextOffset() const {
UNIMPLEMENTED();
return 0;
}
diff --git a/runtime/vm/stack_frame_ia32.cc b/runtime/vm/stack_frame_ia32.cc
index 67051bb..b3f554e 100644
--- a/runtime/vm/stack_frame_ia32.cc
+++ b/runtime/vm/stack_frame_ia32.cc
@@ -13,6 +13,7 @@
// The constant kExitLinkOffsetInEntryFrame must be kept in sync with the
// code in the InvokeDartCode stub.
+static const int kSavedContextOffsetInEntryFrame = -5 * kWordSize;
static const int kExitLinkOffsetInEntryFrame = -4 * kWordSize;
static const int kPcAddressOffsetFromSp = -1 * kWordSize;
static const int kSpOffsetFromPreviousFp = 2 * kWordSize;
@@ -33,11 +34,16 @@
}
-intptr_t EntryFrame::ExitLinkOffset() {
+intptr_t EntryFrame::ExitLinkOffset() const {
return kExitLinkOffsetInEntryFrame;
}
+intptr_t EntryFrame::SavedContextOffset() const {
+ return kSavedContextOffsetInEntryFrame;
+}
+
+
void StackFrameIterator::SetupLastExitFrameData() {
Isolate* current = Isolate::Current();
uword exit_marker = current->top_exit_frame_info();
diff --git a/runtime/vm/stack_frame_mips.cc b/runtime/vm/stack_frame_mips.cc
index 500a8e6..eb79f18 100644
--- a/runtime/vm/stack_frame_mips.cc
+++ b/runtime/vm/stack_frame_mips.cc
@@ -27,7 +27,13 @@
}
-intptr_t EntryFrame::ExitLinkOffset() {
+intptr_t EntryFrame::ExitLinkOffset() const {
+ UNIMPLEMENTED();
+ return 0;
+}
+
+
+intptr_t EntryFrame::SavedContextOffset() const {
UNIMPLEMENTED();
return 0;
}
diff --git a/runtime/vm/stack_frame_x64.cc b/runtime/vm/stack_frame_x64.cc
index 2650b30..d0ae422 100644
--- a/runtime/vm/stack_frame_x64.cc
+++ b/runtime/vm/stack_frame_x64.cc
@@ -13,6 +13,7 @@
// The constant kExitLinkOffsetInEntryFrame must be kept in sync with the
// code in the InvokeDartCode stub.
+static const int kSavedContextOffsetInEntryFrame = -9 * kWordSize;
static const int kExitLinkOffsetInEntryFrame = -8 * kWordSize;
static const int kPcAddressOffsetFromSp = -1 * kWordSize;
static const int kSpOffsetFromPreviousFp = 2 * kWordSize;
@@ -33,11 +34,16 @@
}
-intptr_t EntryFrame::ExitLinkOffset() {
+intptr_t EntryFrame::ExitLinkOffset() const {
return kExitLinkOffsetInEntryFrame;
}
+intptr_t EntryFrame::SavedContextOffset() const {
+ return kSavedContextOffsetInEntryFrame;
+}
+
+
void StackFrameIterator::SetupLastExitFrameData() {
Isolate* current = Isolate::Current();
uword exit_marker = current->top_exit_frame_info();
diff --git a/runtime/vm/stub_code_ia32.cc b/runtime/vm/stub_code_ia32.cc
index bc47212..387a52d 100644
--- a/runtime/vm/stub_code_ia32.cc
+++ b/runtime/vm/stub_code_ia32.cc
@@ -745,18 +745,20 @@
__ movl(EDI, FieldAddress(CTX, Context::isolate_offset()));
// Save the top exit frame info. Use EDX as a temporary register.
+ // StackFrameIterator reads the top exit frame info saved in this frame.
+ // The constant kExitLinkOffsetInEntryFrame must be kept in sync with the
+ // code below: kExitLinkOffsetInEntryFrame = -4 * kWordSize.
__ movl(EDX, Address(EDI, Isolate::top_exit_frame_info_offset()));
__ pushl(EDX);
__ movl(Address(EDI, Isolate::top_exit_frame_info_offset()), Immediate(0));
- // StackFrameIterator reads the top exit frame info saved in this frame.
- // The constant kExitLinkOffsetInEntryFrame must be kept in sync with the
- // code above.
-
// Save the old Context pointer. Use ECX as a temporary register.
// Note that VisitObjectPointers will find this saved Context pointer during
// GC marking, since it traverses any information between SP and
// FP - kExitLinkOffsetInEntryFrame.
+ // EntryFrame::SavedContext reads the context saved in this frame.
+ // The constant kSavedContextOffsetInEntryFrame must be kept in sync with
+ // the code below: kSavedContextOffsetInEntryFrame = -5 * kWordSize.
__ movl(ECX, Address(EDI, Isolate::top_context_offset()));
__ pushl(ECX);
@@ -1270,7 +1272,7 @@
__ movl(EDX, FieldAddress(CTX, Context::isolate_offset()));
__ movl(Address(ECX, Context::isolate_offset()), EDX);
- // Set the parent field to null.
+ // Set the parent to null.
__ movl(Address(ECX, Context::parent_offset()), raw_null);
// Initialize the context variable to the receiver.
diff --git a/runtime/vm/stub_code_x64.cc b/runtime/vm/stub_code_x64.cc
index 70d9c36..de2b1de 100644
--- a/runtime/vm/stub_code_x64.cc
+++ b/runtime/vm/stub_code_x64.cc
@@ -735,18 +735,20 @@
__ movq(R8, FieldAddress(CTX, Context::isolate_offset()));
// Save the top exit frame info. Use RAX as a temporary register.
+ // StackFrameIterator reads the top exit frame info saved in this frame.
+ // The constant kExitLinkOffsetInEntryFrame must be kept in sync with the
+ // code below: kExitLinkOffsetInEntryFrame = -8 * kWordSize.
__ movq(RAX, Address(R8, Isolate::top_exit_frame_info_offset()));
__ pushq(RAX);
__ movq(Address(R8, Isolate::top_exit_frame_info_offset()), Immediate(0));
- // StackFrameIterator reads the top exit frame info saved in this frame.
- // The constant kExitLinkOffsetInEntryFrame must be kept in sync with the
- // code above: kExitLinkOffsetInEntryFrame = -8 * kWordSize.
-
// Save the old Context pointer. Use RAX as a temporary register.
// Note that VisitObjectPointers will find this saved Context pointer during
// GC marking, since it traverses any information between SP and
// FP - kExitLinkOffsetInEntryFrame.
+ // EntryFrame::SavedContext reads the context saved in this frame.
+ // The constant kSavedContextOffsetInEntryFrame must be kept in sync with
+ // the code below: kSavedContextOffsetInEntryFrame = -9 * kWordSize.
__ movq(RAX, Address(R8, Isolate::top_context_offset()));
__ pushq(RAX);
@@ -1258,7 +1260,7 @@
__ movq(R10, FieldAddress(CTX, Context::isolate_offset()));
__ movq(Address(RBX, Context::isolate_offset()), R10);
- // Set the parent field to null.
+ // Set the parent to null.
__ movq(Address(RBX, Context::parent_offset()), raw_null);
// Initialize the context variable to the receiver.
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index 1ab5563..caec906 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -54,8 +54,9 @@
V(GetIterator, "iterator") \
V(NoSuchMethod, "noSuchMethod") \
V(SavedArgDescVarPrefix, ":saved_args_desc_var") \
+ V(SavedCurrentContextVar, ":saved_current_context_var") \
V(SavedEntryContextVar, ":saved_entry_context_var") \
- V(SavedContextVar, ":saved_context_var") \
+ V(SavedTryContextVar, ":saved_try_context_var") \
V(ExceptionVar, ":exception_var") \
V(StacktraceVar, ":stacktrace_var") \
V(ListLiteralElement, "list literal element") \
@@ -191,6 +192,17 @@
V(PrivateGetterPrefix, "get:_") \
V(PrivateSetterPrefix, "set:_") \
V(_New, "_new") \
+ V(DartScheme, "dart:") \
+ V(DartSchemePrivate, "dart:_") \
+ V(DartCore, "dart:core") \
+ V(DartCollection, "dart:collection") \
+ V(DartCollectionDev, "dart:_collection-dev") \
+ V(DartMath, "dart:math") \
+ V(DartIsolate, "dart:isolate") \
+ V(DartMirrors, "dart:mirrors") \
+ V(DartScalarlist, "dart:scalarlist") \
+ V(DartNativeWrappers, "dart:nativewrappers") \
+ V(DartAsync, "dart:async") \
// Contains a list of frequently used strings in a canonicalized form. This
diff --git a/runtime/vm/unit_test.h b/runtime/vm/unit_test.h
index 7859a5e..bd15b1e 100644
--- a/runtime/vm/unit_test.h
+++ b/runtime/vm/unit_test.h
@@ -15,6 +15,7 @@
#include "vm/longjump.h"
#include "vm/object.h"
#include "vm/object_store.h"
+#include "vm/simulator.h"
#include "vm/zone.h"
// The UNIT_TEST_CASE macro is used for tests that do not need any
@@ -128,6 +129,49 @@
}
+#if defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_MIPS)
+#if defined(HOST_ARCH_ARM) || defined(HOST_ARCH_MIPS)
+// Running on actual ARM or MIPS hardware, execute code natively.
+#define EXECUTE_TEST_CODE_INT32(name, entry) reinterpret_cast<name>(entry)()
+#define EXECUTE_TEST_CODE_INT64_LL(name, entry, long_arg0, long_arg1) \
+ reinterpret_cast<name>(entry)(long_arg0, long_arg1)
+#define EXECUTE_TEST_CODE_FLOAT(name, entry) reinterpret_cast<name>(entry)()
+#define EXECUTE_TEST_CODE_DOUBLE(name, entry) reinterpret_cast<name>(entry)()
+#define EXECUTE_TEST_CODE_INT32_F(name, entry, float_arg) \
+ reinterpret_cast<name>(entry)(float_arg)
+#define EXECUTE_TEST_CODE_INT32_D(name, entry, double_arg) \
+ reinterpret_cast<name>(entry)(double_arg)
+#else
+// Not running on ARM or MIPS hardware, call simulator to execute code.
+#define EXECUTE_TEST_CODE_INT32(name, entry) \
+ static_cast<int32_t>(Simulator::Current()->Call((int32_t)entry, \
+ 0, 0, 0, 0, 0))
+#define EXECUTE_TEST_CODE_INT64_LL(name, entry, long_arg0, long_arg1) \
+ static_cast<int64_t>(Simulator::Current()->Call((int32_t)entry, \
+ Utils::Low32Bits(long_arg0), \
+ Utils::High32Bits(long_arg0), \
+ Utils::Low32Bits(long_arg1), \
+ Utils::High32Bits(long_arg1), \
+ 0))
+#define EXECUTE_TEST_CODE_FLOAT(name, entry) \
+ bit_cast<float, int32_t>(Simulator::Current()->Call((int32_t)entry, \
+ 0, 0, 0, 0, 0))
+#define EXECUTE_TEST_CODE_DOUBLE(name, entry) \
+ bit_cast<double, int64_t>(Simulator::Current()->Call((int32_t)entry, \
+ 0, 0, 0, 0, 0))
+#define EXECUTE_TEST_CODE_INT32_F(name, entry, float_arg) \
+ static_cast<int32_t>(Simulator::Current()->Call((int32_t)entry, \
+ bit_cast<int32_t, float>(float_arg), \
+ 0, 0, 0, 0))
+#define EXECUTE_TEST_CODE_INT32_D(name, entry, double_arg) \
+ static_cast<int32_t>(Simulator::Current()->Call((int32_t)entry, \
+ Utils::Low32Bits(bit_cast<int64_t, double>(double_arg)), \
+ Utils::High32Bits(bit_cast<int64_t, double>(double_arg)), \
+ 0, 0, 0))
+#endif // defined(HOST_ARCH_ARM) || defined(HOST_ARCH_MIPS)
+#endif // defined(TARGET_ARCH_ARM) || defined(TARGET_ARCH_MIPS)
+
+
inline Dart_Handle NewString(const char* str) {
return Dart_NewStringFromCString(str);
}
diff --git a/runtime/vm/vm.gypi b/runtime/vm/vm.gypi
index 6c887e7..9ed725d 100644
--- a/runtime/vm/vm.gypi
+++ b/runtime/vm/vm.gypi
@@ -363,7 +363,7 @@
},
'includes': [
# Load the shared collection_dev library sources.
- '../../sdk/lib/collection_dev/collection_dev_sources.gypi',
+ '../../sdk/lib/_collection_dev/collection_dev_sources.gypi',
],
'sources/': [
# Exclude all .[cc|h] files.
diff --git a/sdk/lib/collection_dev/collection_dev.dart b/sdk/lib/_collection_dev/collection_dev.dart
similarity index 69%
rename from sdk/lib/collection_dev/collection_dev.dart
rename to sdk/lib/_collection_dev/collection_dev.dart
index 12e8e62..839fd1c 100644
--- a/sdk/lib/collection_dev/collection_dev.dart
+++ b/sdk/lib/_collection_dev/collection_dev.dart
@@ -2,9 +2,12 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-library dart.collection.dev;
+library dart._collection.dev;
part 'iterable.dart';
part 'list.dart';
part 'sort.dart';
part 'to_string.dart';
+
+// TODO(floitsch): move this into core, another hidden library or remove it.
+const deprecated = 0;
diff --git a/sdk/lib/collection_dev/collection_dev_sources.gypi b/sdk/lib/_collection_dev/collection_dev_sources.gypi
similarity index 100%
rename from sdk/lib/collection_dev/collection_dev_sources.gypi
rename to sdk/lib/_collection_dev/collection_dev_sources.gypi
diff --git a/sdk/lib/collection_dev/iterable.dart b/sdk/lib/_collection_dev/iterable.dart
similarity index 91%
rename from sdk/lib/collection_dev/iterable.dart
rename to sdk/lib/_collection_dev/iterable.dart
index 9729e1c..89b9e6d 100644
--- a/sdk/lib/collection_dev/iterable.dart
+++ b/sdk/lib/_collection_dev/iterable.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-part of dart.collection.dev;
+part of dart._collection.dev;
typedef T _Transformation<S, T>(S value);
@@ -405,6 +405,55 @@
E get current => _iterator.current;
}
+typedef Iterable<T> _ExpandFunction<S, T>(S sourceElement);
+
+class ExpandIterable<S, T> extends Iterable<T> {
+ final Iterable<S> _iterable;
+ // TODO(ahe): Restore type when feature is implemented in dart2js
+ // checked mode. http://dartbug.com/7733
+ final /* _ExpandFunction */ _f;
+
+ ExpandIterable(this._iterable, Iterable<T> this._f(S element));
+
+ Iterator<T> get iterator => new ExpandIterator<S, T>(_iterable.iterator, _f);
+}
+
+class ExpandIterator<S, T> implements Iterator<T> {
+ final Iterator<S> _iterator;
+ // TODO(ahe): Restore type when feature is implemented in dart2js
+ // checked mode. http://dartbug.com/7733
+ final /* _ExpandFunction */ _f;
+ // Initialize _currentExpansion to an empty iterable. A null value
+ // marks the end of iteration, and we don't want to call _f before
+ // the first moveNext call.
+ Iterator<T> _currentExpansion = const EmptyIterator();
+ T _current;
+
+ ExpandIterator(this._iterator, Iterable<T> this._f(S element));
+
+ void _nextExpansion() {
+ }
+
+ T get current => _current;
+
+ bool moveNext() {
+ if (_currentExpansion == null) return false;
+ while (!_currentExpansion.moveNext()) {
+ _current = null;
+ if (_iterator.moveNext()) {
+ // If _f throws, this ends iteration. Otherwise _currentExpansion and
+ // _current will be set again below.
+ _currentExpansion = null;
+ _currentExpansion = _f(_iterator.current).iterator;
+ } else {
+ return false;
+ }
+ }
+ _current = _currentExpansion.current;
+ return true;
+ }
+}
+
class TakeIterable<E> extends Iterable<E> {
final Iterable<E> _iterable;
final int _takeCount;
diff --git a/sdk/lib/collection_dev/list.dart b/sdk/lib/_collection_dev/list.dart
similarity index 99%
rename from sdk/lib/collection_dev/list.dart
rename to sdk/lib/_collection_dev/list.dart
index 09d6deb..7af0fbb 100644
--- a/sdk/lib/collection_dev/list.dart
+++ b/sdk/lib/_collection_dev/list.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-part of dart.collection.dev;
+part of dart._collection.dev;
/**
* Class implementing the read-operations on [List].
diff --git a/sdk/lib/collection_dev/sort.dart b/sdk/lib/_collection_dev/sort.dart
similarity index 99%
rename from sdk/lib/collection_dev/sort.dart
rename to sdk/lib/_collection_dev/sort.dart
index 9b89e63..73276b2 100644
--- a/sdk/lib/collection_dev/sort.dart
+++ b/sdk/lib/_collection_dev/sort.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-part of dart.collection.dev;
+part of dart._collection.dev;
/**
* Dual-Pivot Quicksort algorithm.
diff --git a/sdk/lib/collection_dev/to_string.dart b/sdk/lib/_collection_dev/to_string.dart
similarity index 99%
rename from sdk/lib/collection_dev/to_string.dart
rename to sdk/lib/_collection_dev/to_string.dart
index c55ccac..21cbf0c 100644
--- a/sdk/lib/collection_dev/to_string.dart
+++ b/sdk/lib/_collection_dev/to_string.dart
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-part of dart.collection.dev;
+part of dart._collection.dev;
/**
* Temporary move `toString` methods into this class.
diff --git a/sdk/lib/_internal/compiler/compiler.dart b/sdk/lib/_internal/compiler/compiler.dart
index cf7eb2a..bbee705 100644
--- a/sdk/lib/_internal/compiler/compiler.dart
+++ b/sdk/lib/_internal/compiler/compiler.dart
@@ -22,7 +22,7 @@
typedef Future<String> ReadStringFromUri(Uri uri);
/**
- * Returns a [Sink] that will serve as compiler output for the given
+ * Returns a [StreamSink] that will serve as compiler output for the given
* component.
*
* Components are identified by [name] and [extension]. By convention,
@@ -41,7 +41,8 @@
* As more features are added to the compiler, new names and
* extensions may be introduced.
*/
-typedef Sink<String> CompilerOutputProvider(String name, String extension);
+typedef StreamSink<String> CompilerOutputProvider(String name,
+ String extension);
/**
* Invoked by the compiler to report diagnostics. If [uri] is
diff --git a/sdk/lib/_internal/compiler/implementation/compiler.dart b/sdk/lib/_internal/compiler/implementation/compiler.dart
index 6bf404e..4b1fc3b 100644
--- a/sdk/lib/_internal/compiler/implementation/compiler.dart
+++ b/sdk/lib/_internal/compiler/implementation/compiler.dart
@@ -80,8 +80,7 @@
}
void run(Compiler compiler, CodegenEnqueuer world) {
- js.Expression code = world.universe.generatedCode[element];
- if (code != null) return;
+ if (world.isProcessed(element)) return;
compiler.codegen(this, world);
}
}
@@ -376,8 +375,8 @@
this, backend.constantSystem, isMetadata: true);
}
- ResolutionUniverse get resolverWorld => enqueuer.resolution.universe;
- CodegenUniverse get codegenWorld => enqueuer.codegen.universe;
+ Universe get resolverWorld => enqueuer.resolution.universe;
+ Universe get codegenWorld => enqueuer.codegen.universe;
int getNextFreeClassId() => nextFreeClassId++;
@@ -450,6 +449,8 @@
return spanFromHInstruction(node);
} else if (node is Element) {
return spanFromElement(node);
+ } else if (node is MetadataAnnotation) {
+ return spanFromTokens(node.beginToken, node.endToken);
} else {
throw 'No error location.';
}
@@ -720,7 +721,7 @@
}
if (!REPORT_EXCESS_RESOLUTION) return;
var resolved = new Set.from(enqueuer.resolution.resolvedElements.keys);
- for (Element e in codegenWorld.generatedCode.keys) {
+ for (Element e in enqueuer.codegen.generatedCode.keys) {
resolved.remove(e);
}
for (Element e in new Set.from(resolved)) {
@@ -762,8 +763,11 @@
Node tree = parser.parse(element);
validator.validate(tree);
elements = resolver.resolve(element);
- checker.check(tree, elements);
- typesTask.analyze(tree, elements);
+ if (elements != null) {
+ // Only analyze nodes with a corresponding [TreeElements].
+ checker.check(tree, elements);
+ typesTask.analyze(tree, elements);
+ }
return elements;
}
@@ -794,7 +798,7 @@
if (progress.elapsedMilliseconds > 500) {
// TODO(ahe): Add structured diagnostics to the compiler API and
// use it to separate this from the --verbose option.
- log('Compiled ${codegenWorld.generatedCode.length} methods.');
+ log('Compiled ${enqueuer.codegen.generatedCode.length} methods.');
progress.reset();
}
backend.codegen(work);
@@ -839,7 +843,6 @@
if (identical(message.message.kind, MessageKind.NOT_ASSIGNABLE)) return;
if (identical(message.message.kind, MessageKind.MISSING_RETURN)) return;
if (identical(message.message.kind, MessageKind.MAYBE_MISSING_RETURN)) return;
- if (identical(message.message.kind, MessageKind.ADDITIONAL_ARGUMENT)) return;
if (identical(message.message.kind, MessageKind.METHOD_NOT_FOUND)) return;
}
SourceSpan span = spanFromNode(node);
@@ -1107,13 +1110,15 @@
}
/// A sink that drains into /dev/null.
-class NullSink extends Sink<String> {
+class NullSink extends StreamSink<String> {
final String name;
NullSink(this.name);
add(String value) {}
+ void signalError(AsyncError error) {}
+
void close() {}
toString() => name;
diff --git a/sdk/lib/_internal/compiler/implementation/dart2js.dart b/sdk/lib/_internal/compiler/implementation/dart2js.dart
index d66579f..ac7d422 100644
--- a/sdk/lib/_internal/compiler/implementation/dart2js.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart2js.dart
@@ -201,7 +201,6 @@
new OptionHandler('--analyze-all', passThrough),
new OptionHandler('--analyze-only', setAnalyzeOnly),
new OptionHandler('--disable-native-live-type-analysis', passThrough),
- new OptionHandler('--enable-native-live-type-analysis', passThrough),
new OptionHandler('--reject-deprecated-language-features', passThrough),
new OptionHandler('--report-sdk-use-of-deprecated-language-features',
passThrough),
@@ -263,7 +262,7 @@
}
}
- Sink<String> outputProvider(String name, String extension) {
+ StreamSink<String> outputProvider(String name, String extension) {
Uri uri;
String sourceMapFileName;
bool isPrimaryOutput = false;
@@ -314,8 +313,8 @@
}
// TODO(ahe): Get rid of this class if http://dartbug.com/8118 is fixed.
-class CountingSink implements Sink<String> {
- final Sink<String> sink;
+class CountingSink implements StreamSink<String> {
+ final StreamSink<String> sink;
int count = 0;
CountingSink(this.sink);
@@ -325,6 +324,8 @@
count += value.length;
}
+ signalError(AsyncError error) => sink.signalError(error);
+
close() => sink.close();
}
@@ -430,12 +431,12 @@
--enable-concrete-type-inference
Enable experimental concrete type inference.
- --enable-native-live-type-analysis
- Remove unused native types from dart:html and related libraries. This is
- expected to become the default behavior.
+ --disable-native-live-type-analysis
+ Disable the optimization that removes unused native types from dart:html
+ and related libraries.
--disallow-unsafe-eval
- Disables dynamic generation of code in the generated output. This is
+ Disable dynamic generation of code in the generated output. This is
necessary to satisfy CSP restrictions (see http://www.w3.org/TR/CSP/).
This flag is not continuously tested. Please report breakages and we
will fix them as soon as possible.
diff --git a/sdk/lib/_internal/compiler/implementation/dart2jslib.dart b/sdk/lib/_internal/compiler/implementation/dart2jslib.dart
index 8a1e012..9b683f2 100644
--- a/sdk/lib/_internal/compiler/implementation/dart2jslib.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart2jslib.dart
@@ -4,6 +4,7 @@
library dart2js;
+import 'dart:async';
import 'dart:uri';
import 'dart:collection' show Queue, LinkedHashMap;
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/utils.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/utils.dart
index 0d421b3..c30a2cf 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/utils.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/utils.dart
@@ -213,8 +213,7 @@
visit(node.name), visit(node.bound));
visitVariableDefinitions(VariableDefinitions node) => new VariableDefinitions(
- visit(node.type), visit(node.modifiers), visit(node.definitions),
- node.endToken);
+ visit(node.type), visit(node.modifiers), visit(node.definitions));
visitWhile(While node) => new While(
visit(node.condition), visit(node.body), node.whileKeyword);
diff --git a/sdk/lib/_internal/compiler/implementation/dart_types.dart b/sdk/lib/_internal/compiler/implementation/dart_types.dart
index b43de38..7c78bd5 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_types.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_types.dart
@@ -293,22 +293,16 @@
return false;
}
-// TODO(johnniwinther): Add common supertype for InterfaceType and TypedefType.
-class InterfaceType extends DartType {
- final ClassElement element;
+abstract class GenericType extends DartType {
final Link<DartType> typeArguments;
final bool isMalformed;
- InterfaceType(this.element,
- [Link<DartType> typeArguments = const Link<DartType>()])
- : this.typeArguments = typeArguments,
- this.isMalformed = hasMalformed(typeArguments) {
- assert(invariant(element, element.isDeclaration));
- }
+ GenericType(Link<DartType> this.typeArguments, bool this.isMalformed);
- TypeKind get kind => TypeKind.INTERFACE;
+ TypeDeclarationElement get element;
- SourceString get name => element.name;
+ /// Creates a new instance of this type using the provided type arguments.
+ GenericType _createType(Link<DartType> newTypeArguments);
DartType subst(Link<DartType> arguments, Link<DartType> parameters) {
if (typeArguments.isEmpty) {
@@ -324,7 +318,7 @@
Types.substTypes(typeArguments, arguments, parameters);
if (!identical(typeArguments, newTypeArguments)) {
// Create a new type only if necessary.
- return new InterfaceType(element, newTypeArguments);
+ return _createType(newTypeArguments);
}
return this;
}
@@ -338,26 +332,6 @@
return true;
}
- /**
- * Returns the type as an instance of class [other], if possible, null
- * otherwise.
- */
- DartType asInstanceOf(ClassElement other) {
- if (element == other) return this;
- for (InterfaceType supertype in element.allSupertypes) {
- ClassElement superclass = supertype.element;
- if (superclass == other) {
- Link<DartType> arguments = Types.substTypes(supertype.typeArguments,
- typeArguments,
- element.typeVariables);
- return new InterfaceType(superclass, arguments);
- }
- }
- return null;
- }
-
- DartType unalias(Compiler compiler) => this;
-
String toString() {
StringBuffer sb = new StringBuffer();
sb.add(name.slowToString());
@@ -381,14 +355,59 @@
}
bool operator ==(other) {
- if (other is !InterfaceType) return false;
if (!identical(element, other.element)) return false;
return typeArguments == other.typeArguments;
}
bool get isRaw => typeArguments.isEmpty || identical(this, element.rawType);
- InterfaceType asRaw() => element.rawType;
+ GenericType asRaw() => element.rawType;
+}
+
+// TODO(johnniwinther): Add common supertype for InterfaceType and TypedefType.
+class InterfaceType extends GenericType {
+ final ClassElement element;
+
+ InterfaceType(this.element,
+ [Link<DartType> typeArguments = const Link<DartType>()])
+ : super(typeArguments, hasMalformed(typeArguments)) {
+ assert(invariant(element, element.isDeclaration));
+ }
+
+ TypeKind get kind => TypeKind.INTERFACE;
+
+ SourceString get name => element.name;
+
+ InterfaceType _createType(Link<DartType> newTypeArguments) {
+ return new InterfaceType(element, newTypeArguments);
+ }
+
+ /**
+ * Returns the type as an instance of class [other], if possible, null
+ * otherwise.
+ */
+ DartType asInstanceOf(ClassElement other) {
+ if (element == other) return this;
+ for (InterfaceType supertype in element.allSupertypes) {
+ ClassElement superclass = supertype.element;
+ if (superclass == other) {
+ Link<DartType> arguments = Types.substTypes(supertype.typeArguments,
+ typeArguments,
+ element.typeVariables);
+ return new InterfaceType(superclass, arguments);
+ }
+ }
+ return null;
+ }
+
+ DartType unalias(Compiler compiler) => this;
+
+ bool operator ==(other) {
+ if (other is !InterfaceType) return false;
+ return super == other;
+ }
+
+ InterfaceType asRaw() => super.asRaw();
}
class FunctionType extends DartType {
@@ -447,6 +466,19 @@
TypeKind get kind => TypeKind.FUNCTION;
+ DartType getNamedParameterType(SourceString name) {
+ Link<SourceString> namedParameter = namedParameters;
+ Link<DartType> namedParameterType = namedParameterTypes;
+ while (!namedParameter.isEmpty && !namedParameterType.isEmpty) {
+ if (namedParameter.head == name) {
+ return namedParameterType.head;
+ }
+ namedParameter = namedParameter.tail;
+ namedParameterType = namedParameterType.tail;
+ }
+ return null;
+ }
+
DartType subst(Link<DartType> arguments, Link<DartType> parameters) {
if (parameters.isEmpty) {
assert(arguments.isEmpty);
@@ -577,48 +609,21 @@
}
}
-class TypedefType extends DartType {
+class TypedefType extends GenericType {
final TypedefElement element;
- final Link<DartType> typeArguments;
- final bool isMalformed;
TypedefType(this.element,
[Link<DartType> typeArguments = const Link<DartType>()])
- : this.typeArguments = typeArguments,
- this.isMalformed = hasMalformed(typeArguments);
+ : super(typeArguments, hasMalformed(typeArguments));
+
+ TypedefType _createType(Link<DartType> newTypeArguments) {
+ return new TypedefType(element, newTypeArguments);
+ }
TypeKind get kind => TypeKind.TYPEDEF;
SourceString get name => element.name;
- DartType subst(Link<DartType> arguments, Link<DartType> parameters) {
- if (typeArguments.isEmpty) {
- // Return fast on non-generic typedefs.
- return this;
- }
- if (parameters.isEmpty) {
- assert(arguments.isEmpty);
- // Return fast on empty substitutions.
- return this;
- }
- Link<DartType> newTypeArguments = Types.substTypes(typeArguments, arguments,
- parameters);
- if (!identical(typeArguments, newTypeArguments)) {
- // Create a new type only if necessary.
- return new TypedefType(element, newTypeArguments);
- }
- return this;
- }
-
- bool forEachMalformedType(bool f(MalformedType type)) {
- for (DartType typeArgument in typeArguments) {
- if (!typeArgument.forEachMalformedType(f)) {
- return false;
- }
- }
- return true;
- }
-
DartType unalias(Compiler compiler) {
// TODO(ahe): This should be [ensureResolved].
compiler.resolveTypedef(element);
@@ -627,28 +632,12 @@
return definition.subst(typeArguments, declaration.typeArguments);
}
- String toString() {
- StringBuffer sb = new StringBuffer();
- sb.add(name.slowToString());
- if (!isRaw) {
- sb.add('<');
- typeArguments.printOn(sb, ', ');
- sb.add('>');
- }
- return sb.toString();
- }
-
- int get hashCode => 17 * element.hashCode;
-
bool operator ==(other) {
if (other is !TypedefType) return false;
- if (!identical(element, other.element)) return false;
- return typeArguments == other.typeArguments;
+ return super == other;
}
- bool get isRaw => typeArguments.isEmpty || identical(this, element.rawType);
-
- TypedefType asRaw() => element.rawType;
+ TypedefType asRaw() => super.asRaw();
}
/**
diff --git a/sdk/lib/_internal/compiler/implementation/elements/elements.dart b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
index 81e2fc0..2798f95 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/elements.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
@@ -625,6 +625,8 @@
* declarations and typedefs.
*/
abstract class TypeDeclarationElement extends Element {
+ GenericType get rawType;
+
/**
* The type variables declared on this declaration. The type variables are not
* available until the type of the element has been computed through
@@ -775,11 +777,12 @@
void set bound(DartType value);
}
-abstract class MetadataAnnotation {
+abstract class MetadataAnnotation implements Spannable {
Constant get value;
Element get annotatedElement;
int get resolutionState;
Token get beginToken;
+ Token get endToken;
// TODO(kasperl): Try to get rid of these.
void set annotatedElement(Element value);
diff --git a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
index 8c43df5..f007946 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/modelx.dart
@@ -1700,7 +1700,10 @@
* account.
*/
bool isSubclassOf(ClassElement cls) {
- for (ClassElement s = this; s != null; s = s.superclass) {
+ // Use [declaration] for both [this] and [cls], because
+ // declaration classes hold the superclass hierarchy.
+ cls = cls.declaration;
+ for (ClassElement s = declaration; s != null; s = s.superclass) {
if (identical(s, cls)) return true;
}
return false;
diff --git a/sdk/lib/_internal/compiler/implementation/enqueue.dart b/sdk/lib/_internal/compiler/implementation/enqueue.dart
index ea98278..4a4fea8 100644
--- a/sdk/lib/_internal/compiler/implementation/enqueue.dart
+++ b/sdk/lib/_internal/compiler/implementation/enqueue.dart
@@ -31,6 +31,7 @@
final Function itemCompilationContextCreator;
final Map<String, Link<Element>> instanceMembersByName;
final Set<ClassElement> seenClasses;
+ final Universe universe;
bool queueIsClosed = false;
EnqueueTask task;
@@ -40,10 +41,9 @@
ItemCompilationContext itemCompilationContextCreator())
: this.itemCompilationContextCreator = itemCompilationContextCreator,
instanceMembersByName = new Map<String, Link<Element>>(),
+ universe = new Universe(),
seenClasses = new Set<ClassElement>();
- Universe get universe;
-
/// Returns [:true:] if this enqueuer is the resolution enqueuer.
bool get isResolutionQueue => false;
@@ -272,7 +272,7 @@
void handleUnseenSelector(SourceString methodName, Selector selector) {
processInstanceMembers(methodName, (Element member) {
- if (selector.applies(member, compiler)) {
+ if (selector.appliesUnnamed(member, compiler)) {
if (member.isField() && member.enclosingElement.isNative()) {
if (selector.isGetter() || selector.isCall()) {
nativeEnqueuer.registerFieldLoad(member);
@@ -319,8 +319,26 @@
registerInvocation(methodName, selector);
}
- void registerDynamicInvocationOf(Element element) {
- addToWorkList(element);
+ void registerDynamicInvocationOf(Element element, Selector selector) {
+ assert(selector.isCall()
+ || selector.isOperator()
+ || selector.isIndex()
+ || selector.isIndexSet());
+ if (element.isFunction()) {
+ addToWorkList(element);
+ } else if (element.isAbstractField()) {
+ AbstractFieldElement field = element;
+ // Since the invocation is a dynamic call on a getter, we only
+ // need to schedule the getter on the work list.
+ addToWorkList(field.getter);
+ } else {
+ assert(element.isField());
+ }
+ // We also need to add the selector to the invoked names map,
+ // because the emitter uses that map to generate parameter stubs.
+ Set<Selector> selectors = universe.invokedNames.putIfAbsent(
+ element.name, () => new Set<Selector>());
+ selectors.add(selector);
}
void registerDynamicGetter(SourceString methodName, Selector selector) {
@@ -331,6 +349,28 @@
registerInvokedSetter(methodName, selector);
}
+ void registerFieldGetter(SourceString getterName,
+ LibraryElement library,
+ DartType type) {
+ task.measure(() {
+ Selector getter = new Selector.getter(getterName, library);
+ registerNewSelector(getterName,
+ new TypedSelector(type, getter),
+ universe.fieldGetters);
+ });
+ }
+
+ void registerFieldSetter(SourceString setterName,
+ LibraryElement library,
+ DartType type) {
+ task.measure(() {
+ Selector setter = new Selector.setter(setterName, library);
+ registerNewSelector(setterName,
+ new TypedSelector(type, setter),
+ universe.fieldSetters);
+ });
+ }
+
void registerIsCheck(DartType type) {
universe.isChecks.add(type);
}
@@ -350,8 +390,6 @@
/// [Enqueuer] which is specific to resolution.
class ResolutionEnqueuer extends Enqueuer {
- final ResolutionUniverse universe;
-
/**
* Map from declaration elements to the [TreeElements] object holding the
* resolution mapping for the element implementation.
@@ -366,7 +404,6 @@
ItemCompilationContext itemCompilationContextCreator())
: super('resolution enqueuer', compiler, itemCompilationContextCreator),
resolvedElements = new Map<Element, TreeElements>(),
- universe = new ResolutionUniverse(),
queue = new Queue<ResolutionWorkItem>();
bool get isResolutionQueue => true;
@@ -445,12 +482,12 @@
void enableNoSuchMethod(Element element) {
if (compiler.enabledNoSuchMethod) return;
+ Selector selector = new Selector.noSuchMethod();
if (identical(element.getEnclosingClass(), compiler.objectClass)) {
- registerDynamicInvocationOf(element);
+ registerDynamicInvocationOf(element, selector);
return;
}
compiler.enabledNoSuchMethod = true;
- Selector selector = new Selector.noSuchMethod();
registerInvocation(Compiler.NO_SUCH_METHOD, selector);
compiler.createInvocationMirrorElement =
@@ -476,40 +513,16 @@
/// [Enqueuer] which is specific to code generation.
class CodegenEnqueuer extends Enqueuer {
- final CodegenUniverse universe;
-
final Queue<CodegenWorkItem> queue;
+ final Map<Element, js.Expression> generatedCode =
+ new Map<Element, js.Expression>();
CodegenEnqueuer(Compiler compiler,
ItemCompilationContext itemCompilationContextCreator())
: super('codegen enqueuer', compiler, itemCompilationContextCreator),
- universe = new CodegenUniverse(),
queue = new Queue<CodegenWorkItem>();
- bool isProcessed(Element member) =>
- universe.generatedCode.containsKey(member);
-
- /**
- * Unit test hook that returns code of an element as a String.
- *
- * Invariant: [element] must be a declaration element.
- */
- String assembleCode(Element element) {
- assert(invariant(element, element.isDeclaration));
- return js.prettyPrint(universe.generatedCode[element], compiler).getText();
- }
-
- /**
- * Documentation wanted -- johnniwinther
- *
- * Invariant: [element] must be a declaration element.
- */
- void eagerRecompile(Element element) {
- assert(invariant(element, element.isDeclaration));
- universe.generatedCode.remove(element);
- universe.generatedBailoutCode.remove(element);
- addToWorkList(element);
- }
+ bool isProcessed(Element member) => generatedCode.containsKey(member);
bool addElementToWorkList(Element element, [TreeElements elements]) {
if (queueIsClosed) {
@@ -526,28 +539,6 @@
return true;
}
- void registerFieldGetter(SourceString getterName,
- LibraryElement library,
- DartType type) {
- task.measure(() {
- Selector getter = new Selector.getter(getterName, library);
- registerNewSelector(getterName,
- new TypedSelector(type, getter),
- universe.fieldGetters);
- });
- }
-
- void registerFieldSetter(SourceString setterName,
- LibraryElement library,
- DartType type) {
- task.measure(() {
- Selector setter = new Selector.setter(setterName, library);
- registerNewSelector(setterName,
- new TypedSelector(type, setter),
- universe.fieldSetters);
- });
- }
-
void forEach(f(WorkItem work)) {
while(!queue.isEmpty) {
// TODO(johnniwinther): Find an optimal process order for codegen.
@@ -556,6 +547,6 @@
}
void _logSpecificSummary(log(message)) {
- log('Compiled ${universe.generatedCode.length} methods.');
+ log('Compiled ${generatedCode.length} methods.');
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
index a3e2a7e..2a681d8 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/backend.dart
@@ -621,6 +621,19 @@
SsaCodeGeneratorTask generator;
CodeEmitterTask emitter;
+ /**
+ * The generated code as a js AST for compiled methods.
+ */
+ Map<Element, js.Expression> get generatedCode {
+ return compiler.enqueuer.codegen.generatedCode;
+ }
+
+ /**
+ * The generated code as a js AST for compiled bailout methods.
+ */
+ final Map<Element, js.Expression> generatedBailoutCode =
+ new Map<Element, js.Expression>();
+
ClassElement jsStringClass;
ClassElement jsArrayClass;
ClassElement jsNumberClass;
@@ -636,6 +649,7 @@
Element jsArrayAdd;
Element jsStringSplit;
Element jsStringConcat;
+ Element jsStringToString;
Element getInterceptorMethod;
Element fixedLengthListConstructor;
bool seenAnyClass = false;
@@ -801,6 +815,8 @@
jsStringClass, const SourceString('split'));
jsStringConcat = compiler.lookupElementIn(
jsStringClass, const SourceString('concat'));
+ jsStringToString = compiler.lookupElementIn(
+ jsStringClass, const SourceString('toString'));
for (ClassElement cls in classes) {
if (cls != null) interceptedClasses[cls] = null;
@@ -868,10 +884,12 @@
addInterceptors(jsArrayClass, enqueuer);
// The backend will try to optimize array access and use the
// `ioore` and `iae` helpers directly.
- enqueuer.registerStaticUse(
- compiler.findHelper(const SourceString('ioore')));
- enqueuer.registerStaticUse(
- compiler.findHelper(const SourceString('iae')));
+ if (enqueuer.isResolutionQueue) {
+ enqueuer.registerStaticUse(
+ compiler.findHelper(const SourceString('ioore')));
+ enqueuer.registerStaticUse(
+ compiler.findHelper(const SourceString('iae')));
+ }
} else if (cls == compiler.intClass) {
addInterceptors(jsIntClass, enqueuer);
addInterceptors(jsNumberClass, enqueuer);
@@ -888,6 +906,12 @@
addInterceptors(jsIntClass, enqueuer);
addInterceptors(jsDoubleClass, enqueuer);
addInterceptors(jsNumberClass, enqueuer);
+ } else if (cls == compiler.mapClass) {
+ // The backend will use a literal list to initialize the entries
+ // of the map.
+ if (enqueuer.isResolutionQueue) {
+ enqueuer.registerInstantiatedClass(compiler.listClass);
+ }
}
}
@@ -917,7 +941,8 @@
}
void codegen(CodegenWorkItem work) {
- if (work.element.kind.category == ElementCategory.VARIABLE) {
+ Element element = work.element;
+ if (element.kind.category == ElementCategory.VARIABLE) {
Constant initialValue = compiler.constantHandler.compileWorkItem(work);
if (initialValue != null) {
return;
@@ -935,13 +960,13 @@
if (work.allowSpeculativeOptimization
&& optimizer.trySpeculativeOptimizations(work, graph)) {
js.Expression code = generator.generateBailoutMethod(work, graph);
- compiler.codegenWorld.addBailoutCode(work, code);
+ generatedBailoutCode[element] = code;
optimizer.prepareForSpeculativeOptimizations(work, graph);
optimizer.optimize(work, graph, true);
}
js.Expression code = generator.generateCode(work, graph);
- compiler.codegenWorld.addGeneratedCode(work, code);
- invalidateAfterCodegen.forEach(compiler.enqueuer.codegen.eagerRecompile);
+ generatedCode[element] = code;
+ invalidateAfterCodegen.forEach(eagerRecompile);
invalidateAfterCodegen.clear();
}
@@ -953,6 +978,16 @@
return new native.NativeCodegenEnqueuer(world, compiler, emitter);
}
+ /**
+ * Unit test hook that returns code of an element as a String.
+ *
+ * Invariant: [element] must be a declaration element.
+ */
+ String assembleCode(Element element) {
+ assert(invariant(element, element.isDeclaration));
+ return js.prettyPrint(generatedCode[element], compiler).getText();
+ }
+
void assembleProgram() {
emitter.assembleProgram();
}
@@ -1106,6 +1141,13 @@
return fieldTypes.optimisticFieldType(element);
}
+ /**
+ * Return the checked mode helper name that will be needed to do a
+ * type check on [type] at runtime. Note that this method is being
+ * called both by the resolver with interface types (int, String,
+ * ...), and by the SSA backend with implementation types (JSInt,
+ * JSString, ...).
+ */
SourceString getCheckedModeHelper(DartType type) {
Element element = type.element;
bool nativeCheck =
@@ -1116,17 +1158,18 @@
return const SourceString('malformedTypeCheck');
} else if (type == compiler.types.voidType) {
return const SourceString('voidTypeCheck');
- } else if (element == compiler.stringClass) {
+ } else if (element == jsStringClass || element == compiler.stringClass) {
return const SourceString('stringTypeCheck');
- } else if (element == compiler.doubleClass) {
+ } else if (element == jsDoubleClass || element == compiler.doubleClass) {
return const SourceString('doubleTypeCheck');
- } else if (element == compiler.numClass) {
+ } else if (element == jsNumberClass || element == compiler.numClass) {
return const SourceString('numTypeCheck');
- } else if (element == compiler.boolClass) {
+ } else if (element == jsBoolClass || element == compiler.boolClass) {
return const SourceString('boolTypeCheck');
- } else if (element == compiler.functionClass) {
+ } else if (element == jsFunctionClass
+ || element == compiler.functionClass) {
return const SourceString('functionTypeCheck');
- } else if (element == compiler.intClass) {
+ } else if (element == jsIntClass || element == compiler.intClass) {
return const SourceString('intTypeCheck');
} else if (Elements.isNumberOrStringSupertype(element, compiler)) {
return nativeCheck
@@ -1136,7 +1179,7 @@
return nativeCheck
? const SourceString('stringSuperNativeTypeCheck')
: const SourceString('stringSuperTypeCheck');
- } else if (identical(element, compiler.listClass)) {
+ } else if (element == compiler.listClass || element == jsArrayClass) {
return const SourceString('listTypeCheck');
} else {
if (Elements.isListSupertype(element, compiler)) {
@@ -1203,4 +1246,17 @@
Element getGetRuntimeTypeInfo() {
return compiler.findHelper(const SourceString('getRuntimeTypeInfo'));
}
+
+ /**
+ * Remove [element] from the set of generated code, and put it back
+ * into the worklist.
+ *
+ * Invariant: [element] must be a declaration element.
+ */
+ void eagerRecompile(Element element) {
+ assert(invariant(element, element.isDeclaration));
+ generatedCode.remove(element);
+ generatedBailoutCode.remove(element);
+ compiler.enqueuer.codegen.addToWorkList(element);
+ }
}
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
index c25a335..f401235 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/emitter.dart
@@ -714,10 +714,11 @@
|| member.isGenerativeConstructorBody()
|| member.isAccessor()) {
if (member.isAbstract(compiler)) return;
- js.Expression code = compiler.codegenWorld.generatedCode[member];
+ JavaScriptBackend backend = compiler.backend;
+ js.Expression code = backend.generatedCode[member];
if (code == null) return;
builder.addProperty(namer.getName(member), code);
- code = compiler.codegenWorld.generatedBailoutCode[member];
+ code = backend.generatedBailoutCode[member];
if (code != null) {
builder.addProperty(namer.getBailoutName(member), code);
}
@@ -1125,11 +1126,6 @@
if (classElement.isNative()) {
nativeEmitter.generateNativeClass(classElement);
return;
- } else {
- // TODO(ngeoffray): Instead of switching between buffer, we
- // should create code sections, and decide where to emit them at
- // the end.
- buffer = mainBuffer;
}
needsDefineClass = true;
@@ -1397,21 +1393,21 @@
}
void emitStaticFunctions(CodeBuffer buffer) {
+ JavaScriptBackend backend = compiler.backend;
bool isStaticFunction(Element element) =>
!element.isInstanceMember() && !element.isField();
Iterable<Element> elements =
- compiler.codegenWorld.generatedCode.keys.where(isStaticFunction);
+ backend.generatedCode.keys.where(isStaticFunction);
Set<Element> pendingElementsWithBailouts =
- compiler.codegenWorld.generatedBailoutCode.keys
+ backend.generatedBailoutCode.keys
.where(isStaticFunction)
.toSet();
for (Element element in Elements.sortedByPosition(elements)) {
- js.Expression code = compiler.codegenWorld.generatedCode[element];
+ js.Expression code = backend.generatedCode[element];
emitStaticFunction(buffer, namer.getName(element), code);
- js.Expression bailoutCode =
- compiler.codegenWorld.generatedBailoutCode[element];
+ js.Expression bailoutCode = backend.generatedBailoutCode[element];
if (bailoutCode != null) {
pendingElementsWithBailouts.remove(element);
emitStaticFunction(buffer, namer.getBailoutName(element), bailoutCode);
@@ -1421,8 +1417,7 @@
// Is it possible the primary function was inlined but the bailout was not?
for (Element element in
Elements.sortedByPosition(pendingElementsWithBailouts)) {
- js.Expression bailoutCode =
- compiler.codegenWorld.generatedBailoutCode[element];
+ js.Expression bailoutCode = backend.generatedBailoutCode[element];
emitStaticFunction(buffer, namer.getBailoutName(element), bailoutCode);
}
}
@@ -1665,8 +1660,17 @@
}
}
+ // Two selectors may match but differ only in type. To avoid generating
+ // identical stubs for each we track untyped selectors which already have
+ // stubs.
+ Set<Selector> generatedSelectors = new Set<Selector>();
+
for (Selector selector in selectors) {
if (selector.applies(member, compiler)) {
+ selector = selector.asUntyped;
+ if (generatedSelectors.contains(selector)) continue;
+ generatedSelectors.add(selector);
+
String invocationName = namer.invocationName(selector);
Selector callSelector = new Selector.callClosureFrom(selector);
String closureCallName = namer.invocationName(callSelector);
@@ -1719,11 +1723,12 @@
ConstantHandler handler = compiler.constantHandler;
List<VariableElement> lazyFields =
handler.getLazilyInitializedFieldsForEmission();
+ JavaScriptBackend backend = compiler.backend;
if (!lazyFields.isEmpty) {
needsLazyInitializer = true;
for (VariableElement element in Elements.sortedByPosition(lazyFields)) {
- assert(compiler.codegenWorld.generatedBailoutCode[element] == null);
- js.Expression code = compiler.codegenWorld.generatedCode[element];
+ assert(backend.generatedBailoutCode[element] == null);
+ js.Expression code = backend.generatedCode[element];
assert(code != null);
// The code only computes the initial value. We build the lazy-check
// here:
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/minify_namer.dart b/sdk/lib/_internal/compiler/implementation/js_backend/minify_namer.dart
index bbe7368..98344a1 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/minify_namer.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/minify_namer.dart
@@ -23,8 +23,15 @@
// counterpart it will never return the proposedName as the new fresh name.
String getFreshName(String proposedName,
Set<String> usedNames,
+ Map<String, String> suggestedNames,
{bool ensureSafe: true}) {
- var freshName = _getUnusedName(proposedName, usedNames);
+ var freshName;
+ var suggestion = suggestedNames[proposedName];
+ if (suggestion != null && !usedNames.contains(suggestion)) {
+ freshName = suggestion;
+ } else {
+ freshName = _getUnusedName(proposedName, usedNames);
+ }
usedNames.add(freshName);
return freshName;
}
@@ -37,16 +44,90 @@
}
void reserveBackendNames() {
- // TODO(7554): We need a complete list from the DOM.
- const reservedNativeProperties = const <String>["x", "y", "z"];
+ // From issue 7554. These should not be used on objects (as instance
+ // variables) because they clash with names from the DOM.
+ const reservedNativeProperties = const <String>[
+ 'Q', 'a', 'b', 'c', 'd', 'e', 'f', 'r', 'x', 'y', 'z',
+ // 2-letter:
+ 'ch', 'cx', 'cy', 'db', 'dx', 'dy', 'fr', 'fx', 'fy', 'go', 'id', 'k1',
+ 'k2', 'k3', 'k4', 'r1', 'r2', 'rx', 'ry', 'x1', 'x2', 'y1', 'y2',
+ // 3-letter:
+ 'add', 'all', 'alt', 'arc', 'CCW', 'cmp', 'dir', 'end', 'get', 'in1',
+ 'in2', 'INT', 'key', 'log', 'low', 'm11', 'm12', 'm13', 'm14', 'm21',
+ 'm22', 'm23', 'm24', 'm31', 'm32', 'm33', 'm34', 'm41', 'm42', 'm43',
+ 'm44', 'max', 'min', 'now', 'ONE', 'put', 'red', 'rel', 'rev', 'RGB',
+ 'sdp', 'set', 'src', 'tag', 'top', 'uid', 'uri', 'url', 'URL',
+ // 4-letter:
+ 'abbr', 'atob', 'Attr', 'axes', 'axis', 'back', 'BACK', 'beta', 'bias',
+ 'Blob', 'blue', 'blur', 'BLUR', 'body', 'BOOL', 'BOTH', 'btoa', 'BYTE',
+ 'cite', 'clip', 'code', 'cols', 'cues', 'data', 'DECR', 'DONE', 'face',
+ 'file', 'File', 'fill', 'find', 'font', 'form', 'gain', 'hash', 'head',
+ 'high', 'hint', 'host', 'href', 'HRTF', 'IDLE', 'INCR', 'info', 'INIT',
+ 'isId', 'item', 'KEEP', 'kind', 'knee', 'lang', 'left', 'LESS', 'line',
+ 'link', 'list', 'load', 'loop', 'mode', 'name', 'Node', 'None', 'NONE',
+ 'only', 'open', 'OPEN', 'ping', 'play', 'port', 'rect', 'Rect', 'refX',
+ 'refY', 'RGBA', 'root', 'rows', 'save', 'seed', 'seek', 'self', 'send',
+ 'show', 'SINE', 'size', 'span', 'stat', 'step', 'stop', 'tags', 'text',
+ 'Text', 'time', 'type', 'view', 'warn', 'wrap', 'ZERO'];
for (var name in reservedNativeProperties) {
- if (name.length < 3) {
+ if (name.length < 2) {
instanceNameMap[name] = name;
}
usedInstanceNames.add(name);
}
+
+ // This list of popular instance variable names generated with:
+ // cat out.js |
+ // perl -ne '$_=~s/(?<![^a-z0-9_\$]\$)\.([a-z0-9_\$]+)/print("$1\n")/gei' |
+ // sort | uniq -c | sort -nr | head -40
+ // Removed: html, call*, hasOwnProperty.
+ _populateSuggestedNames(
+ suggestedInstanceNames,
+ usedInstanceNames,
+ const <String>[
+ r'$add', r'add$1', r'box_0', r'charCodeAt$1', r'constructor',
+ r'current', r'$defineNativeClass', r'$eq', r'$ne',
+ r'getPrototypeOf', r'hasOwnProperty', r'$index', r'$indexSet',
+ r'$isJavaScriptIndexingBehavior', r'$isolateProperties',
+ r'iterator', r'length', r'$lt', r'$gt', r'$le', r'$ge',
+ r'moveNext$0', r'node', r'on', r'prototype', r'push', r'self',
+ r'start', r'target', r'this_0', r'value', r'width', r'style']);
+
+ _populateSuggestedNames(
+ suggestedGlobalNames,
+ usedGlobalNames,
+ const <String>[
+ r'Object', r'$throw', r'$eq', r'S', r'ioore', r'UnsupportedError$',
+ r'length', r'$sub', r'getInterceptor$JSStringJSArray', r'$add',
+ r'$gt', r'$ge', r'$lt', r'$le', r'add', r'getInterceptor$JSNumber',
+ r'iterator', r'$index', r'iae', r'getInterceptor$JSArray',
+ r'ArgumentError$', r'BoundClosure', r'StateError$',
+ r'getInterceptor', r'max', r'$mul', r'List_List', r'Map_Map',
+ r'getInterceptor$JSString', r'$div', r'$indexSet',
+ r'List_List$from', r'Set_Set$from', r'toString', r'toInt', r'min',
+ r'StringBuffer_StringBuffer', r'contains1', r'WhereIterable$',
+ r'RangeError$value', r'JSString', r'JSNumber',
+ r'JSArray'
+ ]);
}
+ void _populateSuggestedNames(Map<String, String> suggestionMap,
+ Set<String> used,
+ List<String> suggestions) {
+ int c = $a - 1;
+ String letter;
+ for (String name in suggestions) {
+ do {
+ assert(c != $Z);
+ c = (c == $z) ? $A : c + 1;
+ letter = new String.fromCharCodes([c]);
+ } while (used.contains(letter));
+ assert(suggestionMap[name] == null);
+ suggestionMap[name] = letter;
+ }
+ }
+
+
// This gets a minified name based on a hash of the proposed name. This
// is slightly less efficient than just getting the next name in a series,
// but it means that small changes in the input program will give smallish
diff --git a/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart b/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
index e424168..e5bb967 100644
--- a/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
+++ b/sdk/lib/_internal/compiler/implementation/js_backend/namer.dart
@@ -184,22 +184,17 @@
final Map<Element, String> globals;
final Map<Selector, String> oneShotInterceptorNames;
final Map<String, LibraryElement> shortPrivateNameOwners;
+
final Set<String> usedGlobalNames;
final Set<String> usedInstanceNames;
final Map<String, String> globalNameMap;
+ final Map<String, String> suggestedGlobalNames;
final Map<String, String> instanceNameMap;
+ final Map<String, String> suggestedInstanceNames;
+
final Map<String, String> operatorNameMap;
final Map<String, int> popularNameCounters;
- /**
- * A cache of names used for bailout methods. We make sure two
- * bailout methods cannot have the same name because if the two
- * bailout methods are in a class and a subclass, we would
- * call the wrong bailout method at runtime. To make it
- * simple, we don't keep track of inheritance and always avoid
- * similar names.
- */
- final Set<String> usedBailoutInstanceNames;
final Map<Element, String> bailoutNames;
final Map<Constant, String> constantNames;
@@ -209,12 +204,13 @@
oneShotInterceptorNames = new Map<Selector, String>(),
shortPrivateNameOwners = new Map<String, LibraryElement>(),
bailoutNames = new Map<Element, String>(),
- usedBailoutInstanceNames = new Set<String>(),
usedGlobalNames = new Set<String>(),
usedInstanceNames = new Set<String>(),
instanceNameMap = new Map<String, String>(),
operatorNameMap = new Map<String, String>(),
globalNameMap = new Map<String, String>(),
+ suggestedGlobalNames = new Map<String, String>(),
+ suggestedInstanceNames = new Map<String, String>(),
constantNames = new Map<Constant, String>(),
popularNameCounters = new Map<String, int>();
@@ -251,7 +247,8 @@
} else {
longName = "CONSTANT";
}
- result = getFreshName(longName, usedGlobalNames, ensureSafe: true);
+ result = getFreshName(longName, usedGlobalNames, suggestedGlobalNames,
+ ensureSafe: true);
constantNames[constant] = result;
}
return result;
@@ -447,7 +444,8 @@
String getMappedGlobalName(String proposedName) {
var newName = globalNameMap[proposedName];
if (newName == null) {
- newName = getFreshName(proposedName, usedGlobalNames, ensureSafe: true);
+ newName = getFreshName(proposedName, usedGlobalNames,
+ suggestedGlobalNames, ensureSafe: true);
globalNameMap[proposedName] = newName;
}
return newName;
@@ -456,7 +454,8 @@
String getMappedInstanceName(String proposedName) {
var newName = instanceNameMap[proposedName];
if (newName == null) {
- newName = getFreshName(proposedName, usedInstanceNames, ensureSafe: true);
+ newName = getFreshName(proposedName, usedInstanceNames,
+ suggestedInstanceNames, ensureSafe: true);
instanceNameMap[proposedName] = newName;
}
return newName;
@@ -465,8 +464,8 @@
String getMappedOperatorName(String proposedName) {
var newName = operatorNameMap[proposedName];
if (newName == null) {
- newName = getFreshName(
- proposedName, usedInstanceNames, ensureSafe: false);
+ newName = getFreshName(proposedName, usedInstanceNames,
+ suggestedInstanceNames, ensureSafe: false);
operatorNameMap[proposedName] = newName;
}
return newName;
@@ -474,6 +473,7 @@
String getFreshName(String proposedName,
Set<String> usedNames,
+ Map<String, String> suggestedNames,
{bool ensureSafe: true}) {
var candidate;
if (ensureSafe) {
@@ -537,11 +537,12 @@
// need to go through the generic getInterceptorMethod.
return getName(element);
}
- // This gets the minified name, but it doesn't really make much difference.
- // The important thing is that it is a unique name.
- StringBuffer buffer = new StringBuffer('${getName(element)}\$');
+ // Use the unminified names here to construct the interceptor names. This
+ // helps ensure that they don't all suddenly change names due to a name
+ // clash in the minifier, which would affect the diff size.
+ StringBuffer buffer = new StringBuffer('${element.name.slowToString()}\$');
for (ClassElement cls in classes) {
- buffer.add(getName(cls));
+ buffer.add(cls.name.slowToString());
}
return getMappedGlobalName(buffer.toString());
}
@@ -558,12 +559,21 @@
if (global) {
name = getMappedGlobalName(unminifiedName);
} else {
- name = unminifiedName;
- int i = 0;
- while (usedBailoutInstanceNames.contains(name)) {
- name = '$unminifiedName${i++}';
+ // Make sure two bailout methods on the same inheritance chain do not have
+ // the same name to prevent a subclass bailout method being accidentally
+ // called from the superclass main method. Use the count of the number of
+ // elements with the same name on the superclass chain to disambiguate
+ // based on 'level'.
+ int level = 0;
+ ClassElement classElement = element.getEnclosingClass().superclass;
+ while (classElement != null) {
+ if (classElement.localLookup(element.name) != null) level++;
+ classElement = classElement.superclass;
}
- usedBailoutInstanceNames.add(name);
+ name = unminifiedName;
+ if (level != 0) {
+ name = '$unminifiedName$level';
+ }
name = getMappedInstanceName(name);
}
bailoutNames[element] = name;
@@ -625,7 +635,8 @@
}
String result = fixedName
? guess
- : getFreshName(guess, usedGlobalNames, ensureSafe: true);
+ : getFreshName(guess, usedGlobalNames, suggestedGlobalNames,
+ ensureSafe: true);
globals[element] = result;
return result;
}
@@ -685,7 +696,8 @@
String cached = oneShotInterceptorNames[selector];
if (cached != null) return cached;
SourceString name = operatorNameToIdentifier(selector.name);
- String result = getFreshName(name.slowToString(), usedGlobalNames);
+ String result = getFreshName(name.slowToString(), usedGlobalNames,
+ suggestedGlobalNames);
oneShotInterceptorNames[selector] = result;
return result;
}
diff --git a/sdk/lib/_internal/compiler/implementation/lib/core_patch.dart b/sdk/lib/_internal/compiler/implementation/lib/core_patch.dart
index 8d68c8d..09e31da 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/core_patch.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/core_patch.dart
@@ -158,7 +158,7 @@
// Patch for Stopwatch implementation.
-patch class _StopwatchImpl {
+patch class Stopwatch {
patch static int _frequency() => 1000000;
patch static int _now() => Primitives.numMicroseconds();
}
diff --git a/sdk/lib/_internal/compiler/implementation/lib/foreign_helper.dart b/sdk/lib/_internal/compiler/implementation/lib/foreign_helper.dart
index 89c2a58..2ad4a1e 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/foreign_helper.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/foreign_helper.dart
@@ -87,8 +87,11 @@
* optimizations around the code. This might be an extension of [JS] or a new
* function similar to [JS] with additional arguments for the new information.
*/
+// 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 arg0, var arg1, var arg2, var arg3, var arg4, var arg5, var arg6,
+ var arg7, var arg8, var arg9, var arg10, var arg11]) {}
/**
* Returns the isolate in which this code is running.
diff --git a/sdk/lib/_internal/compiler/implementation/lib/interceptors.dart b/sdk/lib/_internal/compiler/implementation/lib/interceptors.dart
index b133d12..6a32f17 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/interceptors.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/interceptors.dart
@@ -5,7 +5,7 @@
library _interceptors;
import 'dart:collection';
-import 'dart:collection-dev';
+import 'dart:_collection-dev';
import 'dart:_js_helper' show allMatchesInStringUnchecked,
Null,
JSSyntaxRegExp,
@@ -43,7 +43,7 @@
* to emit a call to an intercepted method, that is a method that is
* defined in an interceptor class.
*/
-getInterceptor() {
+getInterceptor(object) {
// This is a magic method: the compiler does specialization of it
// depending on the uses of intercepted methods and instantiated
// primitive types.
@@ -86,5 +86,5 @@
String toString() => 'null';
int get hashCode => 0;
- Type get runtimeType => createRuntimeType('Null');
+ Type get runtimeType => Null;
}
diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_array.dart b/sdk/lib/_internal/compiler/implementation/lib/js_array.dart
index fad48f0..e33ae3f 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/js_array.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/js_array.dart
@@ -65,6 +65,10 @@
return IterableMixinWorkaround.where(this, f);
}
+ Iterable expand(Iterable f(E element)) {
+ return IterableMixinWorkaround.expand(this, f);
+ }
+
void addAll(Collection<E> collection) {
for (E e in collection) {
this.add(e);
diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart b/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart
index 2c80eaa..0fbff9c 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/js_helper.dart
@@ -13,6 +13,7 @@
JS_HAS_EQUALS,
RAW_DART_FUNCTION_REF,
UNINTERCEPTED;
+import 'dart:_interceptors' show getInterceptor;
part 'constant_map.dart';
part 'native_helper.dart';
@@ -95,11 +96,19 @@
return map;
}
+ static final _objectInterceptor = getInterceptor(new Object());
invokeOn(Object object) {
- List arguments = _arguments;
- if (!isJsArray(arguments)) arguments = new List.from(arguments);
- return JS("var", "#[#].apply(#, #)",
- object, _internalName, object, arguments);
+ var interceptor = getInterceptor(object);
+ var receiver = object;
+ var name = _internalName;
+ var arguments = _arguments;
+ if (identical(interceptor, _objectInterceptor)) {
+ if (!isJsArray(arguments)) arguments = new List.from(arguments);
+ } else {
+ arguments = [object]..addAll(arguments);
+ receiver = interceptor;
+ }
+ return JS("var", "#[#].apply(#, #)", receiver, name, receiver, arguments);
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_number.dart b/sdk/lib/_internal/compiler/implementation/lib/js_number.dart
index 975c1a5..fa5677f 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/js_number.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/js_number.dart
@@ -10,7 +10,7 @@
* [:this:] to actually use the receiver of the method, which is
* generated as an extra argument added to each member.
*/
-class JSNumber {
+class JSNumber implements num {
const JSNumber();
int compareTo(num b) {
@@ -254,7 +254,7 @@
}
}
-class JSInt extends JSNumber {
+class JSInt extends JSNumber implements int {
const JSInt();
bool get isEven => (this & 1) == 0;
@@ -266,7 +266,7 @@
int operator ~() => JS('int', r'(~#) >>> 0', this);
}
-class JSDouble extends JSNumber {
+class JSDouble extends JSNumber implements double {
const JSDouble();
Type get runtimeType => double;
}
diff --git a/sdk/lib/_internal/compiler/implementation/lib/native_helper.dart b/sdk/lib/_internal/compiler/implementation/lib/native_helper.dart
index 860e706..c75e554 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/native_helper.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/native_helper.dart
@@ -27,6 +27,7 @@
if (name == 'JavaScriptAudioNode') return 'ScriptProcessorNode';
if (name == 'Oscillator') return 'OscillatorNode';
if (name == 'RealtimeAnalyserNode') return 'AnalyserNode';
+ if (name == 'IDBVersionChangeRequest') return 'IDBOpenDBRequest';
return name;
}
diff --git a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart
index ea9b593..13a15f8 100644
--- a/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart
+++ b/sdk/lib/_internal/compiler/implementation/mirrors/dart2js_mirror.dart
@@ -12,10 +12,10 @@
import '../../compiler.dart' as diagnostics;
import '../elements/elements.dart';
import '../resolution/resolution.dart' show ResolverTask, ResolverVisitor;
-import '../apiimpl.dart' as api;
+import '../apiimpl.dart' show Compiler;
import '../scanner/scannerlib.dart' hide SourceString;
import '../ssa/ssa.dart';
-import '../dart2jslib.dart';
+import '../dart2jslib.dart' hide Compiler;
import '../dart_types.dart';
import '../filenames.dart';
import '../source_file.dart';
@@ -237,152 +237,20 @@
}
//------------------------------------------------------------------------------
-// Compiler extension for apidoc.
-//------------------------------------------------------------------------------
-
-/**
- * Extension of the compiler that enables the analysis of several libraries with
- * no particular entry point.
- */
-class LibraryCompiler extends api.Compiler {
- LibraryCompiler(diagnostics.ReadStringFromUri provider,
- diagnostics.DiagnosticHandler handler,
- Uri libraryRoot, Uri packageRoot,
- List<String> options)
- : super(provider, null, handler, libraryRoot, packageRoot, options) {
- checker = new LibraryTypeCheckerTask(this);
- resolver = new LibraryResolverTask(this);
- }
-
- // TODO(johnniwinther): The following methods are added to enable the analysis
- // of a collection of libraries to be used for apidoc. Most of the methods
- // are based on copies of existing methods and could probably be implemented
- // such that the duplicate code is avoided. Not to affect the correctness and
- // speed of dart2js as is, the redundancy is accepted temporarily.
-
- /**
- * Run the compiler on a list of libraries. No entry point is used.
- */
- bool runList(List<Uri> uriList) {
- bool success = _runList(uriList);
- for (final task in tasks) {
- log('${task.name} took ${task.timing}msec');
- }
- return success;
- }
-
- bool _runList(List<Uri> uriList) {
- try {
- runCompilerList(uriList);
- } on CompilerCancelledException catch (exception) {
- log(exception.toString());
- log('compilation failed');
- return false;
- }
- tracer.close();
- log('compilation succeeded');
- return true;
- }
-
- void runCompilerList(List<Uri> uriList) {
- scanBuiltinLibraries();
- var elementList = <LibraryElement>[];
- for (var uri in uriList) {
- elementList.add(libraryLoader.loadLibrary(uri, null, uri));
- }
-
- world.populate();
-
- log('Resolving...');
- phase = Compiler.PHASE_RESOLVING;
- backend.enqueueHelpers(enqueuer.resolution);
- processQueueList(enqueuer.resolution, elementList);
- log('Resolved ${enqueuer.resolution.resolvedElements.length} elements.');
- }
-
- void processQueueList(Enqueuer world, List<LibraryElement> elements) {
- world.nativeEnqueuer.processNativeClasses(libraries.values);
- for (var library in elements) {
- fullyEnqueueLibrary(library);
- }
- progress.reset();
- world.forEach((WorkItem work) {
- withCurrentElement(work.element, () => work.run(this, world));
- });
- }
-
- String codegen(WorkItem work, Enqueuer world) {
- return null;
- }
-}
-
-// TODO(johnniwinther): The source for the apidoc includes calls to methods on
-// for instance [MathPrimitives] which are not resolved by dart2js. Since we
-// do not need to analyse the body of functions to produce the documenation
-// we use a specialized resolver which bypasses method bodies.
-class LibraryResolverTask extends ResolverTask {
- LibraryResolverTask(api.Compiler compiler) : super(compiler);
-
- void visitBody(ResolverVisitor visitor, Statement body) {}
-}
-
-// TODO(johnniwinther): As a side-effect of bypassing method bodies in
-// [LibraryResolveTask] we can not perform the typecheck.
-class LibraryTypeCheckerTask extends TypeCheckerTask {
- LibraryTypeCheckerTask(api.Compiler compiler) : super(compiler);
-
- void check(Node tree, TreeElements elements) {}
-}
-
-//------------------------------------------------------------------------------
// Compilation implementation
//------------------------------------------------------------------------------
+// TODO(johnniwinther): Support client configurable handlers/providers.
class Dart2JsCompilation implements Compilation {
- bool isWindows = (Platform.operatingSystem == 'windows');
- api.Compiler _compiler;
- Uri cwd;
- bool isAborting = false;
- Map<String, SourceFile> sourceFiles;
-
- Future<String> provider(Uri uri) {
- if (uri.scheme != 'file') {
- throw new ArgumentError(uri);
- }
- String source;
- try {
- source = readAll(uriPathToNative(uri.path));
- } on FileIOException catch (ex) {
- throw 'Error: Cannot read "${relativize(cwd, uri, isWindows)}" '
- '(${ex.osError}).';
- }
- sourceFiles[uri.toString()] =
- new SourceFile(relativize(cwd, uri, isWindows), source);
- return new Future.immediate(source);
- }
-
- void handler(Uri uri, int begin, int end,
- String message, diagnostics.Diagnostic kind) {
- if (isAborting) return;
- bool fatal =
- kind == diagnostics.Diagnostic.CRASH ||
- kind == diagnostics.Diagnostic.ERROR;
- if (uri == null) {
- if (!fatal) {
- return;
- }
- print(message);
- throw message;
- } else if (fatal) {
- SourceFile file = sourceFiles[uri.toString()];
- print(file.getLocationMessage(message, begin, end, true, (s) => s));
- throw message;
- }
- }
+ Compiler _compiler;
+ final Uri cwd;
+ final SourceFileProvider provider;
Dart2JsCompilation(Path script, Path libraryRoot,
[Path packageRoot, List<String> opts = const <String>[]])
- : cwd = getCurrentDirectory(), sourceFiles = <String, SourceFile>{} {
+ : cwd = getCurrentDirectory(),
+ provider = new SourceFileProvider() {
+ var handler = new FormattingDiagnosticHandler(provider);
var libraryUri = cwd.resolve(libraryRoot.toString());
var packageUri;
if (packageRoot != null) {
@@ -390,8 +258,10 @@
} else {
packageUri = libraryUri;
}
- _compiler = new api.Compiler(provider, null, handler,
- libraryUri, packageUri, opts);
+ _compiler = new Compiler(provider.readStringFromUri,
+ null,
+ handler.diagnosticHandler,
+ libraryUri, packageUri, opts);
var scriptUri = cwd.resolve(script.toString());
// TODO(johnniwinther): Detect file not found
_compiler.run(scriptUri);
@@ -399,7 +269,8 @@
Dart2JsCompilation.library(List<Path> libraries, Path libraryRoot,
[Path packageRoot, List<String> opts = const <String>[]])
- : cwd = getCurrentDirectory(), sourceFiles = <String, SourceFile>{} {
+ : cwd = getCurrentDirectory(),
+ provider = new SourceFileProvider() {
var libraryUri = cwd.resolve(libraryRoot.toString());
var packageUri;
if (packageRoot != null) {
@@ -407,15 +278,20 @@
} else {
packageUri = libraryUri;
}
- _compiler = new LibraryCompiler(provider, handler,
- libraryUri, packageUri, opts);
+ opts = new List<String>.from(opts);
+ opts.add('--analyze-only');
+ opts.add('--analyze-all');
+ _compiler = new Compiler(provider.readStringFromUri,
+ null,
+ silentDiagnosticHandler,
+ libraryUri, packageUri, opts);
var librariesUri = <Uri>[];
for (Path library in libraries) {
librariesUri.add(cwd.resolve(library.toString()));
// TODO(johnniwinther): Detect file not found
}
- LibraryCompiler libraryCompiler = _compiler;
- libraryCompiler.runList(librariesUri);
+ _compiler.librariesToAnalyzeWhenRun = librariesUri;
+ _compiler.run(null);
}
MirrorSystem get mirrors => new Dart2JsMirrorSystem(_compiler);
@@ -581,7 +457,7 @@
//------------------------------------------------------------------------------
class Dart2JsMirrorSystem implements MirrorSystem {
- final api.Compiler compiler;
+ final Compiler compiler;
Map<String, Dart2JsLibraryMirror> _libraries;
Map<LibraryElement, Dart2JsLibraryMirror> _libraryMap;
diff --git a/sdk/lib/_internal/compiler/implementation/native_handler.dart b/sdk/lib/_internal/compiler/implementation/native_handler.dart
index 5640670..373f16e 100644
--- a/sdk/lib/_internal/compiler/implementation/native_handler.dart
+++ b/sdk/lib/_internal/compiler/implementation/native_handler.dart
@@ -824,7 +824,7 @@
// TODO(ngeoffray): For static methods, we could pass a method with a
// defined arity.
Element helper = builder.backend.getClosureConverter();
- builder.pushInvokeHelper2(helper, local, arity);
+ builder.pushInvokeHelper2(helper, local, arity, HType.UNKNOWN);
HInstruction closure = builder.pop();
return closure;
}
diff --git a/sdk/lib/_internal/compiler/implementation/patch_parser.dart b/sdk/lib/_internal/compiler/implementation/patch_parser.dart
index 57dbd25..5a0da01 100644
--- a/sdk/lib/_internal/compiler/implementation/patch_parser.dart
+++ b/sdk/lib/_internal/compiler/implementation/patch_parser.dart
@@ -118,6 +118,7 @@
import "tree/tree.dart" as tree;
import "dart2jslib.dart" as leg; // CompilerTask, Compiler.
import "apiimpl.dart";
+import "../compiler.dart" as api;
import "scanner/scannerlib.dart"; // Scanner, Parsers, Listeners
import "elements/elements.dart";
import "elements/modelx.dart" show LibraryElementX, MetadataAnnotationX;
@@ -192,89 +193,14 @@
}));
}
- void applyContainerPatch(ScopeContainerElement original,
+ void applyContainerPatch(ClassElement originClass,
Link<Element> patches) {
- while (!patches.isEmpty) {
- Element patchElement = patches.head;
- Element originalElement = original.localLookup(patchElement.name);
- if (patchElement.isAccessor() && originalElement != null) {
- if (!identical(originalElement.kind, ElementKind.ABSTRACT_FIELD)) {
- compiler.internalError(
- "Cannot patch non-getter/setter with getter/setter",
- element: originalElement);
- }
- AbstractFieldElement originalField = originalElement;
- if (patchElement.isGetter()) {
- originalElement = originalField.getter;
- } else {
- originalElement = originalField.setter;
- }
- }
- if (originalElement == null) {
- if (isPatchElement(patchElement)) {
- compiler.internalError("Cannot patch non-existing member '"
- "${patchElement.name.slowToString()}'.");
- }
- } else {
- patchMember(originalElement, patchElement);
- }
- patches = patches.tail;
- }
- }
+ for (Element patch in patches) {
+ if (!isPatchElement(patch)) continue;
- bool isPatchElement(Element element) {
- // TODO(lrn): More checks needed if we introduce metadata for real.
- // In that case, it must have the identifier "native" as metadata.
- for (Link link = element.metadata; !link.isEmpty; link = link.tail) {
- if (link.head is PatchMetadataAnnotation) return true;
+ Element origin = originClass.localLookup(patch.name);
+ patchElement(compiler, origin, patch);
}
- return false;
- }
-
- void patchMember(Element originalElement, Element patchElement) {
- // The original library has an element with the same name as the patch
- // library element.
- // In this case, the patch library element must be a function marked as
- // "patch" and it must have the same signature as the function it patches.
- if (!isPatchElement(patchElement)) {
- compiler.internalError("Cannot overwrite existing '"
- "${originalElement.name.slowToString()}' with non-patch.");
- }
- if (originalElement is! FunctionElement) {
- // TODO(lrn): Handle class declarations too.
- compiler.internalError("Can only patch functions", element: originalElement);
- }
- FunctionElement original = originalElement;
- if (!original.modifiers.isExternal()) {
- compiler.internalError("Can only patch external functions.", element: original);
- }
- if (patchElement is! FunctionElement ||
- !patchSignatureMatches(original, patchElement)) {
- compiler.internalError("Can only patch functions with matching signatures",
- element: original);
- }
- applyFunctionPatch(original, patchElement);
- }
-
- bool patchSignatureMatches(FunctionElement original, FunctionElement patch) {
- // TODO(lrn): Check that patches actually match the signature of
- // the function it's patching.
- return true;
- }
-
- void applyFunctionPatch(FunctionElement element,
- FunctionElement patchElement) {
- if (element.isPatched) {
- compiler.internalError("Trying to patch a function more than once.",
- element: element);
- }
- if (element.cachedNode != null) {
- compiler.internalError("Trying to patch an already compiled function.",
- element: element);
- }
- // Don't just assign the patch field. This also updates the cachedNode.
- element.setPatch(patchElement);
- patchElement.origin = element;
}
}
@@ -370,7 +296,7 @@
this.imports)
: super(listener, patchElement, idGenerator);
- MetadataAnnotation popMetadata() {
+ MetadataAnnotation popMetadataHack() {
// TODO(ahe): Remove this method.
popNode(); // Discard null.
return new PatchMetadataAnnotation();
@@ -404,59 +330,16 @@
imports.addLast(tag);
}
- void pushElement(Element element) {
- if (isMemberPatch || (isClassPatch && element is ClassElement)) {
+ void pushElement(Element patch) {
+ if (isMemberPatch || (isClassPatch && patch is ClassElement)) {
// Apply patch.
- element.addMetadata(popMetadata());
+ patch.addMetadata(popMetadataHack());
LibraryElement originLibrary = compilationUnitElement.getLibrary();
assert(originLibrary.isPatched);
- Element existing = originLibrary.localLookup(element.name);
- if (isMemberPatch) {
- if (element is! FunctionElement) {
- listener.internalErrorOnElement(element,
- "Member patch is not a function.");
- }
- FunctionElement functionElement = element;
- if (identical(existing.kind, ElementKind.ABSTRACT_FIELD)) {
- if (!element.isAccessor()) {
- listener.internalErrorOnElement(
- functionElement, "Patching non-accessor with accessor");
- }
- AbstractFieldElement field = existing;
- if (functionElement.isGetter()) {
- existing = field.getter;
- } else {
- existing = field.setter;
- }
- }
- if (existing is! FunctionElement) {
- listener.internalErrorOnElement(functionElement,
- "No corresponding method for patch.");
- }
- FunctionElement existingFunction = existing;
- if (existingFunction.isPatched) {
- listener.internalErrorOnElement(
- functionElement, "Patching the same function more than once.");
- }
- existingFunction.patch = functionElement;
- functionElement.origin = existingFunction;
- } else {
- assert(leg.invariant(element, element is ClassElement));
- ClassElement classElement = element;
- if (existing is! ClassElement) {
- listener.internalErrorOnElement(
- classElement, "Patching a non-class with a class patch.");
- }
- ClassElement existingClass = existing;
- if (existingClass.isPatched) {
- listener.internalErrorOnElement(
- classElement, "Patching the same class more than once.");
- }
- existingClass.patch = classElement;
- classElement.origin = existingClass;
- }
+ Element origin = originLibrary.localLookup(patch.name);
+ patchElement(listener, origin, patch);
}
- super.pushElement(element);
+ super.pushElement(patch);
}
}
@@ -470,7 +353,7 @@
Element enclosingElement)
: super(listener, enclosingElement);
- MetadataAnnotation popMetadata() {
+ MetadataAnnotation popMetadataHack() {
// TODO(ahe): Remove this method.
popNode(); // Discard null.
return new PatchMetadataAnnotation();
@@ -495,7 +378,7 @@
void addMember(Element element) {
if (isMemberPatch || (isClassPatch && element is ClassElement)) {
- element.addMetadata(popMetadata());
+ element.addMetadata(popMetadataHack());
}
super.addMember(element);
}
@@ -508,4 +391,206 @@
PatchMetadataAnnotation() : super(STATE_DONE);
Token get beginToken => null;
+ Token get endToken => null;
+}
+
+void patchElement(leg.DiagnosticListener listener,
+ Element origin,
+ Element patch) {
+ if (origin == null) {
+ listener.reportMessage(
+ listener.spanFromSpannable(patch),
+ leg.MessageKind.PATCH_NON_EXISTING.error({'name': patch.name}),
+ api.Diagnostic.ERROR);
+ return;
+ }
+ if (!(origin.isClass() ||
+ origin.isConstructor() ||
+ origin.isFunction() ||
+ origin.isAbstractField())) {
+ listener.reportMessage(
+ listener.spanFromSpannable(origin),
+ leg.MessageKind.PATCH_NONPATCHABLE.error(),
+ api.Diagnostic.ERROR);
+ return;
+ }
+ if (patch.isClass()) {
+ tryPatchClass(listener, origin, patch);
+ } else if (patch.isGetter()) {
+ tryPatchGetter(listener, origin, patch);
+ } else if (patch.isSetter()) {
+ tryPatchSetter(listener, origin, patch);
+ } else if (patch.isConstructor()) {
+ tryPatchConstructor(listener, origin, patch);
+ } else if(patch.isFunction()) {
+ tryPatchFunction(listener, origin, patch);
+ } else {
+ listener.reportMessage(
+ listener.spanFromSpannable(patch),
+ leg.MessageKind.PATCH_NONPATCHABLE.error(),
+ api.Diagnostic.ERROR);
+ }
+}
+
+void tryPatchClass(leg.DiagnosticListener listener,
+ Element origin,
+ ClassElement patch) {
+ if (!origin.isClass()) {
+ listener.reportMessage(
+ listener.spanFromSpannable(origin),
+ leg.MessageKind.PATCH_NON_CLASS.error({'className': patch.name}),
+ api.Diagnostic.ERROR);
+ listener.reportMessage(
+ listener.spanFromSpannable(patch),
+ leg.MessageKind.PATCH_POINT_TO_CLASS.error({'className': patch.name}),
+ api.Diagnostic.INFO);
+ return;
+ }
+ patchClass(listener, origin, patch);
+}
+
+void patchClass(leg.DiagnosticListener listener,
+ ClassElement origin,
+ ClassElement patch) {
+ if (origin.isPatched) {
+ listener.internalErrorOnElement(
+ origin, "Patching the same class more than once.");
+ }
+ // TODO(johnniwinther): Change to functions on the ElementX class.
+ origin.patch = patch;
+ patch.origin = origin;
+}
+
+void tryPatchGetter(leg.DiagnosticListener listener,
+ Element origin,
+ FunctionElement patch) {
+ if (!origin.isAbstractField()) {
+ listener.reportMessage(
+ listener.spanFromSpannable(origin),
+ leg.MessageKind.PATCH_NON_GETTER.error({'name': origin.name}),
+ api.Diagnostic.ERROR);
+ listener.reportMessage(
+ listener.spanFromSpannable(patch),
+ leg.MessageKind.PATCH_POINT_TO_GETTER.error({'getterName': patch.name}),
+ api.Diagnostic.INFO);
+ return;
+ }
+ AbstractFieldElement originField = origin;
+ if (originField.getter == null) {
+ listener.reportMessage(
+ listener.spanFromSpannable(origin),
+ leg.MessageKind.PATCH_NO_GETTER.error({'getterName': patch.name}),
+ api.Diagnostic.ERROR);
+ listener.reportMessage(
+ listener.spanFromSpannable(patch),
+ leg.MessageKind.PATCH_POINT_TO_GETTER.error({'getterName': patch.name}),
+ api.Diagnostic.INFO);
+ return;
+ }
+ patchFunction(listener, originField.getter, patch);
+}
+
+void tryPatchSetter(leg.DiagnosticListener listener,
+ Element origin,
+ FunctionElement patch) {
+ if (!origin.isAbstractField()) {
+ listener.reportMessage(
+ listener.spanFromSpannable(origin),
+ leg.MessageKind.PATCH_NON_SETTER.error({'name': origin.name}),
+ api.Diagnostic.ERROR);
+ listener.reportMessage(
+ listener.spanFromSpannable(patch),
+ leg.MessageKind.PATCH_POINT_TO_SETTER.error({'setterName': patch.name}),
+ api.Diagnostic.INFO);
+ return;
+ }
+ AbstractFieldElement originField = origin;
+ if (originField.setter == null) {
+ listener.reportMessage(
+ listener.spanFromSpannable(origin),
+ leg.MessageKind.PATCH_NO_SETTER.error({'setterName': patch.name}),
+ api.Diagnostic.ERROR);
+ listener.reportMessage(
+ listener.spanFromSpannable(patch),
+ leg.MessageKind.PATCH_POINT_TO_SETTER.error({'setterName': patch.name}),
+ api.Diagnostic.INFO);
+ return;
+ }
+ patchFunction(listener, originField.setter, patch);
+}
+
+void tryPatchConstructor(leg.DiagnosticListener listener,
+ Element origin,
+ FunctionElement patch) {
+ if (!origin.isConstructor()) {
+ listener.reportMessage(
+ listener.spanFromSpannable(origin),
+ leg.MessageKind.PATCH_NON_CONSTRUCTOR.error(
+ {'constructorName': patch.name}),
+ api.Diagnostic.ERROR);
+ listener.reportMessage(
+ listener.spanFromSpannable(patch),
+ leg.MessageKind.PATCH_POINT_TO_CONSTRUCTOR.error(
+ {'constructorName': patch.name}),
+ api.Diagnostic.INFO);
+ return;
+ }
+ patchFunction(listener, origin, patch);
+}
+
+void tryPatchFunction(leg.DiagnosticListener listener,
+ Element origin,
+ FunctionElement patch) {
+ if (!origin.isFunction()) {
+ listener.reportMessage(
+ listener.spanFromSpannable(origin),
+ leg.MessageKind.PATCH_NON_FUNCTION.error({'functionName': patch.name}),
+ api.Diagnostic.ERROR);
+ listener.reportMessage(
+ listener.spanFromSpannable(patch),
+ leg.MessageKind.PATCH_POINT_TO_FUNCTION.error(
+ {'functionName': patch.name}),
+ api.Diagnostic.INFO);
+ return;
+ }
+ patchFunction(listener, origin, patch);
+}
+
+void patchFunction(leg.DiagnosticListener listener,
+ FunctionElement origin,
+ FunctionElement patch) {
+ if (!origin.modifiers.isExternal()) {
+ listener.reportMessage(
+ listener.spanFromSpannable(origin),
+ leg.MessageKind.PATCH_NON_EXTERNAL.error(),
+ api.Diagnostic.ERROR);
+ listener.reportMessage(
+ listener.spanFromSpannable(patch),
+ leg.MessageKind.PATCH_POINT_TO_FUNCTION.error(
+ {'functionName': patch.name}),
+ api.Diagnostic.INFO);
+ return;
+ }
+ if (origin.isPatched) {
+ listener.internalErrorOnElement(origin,
+ "Trying to patch a function more than once.");
+ }
+ if (origin.cachedNode != null) {
+ listener.internalErrorOnElement(origin,
+ "Trying to patch an already compiled function.");
+ }
+ // Don't just assign the patch field. This also updates the cachedNode.
+ // TODO(johnniwinther): Change to functions on the ElementX class.
+ origin.setPatch(patch);
+ patch.origin = origin;
+}
+
+// TODO(johnniwinther): Add unittest when patch is (real) metadata.
+bool isPatchElement(Element element) {
+ // TODO(lrn): More checks needed if we introduce metadata for real.
+ // In that case, it must have the identifier "native" as metadata.
+ for (Link link = element.metadata; !link.isEmpty; link = link.tail) {
+ if (link.head is PatchMetadataAnnotation) return true;
+ }
+ return false;
}
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/members.dart b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
index bc90813..e62aa70 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/members.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
@@ -99,7 +99,11 @@
ClassElement cls = element;
cls.ensureResolved(compiler);
return null;
- } else if (element.isTypedef() || element.isTypeVariable()) {
+ } else if (element.isTypedef()) {
+ TypedefElement typdef = element;
+ resolveTypedef(typdef);
+ return null;
+ } else if (element.isTypeVariable()) {
element.computeType(compiler);
return null;
}
@@ -250,7 +254,7 @@
return compiler.withCurrentElement(element, () {
FunctionExpression tree = element.parseNode(compiler);
if (tree.modifiers.isExternal()) {
- error(tree, MessageKind.EXTERNAL_WITHOUT_IMPLEMENTATION);
+ error(tree, MessageKind.PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION);
return;
}
if (isConstructor) {
@@ -691,13 +695,16 @@
if (value == null) return;
if (!(isUserDefinableOperator(value) || identical(value, 'unary-'))) return;
+ bool isMinus = false;
int requiredParameterCount;
MessageKind messageKind;
FunctionSignature signature = function.computeSignature(compiler);
if (identical(value, 'unary-')) {
+ isMinus = true;
messageKind = MessageKind.MINUS_OPERATOR_BAD_ARITY;
requiredParameterCount = 0;
} else if (isMinusOperator(value)) {
+ isMinus = true;
messageKind = MessageKind.MINUS_OPERATOR_BAD_ARITY;
requiredParameterCount = 1;
} else if (isUnaryOperator(value)) {
@@ -713,17 +720,40 @@
compiler.internalErrorOnElement(function,
'Unexpected user defined operator $value');
}
- checkArity(function, requiredParameterCount, messageKind);
+ checkArity(function, requiredParameterCount, messageKind, isMinus);
}
void checkArity(FunctionElement function,
- int requiredParameterCount, MessageKind messageKind) {
+ int requiredParameterCount, MessageKind messageKind,
+ bool isMinus) {
FunctionExpression node = function.parseNode(compiler);
FunctionSignature signature = function.computeSignature(compiler);
if (signature.requiredParameterCount != requiredParameterCount) {
Node errorNode = node;
if (node.parameters != null) {
- if (signature.requiredParameterCount < requiredParameterCount) {
+ if (isMinus ||
+ signature.requiredParameterCount < requiredParameterCount) {
+ // If there are too few parameters, point to the whole parameter list.
+ // For instance
+ //
+ // int operator +() {}
+ // ^^
+ //
+ // int operator []=(value) {}
+ // ^^^^^^^
+ //
+ // For operator -, always point the whole parameter list, like
+ //
+ // int operator -(a, b) {}
+ // ^^^^^^
+ //
+ // instead of
+ //
+ // int operator -(a, b) {}
+ // ^
+ //
+ // since the correction might not be to remove 'b' but instead to
+ // remove 'a, b'.
errorNode = node.parameters;
} else {
errorNode = node.parameters.nodes.skip(requiredParameterCount).head;
@@ -2593,6 +2623,7 @@
}
visitLiteralMap(LiteralMap node) {
+ world.registerInstantiatedClass(compiler.mapClass);
node.visitChildren(this);
}
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/class_element_parser.dart b/sdk/lib/_internal/compiler/implementation/scanner/class_element_parser.dart
index 9f99715..1e359aa 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/class_element_parser.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/class_element_parser.dart
@@ -192,6 +192,6 @@
popNode(); // Discard name.
}
popNode(); // Discard node (Send or Identifier).
- pushMetadata(new PartialMetadataAnnotation(beginToken));
+ pushMetadata(new PartialMetadataAnnotation(beginToken, endToken));
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/listener.dart b/sdk/lib/_internal/compiler/implementation/scanner/listener.dart
index 289c2c8..e535f62 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/listener.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/listener.dart
@@ -105,7 +105,7 @@
void beginFormalParameter(Token token) {
}
- void endFormalParameter(Token token, Token thisKeyword) {
+ void endFormalParameter(Token thisKeyword) {
}
void handleNoFormalParameters(Token token) {
@@ -348,6 +348,9 @@
void endRethrowStatement(Token throwToken, Token endToken) {
}
+ void endTopLevelDeclaration(Token token) {
+ }
+
void beginTopLevelMember(Token token) {
}
@@ -682,7 +685,8 @@
void endLibraryName(Token libraryKeyword, Token semicolon) {
Expression name = popNode();
- addLibraryTag(new LibraryName(libraryKeyword, name));
+ addLibraryTag(new LibraryName(libraryKeyword, name,
+ popMetadata(compilationUnitElement)));
}
void endImport(Token importKeyword, Token asKeyword, Token semicolon) {
@@ -692,13 +696,15 @@
prefix = popNode();
}
StringNode uri = popLiteralString();
- addLibraryTag(new Import(importKeyword, uri, prefix, combinators));
+ addLibraryTag(new Import(importKeyword, uri, prefix, combinators,
+ popMetadata(compilationUnitElement)));
}
void endExport(Token exportKeyword, Token semicolon) {
NodeList combinators = popNode();
StringNode uri = popNode();
- addLibraryTag(new Export(exportKeyword, uri, combinators));
+ addLibraryTag(new Export(exportKeyword, uri, combinators,
+ popMetadata(compilationUnitElement)));
}
void endCombinators(int count) {
@@ -728,12 +734,14 @@
void endPart(Token partKeyword, Token semicolon) {
StringNode uri = popLiteralString();
- addLibraryTag(new Part(partKeyword, uri));
+ addLibraryTag(new Part(partKeyword, uri,
+ popMetadata(compilationUnitElement)));
}
void endPartOf(Token partKeyword, Token semicolon) {
Expression name = popNode();
- addPartOfTag(new PartOf(partKeyword, name));
+ addPartOfTag(new PartOf(partKeyword, name,
+ popMetadata(compilationUnitElement)));
}
void addPartOfTag(PartOf tag) {
@@ -765,7 +773,15 @@
popNode(); // Discard name.
}
popNode(); // Discard node (Send or Identifier).
- pushMetadata(new PartialMetadataAnnotation(beginToken));
+ pushMetadata(new PartialMetadataAnnotation(beginToken, endToken));
+ }
+
+ void endTopLevelDeclaration(Token token) {
+ if (!metadata.isEmpty) {
+ recoverableError('Error: Metadata not supported here.',
+ token: metadata.head.beginToken);
+ metadata = const Link<MetadataAnnotation>();
+ }
}
void endClassDeclaration(int interfacesCount, Token beginToken,
@@ -1050,11 +1066,17 @@
}
void pushElement(Element element) {
+ popMetadata(element);
+ compilationUnitElement.addMember(element, listener);
+ }
+
+ Link<MetadataAnnotation> popMetadata(Element element) {
+ var result = metadata;
for (Link link = metadata; !link.isEmpty; link = link.tail) {
element.addMetadata(link.head);
}
metadata = const Link<MetadataAnnotation>();
- compilationUnitElement.addMember(element, listener);
+ return result;
}
void pushMetadata(MetadataAnnotation annotation) {
@@ -1252,9 +1274,9 @@
}
void endTopLevelFields(int count, Token beginToken, Token endToken) {
- NodeList variables = makeNodeList(count, null, null, ",");
+ NodeList variables = makeNodeList(count, null, endToken, ",");
Modifiers modifiers = popNode();
- pushNode(new VariableDefinitions(null, modifiers, variables, endToken));
+ pushNode(new VariableDefinitions(null, modifiers, variables));
}
void endTopLevelMethod(Token beginToken, Token getOrSet, Token endToken) {
@@ -1275,7 +1297,7 @@
modifiers, compilationUnitElement));
}
- void endFormalParameter(Token token, Token thisKeyword) {
+ void endFormalParameter(Token thisKeyword) {
Expression name = popNode();
if (thisKeyword != null) {
Identifier thisIdentifier = new Identifier(thisKeyword);
@@ -1287,8 +1309,8 @@
}
TypeAnnotation type = popNode();
Modifiers modifiers = popNode();
- pushNode(new VariableDefinitions(type, modifiers,
- new NodeList.singleton(name), token));
+ pushNode(
+ new VariableDefinitions(type, modifiers, new NodeList.singleton(name)));
}
void endFormalParameters(int count, Token beginToken, Token endToken) {
@@ -1507,10 +1529,10 @@
void endVariablesDeclaration(int count, Token endToken) {
// TODO(ahe): Pick one name for this concept, either
// VariablesDeclaration or VariableDefinitions.
- NodeList variables = makeNodeList(count, null, null, ",");
+ NodeList variables = makeNodeList(count, null, endToken, ",");
TypeAnnotation type = popNode();
Modifiers modifiers = popNode();
- pushNode(new VariableDefinitions(type, modifiers, variables, endToken));
+ pushNode(new VariableDefinitions(type, modifiers, variables));
}
void endInitializer(Token assignmentOperator) {
@@ -1617,10 +1639,10 @@
}
void endFields(int count, Token beginToken, Token endToken) {
- NodeList variables = makeNodeList(count, null, null, ",");
+ NodeList variables = makeNodeList(count, null, endToken, ",");
TypeAnnotation type = popNode();
Modifiers modifiers = popNode();
- pushNode(new VariableDefinitions(type, modifiers, variables, endToken));
+ pushNode(new VariableDefinitions(type, modifiers, variables));
}
void endMethod(Token getOrSet, Token beginToken, Token endToken) {
@@ -2008,10 +2030,19 @@
/// A [MetadataAnnotation] which is constructed on demand.
class PartialMetadataAnnotation extends MetadataAnnotationX {
final Token beginToken;
+ final Token tokenAfterEndToken;
Expression cachedNode;
Constant value;
- PartialMetadataAnnotation(this.beginToken);
+ PartialMetadataAnnotation(this.beginToken, this.tokenAfterEndToken);
+
+ Token get endToken {
+ Token token = beginToken;
+ while (token.kind != EOF_TOKEN) {
+ if (identical(token.next, tokenAfterEndToken)) return token;
+ token = token.next;
+ }
+ }
Node parseNode(DiagnosticListener listener) {
if (cachedNode != null) return cachedNode;
diff --git a/sdk/lib/_internal/compiler/implementation/scanner/parser.dart b/sdk/lib/_internal/compiler/implementation/scanner/parser.dart
index ef0f417..5a85e00 100644
--- a/sdk/lib/_internal/compiler/implementation/scanner/parser.dart
+++ b/sdk/lib/_internal/compiler/implementation/scanner/parser.dart
@@ -38,6 +38,7 @@
int count = 0;
while (!identical(token.kind, EOF_TOKEN)) {
token = parseTopLevelDeclaration(token);
+ listener.endTopLevelDeclaration(token);
count++;
}
listener.endCompilationUnit(count, token);
@@ -363,7 +364,7 @@
token = parseExpression(token.next);
listener.handleValuedFormalParameter(equal, token);
}
- listener.endFormalParameter(token, thisKeyword);
+ listener.endFormalParameter(thisKeyword);
return token;
}
@@ -554,10 +555,26 @@
/**
* Returns true if the stringValue of the [token] is [value].
*/
- bool optional(String value, Token token) => identical(value, token.stringValue);
+ bool optional(String value, Token token) {
+ return identical(value, token.stringValue);
+ }
+
+ /**
+ * Returns true if the stringValue of the [token] is either [value1],
+ * [value2], [value3], or [value4].
+ */
+ bool isOneOf4(Token token,
+ String value1, String value2, String value3, String value4) {
+ String stringValue = token.stringValue;
+ return identical(value1, stringValue) ||
+ identical(value2, stringValue) ||
+ identical(value3, stringValue) ||
+ identical(value4, stringValue);
+ }
bool notEofOrValue(String value, Token token) {
- return !identical(token.kind, EOF_TOKEN) && !identical(value, token.stringValue);
+ return !identical(token.kind, EOF_TOKEN) &&
+ !identical(value, token.stringValue);
}
Token parseType(Token token) {
@@ -1868,11 +1885,15 @@
}
Token parseVariablesDeclaration(Token token) {
- token = parseVariablesDeclarationNoSemicolon(token);
- return expectSemicolon(token);
+ return parseVariablesDeclarationMaybeSemicolon(token, true);
}
Token parseVariablesDeclarationNoSemicolon(Token token) {
+ return parseVariablesDeclarationMaybeSemicolon(token, false);
+ }
+
+ Token parseVariablesDeclarationMaybeSemicolon(Token token,
+ bool endWithSemicolon) {
int count = 1;
listener.beginVariablesDeclaration(token);
token = parseModifiers(token);
@@ -1882,8 +1903,15 @@
token = parseOptionallyInitializedIdentifier(token.next);
++count;
}
- listener.endVariablesDeclaration(count, token);
- return token;
+ if (endWithSemicolon) {
+ Token semicolon = token;
+ token = expectSemicolon(semicolon);
+ listener.endVariablesDeclaration(count, semicolon);
+ return token;
+ } else {
+ listener.endVariablesDeclaration(count, null);
+ return token;
+ }
}
Token parseOptionallyInitializedIdentifier(Token token) {
@@ -1933,10 +1961,7 @@
Token identifier = peekIdentifierAfterType(token);
if (identifier != null) {
assert(identifier.isIdentifier());
- Token afterId = identifier.next;
- int afterIdKind = afterId.kind;
- if (identical(afterIdKind, EQ_TOKEN) || identical(afterIdKind, SEMICOLON_TOKEN) ||
- identical(afterIdKind, COMMA_TOKEN) || optional('in', afterId)) {
+ if (isOneOf4(identifier.next, '=', ';', ',', 'in')) {
return parseVariablesDeclarationNoSemicolon(token);
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/source_file_provider.dart b/sdk/lib/_internal/compiler/implementation/source_file_provider.dart
index 1c27852..c100694 100644
--- a/sdk/lib/_internal/compiler/implementation/source_file_provider.dart
+++ b/sdk/lib/_internal/compiler/implementation/source_file_provider.dart
@@ -49,6 +49,10 @@
}
}
+void silentDiagnosticHandler(Uri uri, int begin, int end, String message,
+ api.Diagnostic kind) {
+}
+
class FormattingDiagnosticHandler {
final SourceFileProvider provider;
bool showWarnings = true;
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/bailout.dart b/sdk/lib/_internal/compiler/implementation/ssa/bailout.dart
index ddf6bab..0e10ecf 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/bailout.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/bailout.dart
@@ -112,9 +112,17 @@
if (source != null) {
DartType sourceType = source.computeType(compiler);
DartType speculatedType = speculativeType.computeType(compiler);
- if (speculatedType != null &&
- !compiler.types.isAssignable(speculatedType, sourceType)) {
- return false;
+ JavaScriptBackend backend = compiler.backend;
+ if (speculatedType != null) {
+ // Use the num type instead of JSNumber because JSNumber
+ // is not assignment compatible with int and double, but we
+ // still want to generate a type guard.
+ if (speculatedType.element == backend.jsNumberClass) {
+ speculatedType = compiler.numClass.computeType(compiler);
+ }
+ if (!compiler.types.isAssignable(speculatedType, sourceType)) {
+ return false;
+ }
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
index 5ae62cb..ac19fea 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
@@ -2399,7 +2399,7 @@
// creating an [HStatic].
push(new HStatic(element.declaration));
if (element.isGetter()) {
- push(new HInvokeStatic(<HInstruction>[pop()]));
+ push(new HInvokeStatic(<HInstruction>[pop()], HType.UNKNOWN));
}
}
} else if (Elements.isInstanceSend(send, elements)) {
@@ -2455,7 +2455,9 @@
if (element.isSetter()) {
HStatic target = new HStatic(element);
add(target);
- addWithPosition(new HInvokeStatic(<HInstruction>[target, value]), send);
+ addWithPosition(
+ new HInvokeStatic(<HInstruction>[target, value], HType.UNKNOWN),
+ send);
} else {
value = potentiallyCheckType(value, element.computeType(compiler));
addWithPosition(new HStaticStore(element, value), send);
@@ -2493,54 +2495,69 @@
return interceptor;
}
- void pushInvokeHelper0(Element helper) {
+ void pushInvokeHelper0(Element helper, HType type) {
HInstruction reference = new HStatic(helper);
add(reference);
List<HInstruction> inputs = <HInstruction>[reference];
- HInstruction result = new HInvokeStatic(inputs);
+ HInstruction result = new HInvokeStatic(inputs, type);
push(result);
}
- void pushInvokeHelper1(Element helper, HInstruction a0) {
+ void pushInvokeHelper1(Element helper, HInstruction a0, HType type) {
HInstruction reference = new HStatic(helper);
add(reference);
List<HInstruction> inputs = <HInstruction>[reference, a0];
- HInstruction result = new HInvokeStatic(inputs);
+ HInstruction result = new HInvokeStatic(inputs, type);
push(result);
}
- void pushInvokeHelper2(Element helper, HInstruction a0, HInstruction a1) {
+ void pushInvokeHelper2(Element helper,
+ HInstruction a0,
+ HInstruction a1,
+ HType type) {
HInstruction reference = new HStatic(helper);
add(reference);
List<HInstruction> inputs = <HInstruction>[reference, a0, a1];
- HInstruction result = new HInvokeStatic(inputs);
+ HInstruction result = new HInvokeStatic(inputs, type);
push(result);
}
- void pushInvokeHelper3(Element helper, HInstruction a0, HInstruction a1,
- HInstruction a2) {
+ void pushInvokeHelper3(Element helper,
+ HInstruction a0,
+ HInstruction a1,
+ HInstruction a2,
+ HType type) {
HInstruction reference = new HStatic(helper);
add(reference);
List<HInstruction> inputs = <HInstruction>[reference, a0, a1, a2];
- HInstruction result = new HInvokeStatic(inputs);
+ HInstruction result = new HInvokeStatic(inputs, type);
push(result);
}
- void pushInvokeHelper4(Element helper, HInstruction a0, HInstruction a1,
- HInstruction a2, HInstruction a3) {
+ void pushInvokeHelper4(Element helper,
+ HInstruction a0,
+ HInstruction a1,
+ HInstruction a2,
+ HInstruction a3,
+ HType type) {
HInstruction reference = new HStatic(helper);
add(reference);
List<HInstruction> inputs = <HInstruction>[reference, a0, a1, a2, a3];
- HInstruction result = new HInvokeStatic(inputs);
+ HInstruction result = new HInvokeStatic(inputs, type);
push(result);
}
- void pushInvokeHelper5(Element helper, HInstruction a0, HInstruction a1,
- HInstruction a2, HInstruction a3, HInstruction a4) {
+ void pushInvokeHelper5(Element helper,
+ HInstruction a0,
+ HInstruction a1,
+ HInstruction a2,
+ HInstruction a3,
+ HInstruction a4,
+ HType type) {
HInstruction reference = new HStatic(helper);
add(reference);
List<HInstruction> inputs = <HInstruction>[reference, a0, a1, a2, a3, a4];
- HInstruction result = new HInvokeStatic(inputs);
+ HInstruction result = new HInvokeStatic(inputs, type);
push(result);
}
@@ -2549,7 +2566,7 @@
}
HInstruction getRuntimeTypeInfo(HInstruction target) {
- pushInvokeHelper1(backend.getGetRuntimeTypeInfo(), target);
+ pushInvokeHelper1(backend.getGetRuntimeTypeInfo(), target, HType.UNKNOWN);
return pop();
}
@@ -2662,7 +2679,7 @@
// Create the call to isSubtype.
List<HInstruction> inputs =
<HInstruction>[isSubtype, typeArgument, representation];
- HInstruction call = new HInvokeStatic(inputs);
+ HInstruction call = new HInvokeStatic(inputs, HType.BOOLEAN);
add(call);
checks.add(call);
index++;
@@ -2906,7 +2923,7 @@
compiler.cancel(
'Isolate library and compiler mismatch', node: node);
}
- pushInvokeHelper0(element);
+ pushInvokeHelper0(element, HType.UNKNOWN);
}
}
@@ -2930,7 +2947,7 @@
add(target);
List<HInstruction> inputs = <HInstruction>[target];
addGenericSendArgumentsToList(link, inputs);
- push(new HInvokeStatic(inputs));
+ push(new HInvokeStatic(inputs, HType.UNKNOWN));
}
}
@@ -3067,7 +3084,8 @@
graph.addConstant(internalNameConstant),
graph.addConstant(kindConstant),
argumentsInstruction,
- argumentNamesInstruction);
+ argumentNamesInstruction,
+ HType.UNKNOWN);
var inputs = <HInstruction>[
target,
@@ -3153,7 +3171,8 @@
// The type variable is stored in [this].
if (typeInfo == null) {
pushInvokeHelper1(backend.getGetRuntimeTypeInfo(),
- localsHandler.readThis());
+ localsHandler.readThis(),
+ HType.UNKNOWN);
typeInfo = pop();
}
int index = RuntimeTypeInformation.getTypeVariableIndex(type);
@@ -3204,7 +3223,7 @@
HInstruction typeInfoSetter = new HStatic(typeInfoSetterElement);
add(typeInfoSetter);
add(new HInvokeStatic(
- <HInstruction>[typeInfoSetter, newObject, typeInfo]));
+ <HInstruction>[typeInfoSetter, newObject, typeInfo], HType.UNKNOWN));
}
/**
@@ -3334,7 +3353,7 @@
return;
}
- HInvokeStatic instruction = new HInvokeStatic(inputs);
+ HInvokeStatic instruction = new HInvokeStatic(inputs, HType.UNKNOWN);
// TODO(ngeoffray): Only do this if knowing the return type is
// useful.
HType returnType =
@@ -3395,7 +3414,7 @@
void generateError(Node node, String message, Element helper) {
HInstruction errorMessage = addConstantString(node, message);
- pushInvokeHelper1(helper, errorMessage);
+ pushInvokeHelper1(helper, errorMessage, HType.UNKNOWN);
}
void generateRuntimeError(Node node, String message) {
@@ -3446,7 +3465,8 @@
} else {
existingNamesList = graph.addConstantNull(constantSystem);
}
- pushInvokeHelper4(helper, receiver, name, arguments, existingNamesList);
+ pushInvokeHelper4(
+ helper, receiver, name, arguments, existingNamesList, HType.UNKNOWN);
}
/**
@@ -3473,7 +3493,7 @@
HInstruction typeString = addConstantString(node, type.toString());
HInstruction reasonsString = addConstantString(node, reasons);
Element helper = backend.getThrowMalformedSubtypeError();
- pushInvokeHelper3(helper, value, typeString, reasonsString);
+ pushInvokeHelper3(helper, value, typeString, reasonsString, HType.UNKNOWN);
}
visitNewExpression(NewExpression node) {
@@ -4000,7 +4020,10 @@
}
HLiteralList keyValuePairs = new HLiteralList(inputs);
add(keyValuePairs);
- pushInvokeHelper1(backend.getMapMaker(), keyValuePairs);
+ pushInvokeHelper1(backend.getMapMaker(), keyValuePairs,
+ new HType.fromBoundedType(compiler.mapClass.computeType(compiler),
+ compiler,
+ false));
}
visitLiteralMapEntry(LiteralMapEntry node) {
@@ -4161,7 +4184,7 @@
localsHandler = new LocalsHandler.from(savedLocals);
visit(switchCase.statements);
if (!isAborted() && caseIterator.hasNext) {
- pushInvokeHelper0(getFallThroughErrorElement);
+ pushInvokeHelper0(getFallThroughErrorElement, HType.UNKNOWN);
HInstruction error = pop();
close(new HThrow(error));
}
@@ -4278,7 +4301,7 @@
compiler.reportWarning(node, 'Missing break at end of switch case');
Element element =
compiler.findHelper(const SourceString("getFallThroughError"));
- pushInvokeHelper0(element);
+ pushInvokeHelper0(element, HType.UNKNOWN);
HInstruction error = pop();
close(new HThrow(error));
}
@@ -4415,7 +4438,8 @@
HInstruction oldRethrowableException = rethrowableException;
rethrowableException = exception;
- pushInvokeHelper1(backend.getExceptionUnwrapper(), exception);
+ pushInvokeHelper1(
+ backend.getExceptionUnwrapper(), exception, HType.UNKNOWN);
HInvokeStatic unwrappedException = pop();
tryInstruction.exception = exception;
Link<Node> link = node.catchBlocks.nodes;
@@ -4462,7 +4486,8 @@
}
Node trace = catchBlock.trace;
if (trace != null) {
- pushInvokeHelper1(backend.getTraceFromException(), exception);
+ pushInvokeHelper1(
+ backend.getTraceFromException(), exception, HType.UNKNOWN);
HInstruction traceInstruction = pop();
localsHandler.updateLocal(elements[trace], traceInstruction);
}
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
index 8164118..e5caac1 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
@@ -100,7 +100,6 @@
codegen.visitGraph(graph);
js.Block body = new js.Block(<js.Statement>[]);
- if (codegen.setup != null) body.statements.add(codegen.setup);
body.statements.add(codegen.body);
js.Fun fun =
buildJavaScriptFunction(work.element, codegen.newParameters, body);
@@ -196,11 +195,8 @@
*/
final Set<String> declaredLocals;
- Element equalsNullElement;
- Element boolifiedEqualsNullElement;
int indent = 0;
HGraph currentGraph;
- HBasicBlock currentBlock;
// Records a block-information that is being handled specially.
// Used to break bad recursion.
@@ -1114,7 +1110,6 @@
// Abort traversal if we are leaving the currently active sub-graph.
if (!subGraph.contains(node)) return;
- currentBlock = node;
// If this node has block-structure based information attached,
// try using that to traverse from here.
if (node.blockFlow != null && handleBlockFlow(node.blockFlow)) {
@@ -1329,8 +1324,9 @@
}
visitGoto(HGoto node) {
- assert(currentBlock.successors.length == 1);
- List<HBasicBlock> dominated = currentBlock.dominatedBlocks;
+ HBasicBlock block = node.block;
+ assert(block.successors.length == 1);
+ List<HBasicBlock> dominated = block.dominatedBlocks;
// With the exception of the entry-node which dominates its successor
// and the exit node, no block finishing with a 'goto' can have more than
// one dominated block (since it has only one successor).
@@ -1341,11 +1337,11 @@
compiler.internalError('dominated.length = ${dominated.length}',
instruction: node);
}
- if (dominated.length == 2 && !identical(currentBlock, currentGraph.entry)) {
- compiler.internalError('currentBlock !== currentGraph.entry',
+ if (dominated.length == 2 && block != currentGraph.entry) {
+ compiler.internalError('node.block != currentGraph.entry',
instruction: node);
}
- assert(dominated[0] == currentBlock.successors[0]);
+ assert(dominated[0] == block.successors[0]);
visitBasicBlock(dominated[0]);
}
@@ -1374,7 +1370,7 @@
}
visitBreak(HBreak node) {
- assert(currentBlock.successors.length == 1);
+ assert(node.block.successors.length == 1);
if (node.label != null) {
LabelElement label = node.label;
if (!tryCallAction(breakAction, label)) {
@@ -1389,7 +1385,7 @@
}
visitContinue(HContinue node) {
- assert(currentBlock.successors.length == 1);
+ assert(node.block.successors.length == 1);
if (node.label != null) {
LabelElement label = node.label;
if (!tryCallAction(continueAction, label)) {
@@ -1519,18 +1515,20 @@
// seen selectors.
if (target.isGenerativeConstructorBody()) {
methodName = name.slowToString();
- } else if (target == backend.jsArrayAdd) {
- methodName = 'push';
- } else if (target == backend.jsArrayRemoveLast) {
- methodName = 'pop';
- } else if (target == backend.jsStringSplit) {
- methodName = 'split';
- // Split returns a List, so we make sure the backend knows the
- // list class is instantiated.
- world.registerInstantiatedClass(compiler.listClass);
- } else if (target == backend.jsStringConcat) {
- push(new js.Binary('+', object, arguments[0]), node);
- return;
+ } else if (!node.isInterceptorCall) {
+ if (target == backend.jsArrayAdd) {
+ methodName = 'push';
+ } else if (target == backend.jsArrayRemoveLast) {
+ methodName = 'pop';
+ } else if (target == backend.jsStringSplit) {
+ methodName = 'split';
+ // Split returns a List, so we make sure the backend knows the
+ // list class is instantiated.
+ world.registerInstantiatedClass(compiler.listClass);
+ } else if (target == backend.jsStringConcat) {
+ push(new js.Binary('+', object, arguments[0]), node);
+ return;
+ }
}
}
@@ -1560,17 +1558,14 @@
Selector getOptimizedSelectorFor(HInvokeDynamic node,
Selector defaultSelector) {
- // TODO(4434): For private members we need to use the untyped selector.
- if (defaultSelector.name.isPrivate()) return defaultSelector;
- // TODO(ngeoffray): Type intercepted calls.
- if (node.isInterceptorCall) return defaultSelector;
// If [JSInvocationMirror.invokeOn] has been called, we must not create a
// typed selector based on the receiver type.
if (node.element == null && // Invocation is not exact.
backend.compiler.enabledInvokeOn) {
return defaultSelector;
}
- HType receiverHType = types[node.inputs[0]];
+ int receiverIndex = node.isInterceptorCall ? 1 : 0;
+ HType receiverHType = types[node.inputs[receiverIndex]];
DartType receiverType = receiverHType.computeType(compiler);
if (receiverType != null &&
!identical(receiverType.kind, TypeKind.MALFORMED_TYPE)) {
@@ -1617,7 +1612,7 @@
if (target != null) {
// If we know we're calling a specific method, register that
// method only.
- world.registerDynamicInvocationOf(target);
+ world.registerDynamicInvocationOf(target, selector);
} else {
SourceString name = node.selector.name;
world.registerDynamicInvocation(name, selector);
@@ -2425,10 +2420,10 @@
world.registerIsCheck(type);
if (node.isArgumentTypeCheck) {
- if (element == compiler.intClass) {
+ if (element == backend.jsIntClass) {
checkInt(node.checkedInput, '!==');
} else {
- assert(element == compiler.numClass);
+ assert(element == backend.jsNumberClass);
checkNum(node.checkedInput, '!==');
}
js.Expression test = pop();
@@ -2635,7 +2630,6 @@
class SsaUnoptimizedCodeGenerator extends SsaCodeGenerator {
- js.Statement setup;
js.Switch currentBailoutSwitch;
final List<js.Switch> oldBailoutSwitches;
final List<js.Parameter> newParameters;
@@ -2941,7 +2935,7 @@
new js.Binary('===', generateStateUse(), new js.LiteralNumber('0'));
js.Expression condition = new js.Binary('&&', stateEquals0, pop());
// TODO(ngeoffray): Put the condition initialization in the
- // [setup] buffer.
+ // arguments?
List<HBailoutTarget> targets = node.thenBlock.bailoutTargets;
for (int i = 0, len = targets.length; i < len; i++) {
js.VariableUse stateRef = generateStateUse();
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
index 21b3d71..afbd2e1 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
@@ -1441,8 +1441,8 @@
class HInvokeStatic extends HInvoke {
/** The first input must be the target. */
- HInvokeStatic(inputs, [HType knownType = HType.UNKNOWN]) : super(inputs) {
- guaranteedType = knownType;
+ HInvokeStatic(inputs, HType type) : super(inputs) {
+ guaranteedType = type;
}
toString() => 'invoke static: ${element.name}';
@@ -1454,7 +1454,7 @@
class HInvokeSuper extends HInvokeStatic {
final bool isSetter;
- HInvokeSuper(inputs, {this.isSetter: false}) : super(inputs);
+ HInvokeSuper(inputs, {this.isSetter: false}) : super(inputs, HType.UNKNOWN);
toString() => 'invoke super: ${element.name}';
accept(HVisitor visitor) => visitor.visitInvokeSuper(this);
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
index c51395f..35ba2cb 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
@@ -145,15 +145,8 @@
while (instruction != null) {
HInstruction next = instruction.next;
HInstruction replacement = instruction.accept(this);
- if (!identical(replacement, instruction)) {
- if (!replacement.isInBasicBlock()) {
- // The constant folding can return an instruction that is already
- // part of the graph (like an input), so we only add the replacement
- // if necessary.
- block.addAfter(instruction, replacement);
- }
+ if (replacement != instruction) {
block.rewrite(instruction, replacement);
- block.remove(instruction);
// If we can replace [instruction] with [replacement], then
// [replacement]'s type can be narrowed.
@@ -169,6 +162,16 @@
if (replacement.sourcePosition == null) {
replacement.sourcePosition = instruction.sourcePosition;
}
+ if (!replacement.isInBasicBlock()) {
+ // The constant folding can return an instruction that is already
+ // part of the graph (like an input), so we only add the replacement
+ // if necessary.
+ block.addAfter(instruction, replacement);
+ // Visit the replacement as the next instruction in case it
+ // can also be constant folded away.
+ next = replacement;
+ }
+ block.remove(instruction);
}
instruction = next;
}
@@ -182,10 +185,10 @@
List<HInstruction> inputs = node.inputs;
assert(inputs.length == 1);
HInstruction input = inputs[0];
- if (input.isBoolean(types)) return input;
+ HType type = types[input];
+ if (type.isBoolean()) return input;
// All values !== true are boolified to false.
- DartType type = types[input].computeType(compiler);
- if (type != null && !identical(type.element, compiler.boolClass)) {
+ if (!type.isBooleanOrNull() && !type.isUnknown()) {
return graph.addConstantBool(false, constantSystem);
}
return node;
@@ -220,15 +223,43 @@
return null;
}
+ HInstruction optimizeLengthInterceptedGetter(HInvokeDynamic node) {
+ HInstruction actualReceiver = node.inputs[1];
+ if (actualReceiver.isIndexablePrimitive(types)) {
+ if (actualReceiver.isConstantString()) {
+ HConstant constantInput = actualReceiver;
+ StringConstant constant = constantInput.constant;
+ return graph.addConstantInt(constant.length, constantSystem);
+ } else if (actualReceiver.isConstantList()) {
+ HConstant constantInput = actualReceiver;
+ ListConstant constant = constantInput.constant;
+ return graph.addConstantInt(constant.length, constantSystem);
+ }
+ Element element;
+ bool isAssignable;
+ if (actualReceiver.isString(types)) {
+ element = backend.jsStringLength;
+ isAssignable = false;
+ } else {
+ element = backend.jsArrayLength;
+ isAssignable = !actualReceiver.isFixedArray(types);
+ }
+ HFieldGet result = new HFieldGet(
+ element, actualReceiver, isAssignable: isAssignable);
+ result.guaranteedType = HType.INTEGER;
+ types[result] = HType.INTEGER;
+ return result;
+ } else if (actualReceiver.isConstantMap()) {
+ HConstant constantInput = actualReceiver;
+ MapConstant constant = constantInput.constant;
+ return graph.addConstantInt(constant.length, constantSystem);
+ }
+ return node;
+ }
+
HInstruction handleInterceptorCall(HInvokeDynamic node) {
// We only optimize for intercepted method calls in this method.
- if (node.selector.isGetter() || node.selector.isSetter()) return node;
-
- HInstruction input = node.inputs[1];
- if (input.isString(types)
- && node.selector.name == const SourceString('toString')) {
- return node.inputs[1];
- }
+ Selector selector = node.selector;
// Try constant folding the instruction.
Operation operation = node.specializer.operation(constantSystem);
@@ -245,8 +276,16 @@
if (instruction != null) return instruction;
// Check if this call does not need to be intercepted.
+ HInstruction input = node.inputs[1];
HType type = types[input];
var interceptor = node.inputs[0];
+
+ if (interceptor.isConstant() && selector.isCall()) {
+ DartType type = types[interceptor].computeType(compiler);
+ ClassElement cls = type.element;
+ node.element = cls.lookupSelector(selector);
+ }
+
if (interceptor is !HThis && !type.canBePrimitive()) {
// If the type can be null, and the intercepted method can be in
// the object class, keep the interceptor.
@@ -260,42 +299,62 @@
}
if (interceptedClasses.contains(compiler.objectClass)) return node;
}
- // Change the call to a regular invoke dynamic call.
- return new HInvokeDynamicMethod(
- node.selector, node.inputs.getRange(1, node.inputs.length - 1));
+ if (selector.isGetter()) {
+ // Change the call to a regular invoke dynamic call.
+ return new HInvokeDynamicGetter(selector, null, input, false);
+ } else if (selector.isSetter()) {
+ return new HInvokeDynamicSetter(
+ selector, null, input, node.inputs[2], false);
+ } else {
+ // Change the call to a regular invoke dynamic call.
+ return new HInvokeDynamicMethod(
+ selector, node.inputs.getRange(1, node.inputs.length - 1));
+ }
}
- Selector selector = node.selector;
- SourceString selectorName = selector.name;
- Element target;
- if (input.isExtendableArray(types)) {
- if (selectorName == backend.jsArrayRemoveLast.name
- && selector.argumentCount == 0) {
- target = backend.jsArrayRemoveLast;
- } else if (selectorName == backend.jsArrayAdd.name
- && selector.argumentCount == 1
- && selector.namedArgumentCount == 0
- && !compiler.enableTypeAssertions) {
- target = backend.jsArrayAdd;
+ if (selector.isCall()) {
+ Element target;
+ if (input.isExtendableArray(types)) {
+ if (selector.applies(backend.jsArrayRemoveLast, compiler)) {
+ target = backend.jsArrayRemoveLast;
+ } else if (selector.applies(backend.jsArrayAdd, compiler)) {
+ // The codegen special cases array calls, but does not
+ // inline argument type checks.
+ if (!compiler.enableTypeAssertions) {
+ target = backend.jsArrayAdd;
+ }
+ }
+ } else if (input.isString(types)) {
+ if (selector.applies(backend.jsStringSplit, compiler)) {
+ if (node.inputs[2].isString(types)) {
+ target = backend.jsStringSplit;
+ }
+ } else if (selector.applies(backend.jsStringConcat, compiler)) {
+ if (node.inputs[2].isString(types)) {
+ target = backend.jsStringConcat;
+ }
+ } else if (selector.applies(backend.jsStringToString, compiler)) {
+ return input;
+ }
}
- } else if (input.isString(types)) {
- if (selectorName == backend.jsStringSplit.name
- && selector.argumentCount == 1
- && selector.namedArgumentCount == 0
- && node.inputs[2].isString(types)) {
- target = backend.jsStringSplit;
- } else if (selectorName == backend.jsStringConcat.name
- && selector.argumentCount == 1
- && selector.namedArgumentCount == 0
- && node.inputs[2].isString(types)) {
- target = backend.jsStringConcat;
+ if (target != null) {
+ // TODO(ngeoffray): There is a strong dependency between codegen
+ // and this optimization that the dynamic invoke does not need an
+ // interceptor. We currently need to keep a
+ // HInvokeDynamicMethod and not create a HForeign because
+ // HForeign is too opaque for the SssaCheckInserter (that adds a
+ // bounds check on removeLast). Once we start inlining, the
+ // bounds check will become explicit, so we won't need this
+ // optimization.
+ HInvokeDynamicMethod result = new HInvokeDynamicMethod(
+ node.selector, node.inputs.getRange(1, node.inputs.length - 1));
+ result.element = target;
+ return result;
}
- }
- if (target != null) {
- HInvokeDynamicMethod result = new HInvokeDynamicMethod(
- node.selector, node.inputs.getRange(1, node.inputs.length - 1));
- result.element = target;
- return result;
+ } else if (selector.isGetter()) {
+ if (selector.applies(backend.jsArrayLength, compiler)) {
+ return optimizeLengthInterceptedGetter(node);
+ }
}
return node;
}
@@ -345,29 +404,6 @@
return node;
}
- /**
- * Turns a primitive instruction (e.g. [HIndex], [HAdd], ...) into a
- * [HInvokeDynamic] because we know the receiver is not a JS
- * primitive object.
- */
- HInstruction fromPrimitiveInstructionToDynamicInvocation(HInstruction node,
- Selector selector) {
- HBoundedType type = types[node.inputs[1]];
- HInvokeDynamicMethod result = new HInvokeDynamicMethod(
- selector,
- node.inputs.getRange(1, node.inputs.length - 1));
- if (type.isExact()) {
- HBoundedType concrete = type;
- // TODO(johnniwinther): Add lookup by selector to HBoundedType.
- Element element = concrete.lookupMember(selector.name);
- if (selector.applies(element, compiler)) {
- // The target is only valid if the selector applies.
- result.element = element;
- }
- }
- return result;
- }
-
HInstruction visitIntegerCheck(HIntegerCheck node) {
HInstruction value = node.value;
if (value.isInteger(types)) return value;
@@ -584,45 +620,8 @@
return node;
}
- HInstruction optimizeLengthInterceptedCall(HInvokeDynamicGetter node) {
- HInstruction actualReceiver = node.inputs[1];
- if (actualReceiver.isIndexablePrimitive(types)) {
- if (actualReceiver.isConstantString()) {
- HConstant constantInput = actualReceiver;
- StringConstant constant = constantInput.constant;
- return graph.addConstantInt(constant.length, constantSystem);
- } else if (actualReceiver.isConstantList()) {
- HConstant constantInput = actualReceiver;
- ListConstant constant = constantInput.constant;
- return graph.addConstantInt(constant.length, constantSystem);
- }
- Element element;
- bool isAssignable;
- if (actualReceiver.isString(types)) {
- element = backend.jsStringLength;
- isAssignable = false;
- } else {
- element = backend.jsArrayLength;
- isAssignable = !actualReceiver.isFixedArray(types);
- }
- HFieldGet result = new HFieldGet(
- element, actualReceiver, isAssignable: isAssignable);
- result.guaranteedType = HType.INTEGER;
- types[result] = HType.INTEGER;
- return result;
- } else if (actualReceiver.isConstantMap()) {
- HConstant constantInput = actualReceiver;
- MapConstant constant = constantInput.constant;
- return graph.addConstantInt(constant.length, constantSystem);
- }
- return node;
- }
-
HInstruction visitInvokeDynamicGetter(HInvokeDynamicGetter node) {
- if (node.selector.name == const SourceString('length')
- && node.isInterceptorCall) {
- return optimizeLengthInterceptedCall(node);
- }
+ if (node.isInterceptorCall) return handleInterceptorCall(node);
Element field =
findConcreteFieldForDynamicAccess(node.receiver, node.selector);
@@ -647,6 +646,8 @@
}
HInstruction visitInvokeDynamicSetter(HInvokeDynamicSetter node) {
+ if (node.isInterceptorCall) return handleInterceptorCall(node);
+
Element field =
findConcreteFieldForDynamicAccess(node.receiver, node.selector);
if (field == null || !field.isAssignable()) return node;
@@ -700,7 +701,7 @@
} else if (type.isArray()) {
constantInterceptor = backend.jsArrayClass;
} else if (type.isNull()) {
- constantInterceptor = backend.jsIntClass;
+ constantInterceptor = backend.jsNullClass;
} else if (type.isNumber()) {
// If the method being intercepted is not defined in [int] or
// [double] we can safely use the number interceptor.
@@ -826,6 +827,7 @@
void visitInvokeDynamicMethod(HInvokeDynamicMethod node) {
Element element = node.element;
+ if (node.isInterceptorCall) return;
if (element != backend.jsArrayRemoveLast) return;
if (boundsChecked.contains(node)) return;
insertBoundsCheck(
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/types.dart b/sdk/lib/_internal/compiler/implementation/ssa/types.dart
index 06e432e..b6d4746 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/types.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/types.dart
@@ -173,7 +173,8 @@
String toString() => 'null';
DartType computeType(Compiler compiler) {
- return compiler.nullClass.computeType(compiler);
+ JavaScriptBackend backend = compiler.backend;
+ return backend.jsNullClass.computeType(compiler);
}
HType union(HType other, Compiler compiler) {
@@ -211,7 +212,8 @@
bool isBooleanOrNull() => true;
DartType computeType(Compiler compiler) {
- return compiler.boolClass.computeType(compiler);
+ JavaScriptBackend backend = compiler.backend;
+ return backend.jsBoolClass.computeType(compiler);
}
HType union(HType other, Compiler compiler) {
@@ -243,7 +245,8 @@
String toString() => "boolean";
DartType computeType(Compiler compiler) {
- return compiler.boolClass.computeType(compiler);
+ JavaScriptBackend backend = compiler.backend;
+ return backend.jsBoolClass.computeType(compiler);
}
HType union(HType other, Compiler compiler) {
@@ -270,7 +273,8 @@
String toString() => "number or null";
DartType computeType(Compiler compiler) {
- return compiler.numClass.computeType(compiler);
+ JavaScriptBackend backend = compiler.backend;
+ return backend.jsNumberClass.computeType(compiler);
}
HType union(HType other, Compiler compiler) {
@@ -306,7 +310,8 @@
String toString() => "number";
DartType computeType(Compiler compiler) {
- return compiler.numClass.computeType(compiler);
+ JavaScriptBackend backend = compiler.backend;
+ return backend.jsNumberClass.computeType(compiler);
}
HType union(HType other, Compiler compiler) {
@@ -335,7 +340,8 @@
String toString() => "integer or null";
DartType computeType(Compiler compiler) {
- return compiler.intClass.computeType(compiler);
+ JavaScriptBackend backend = compiler.backend;
+ return backend.jsIntClass.computeType(compiler);
}
HType union(HType other, Compiler compiler) {
@@ -373,7 +379,8 @@
String toString() => "integer";
DartType computeType(Compiler compiler) {
- return compiler.intClass.computeType(compiler);
+ JavaScriptBackend backend = compiler.backend;
+ return backend.jsIntClass.computeType(compiler);
}
HType union(HType other, Compiler compiler) {
@@ -406,7 +413,8 @@
String toString() => "double or null";
DartType computeType(Compiler compiler) {
- return compiler.doubleClass.computeType(compiler);
+ JavaScriptBackend backend = compiler.backend;
+ return backend.jsDoubleClass.computeType(compiler);
}
HType union(HType other, Compiler compiler) {
@@ -444,7 +452,8 @@
String toString() => "double";
DartType computeType(Compiler compiler) {
- return compiler.doubleClass.computeType(compiler);
+ JavaScriptBackend backend = compiler.backend;
+ return backend.jsDoubleClass.computeType(compiler);
}
HType union(HType other, Compiler compiler) {
@@ -512,7 +521,8 @@
String toString() => "String or null";
DartType computeType(Compiler compiler) {
- return compiler.stringClass.computeType(compiler);
+ JavaScriptBackend backend = compiler.backend;
+ return backend.jsStringClass.computeType(compiler);
}
HType union(HType other, Compiler compiler) {
@@ -562,7 +572,8 @@
String toString() => "String";
DartType computeType(Compiler compiler) {
- return compiler.stringClass.computeType(compiler);
+ JavaScriptBackend backend = compiler.backend;
+ return backend.jsStringClass.computeType(compiler);
}
HType union(HType other, Compiler compiler) {
@@ -594,7 +605,8 @@
String toString() => "readable array";
DartType computeType(Compiler compiler) {
- return compiler.listClass.computeType(compiler);
+ JavaScriptBackend backend = compiler.backend;
+ return backend.jsArrayClass.computeType(compiler);
}
HType union(HType other, Compiler compiler) {
diff --git a/sdk/lib/_internal/compiler/implementation/tree/nodes.dart b/sdk/lib/_internal/compiler/implementation/tree/nodes.dart
index 9875b25..1b3b455 100644
--- a/sdk/lib/_internal/compiler/implementation/tree/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/tree/nodes.dart
@@ -1069,12 +1069,10 @@
}
class VariableDefinitions extends Statement {
- final Token endToken;
final TypeAnnotation type;
final Modifiers modifiers;
final NodeList definitions;
- VariableDefinitions(this.type, this.modifiers, this.definitions,
- this.endToken) {
+ VariableDefinitions(this.type, this.modifiers, this.definitions) {
assert(modifiers != null);
}
@@ -1095,7 +1093,7 @@
return token;
}
- Token getEndToken() => endToken;
+ Token getEndToken() => definitions.getEndToken();
}
abstract class Loop extends Statement {
@@ -1703,11 +1701,11 @@
token.next = prefixToken.next;
prefixNode = new Identifier(token);
}
- return new Import(tag.token, argument, prefixNode, null);
+ return new Import(tag.token, argument, prefixNode, null, null);
} else if (isLibrary()) {
- return new LibraryName(tag.token, argument);
+ return new LibraryName(tag.token, argument, null);
} else if (isSource()) {
- return new Part(tag.token, argument);
+ return new Part(tag.token, argument, null);
} else {
throw 'Unknown script tag ${tag.token.slowToString()}';
}
@@ -1715,6 +1713,10 @@
}
abstract class LibraryTag extends Node {
+ final Link<MetadataAnnotation> metadata;
+
+ LibraryTag(this.metadata);
+
bool get isLibraryName => false;
bool get isImport => false;
bool get isExport => false;
@@ -1727,7 +1729,10 @@
final Token libraryKeyword;
- LibraryName(this.libraryKeyword, this.name);
+ LibraryName(this.libraryKeyword,
+ this.name,
+ Link<MetadataAnnotation> metadata)
+ : super(metadata);
bool get isLibraryName => true;
@@ -1751,7 +1756,10 @@
final StringNode uri;
final NodeList combinators;
- LibraryDependency(this.uri, this.combinators);
+ LibraryDependency(this.uri,
+ this.combinators,
+ Link<MetadataAnnotation> metadata)
+ : super(metadata);
}
/**
@@ -1766,8 +1774,9 @@
final Token importKeyword;
Import(this.importKeyword, StringNode uri,
- this.prefix, NodeList combinators)
- : super(uri, combinators);
+ this.prefix, NodeList combinators,
+ Link<MetadataAnnotation> metadata)
+ : super(uri, combinators, metadata);
bool get isImport => true;
@@ -1802,8 +1811,11 @@
class Export extends LibraryDependency {
final Token exportKeyword;
- Export(this.exportKeyword, StringNode uri, NodeList combinators)
- : super(uri, combinators);
+ Export(this.exportKeyword,
+ StringNode uri,
+ NodeList combinators,
+ Link<MetadataAnnotation> metadata)
+ : super(uri, combinators, metadata);
bool get isExport => true;
@@ -1829,7 +1841,8 @@
final Token partKeyword;
- Part(this.partKeyword, this.uri);
+ Part(this.partKeyword, this.uri, Link<MetadataAnnotation> metadata)
+ : super(metadata);
bool get isPart => true;
@@ -1849,7 +1862,9 @@
final Token partKeyword;
- PartOf(this.partKeyword, this.name);
+ final Link<MetadataAnnotation> metadata;
+
+ PartOf(this.partKeyword, this.name, this.metadata);
Token get ofKeyword => partKeyword.next;
diff --git a/sdk/lib/_internal/compiler/implementation/tree/tree.dart b/sdk/lib/_internal/compiler/implementation/tree/tree.dart
index 316b153..3faa36c 100644
--- a/sdk/lib/_internal/compiler/implementation/tree/tree.dart
+++ b/sdk/lib/_internal/compiler/implementation/tree/tree.dart
@@ -13,6 +13,8 @@
import '../resolution/secret_tree_element.dart' show TreeElementMixin;
+import '../elements/elements.dart' show MetadataAnnotation;
+
part 'dartstring.dart';
part 'nodes.dart';
part 'prettyprint.dart';
diff --git a/sdk/lib/_internal/compiler/implementation/tree/unparser.dart b/sdk/lib/_internal/compiler/implementation/tree/unparser.dart
index eee95d4..9c20f2d 100644
--- a/sdk/lib/_internal/compiler/implementation/tree/unparser.dart
+++ b/sdk/lib/_internal/compiler/implementation/tree/unparser.dart
@@ -123,7 +123,7 @@
add(node.forToken.value);
sb.add('(');
visit(node.initializer);
- if (node.initializer is !Statement) sb.add(';');
+ sb.add(';');
visit(node.conditionStatement);
visit(node.update);
sb.add(')');
@@ -366,9 +366,6 @@
sb.add(' ');
}
visit(node.definitions);
- if (node.endToken.value == const SourceString(';')) {
- add(node.endToken.value);
- }
}
visitDoWhile(DoWhile node) {
diff --git a/sdk/lib/_internal/compiler/implementation/typechecker.dart b/sdk/lib/_internal/compiler/implementation/typechecker.dart
index ed5ac45..01fa607 100644
--- a/sdk/lib/_internal/compiler/implementation/typechecker.dart
+++ b/sdk/lib/_internal/compiler/implementation/typechecker.dart
@@ -258,6 +258,8 @@
return types.dynamicType;
}
+ // TODO(johnniwinther): Provide the element from which the type came in order
+ // to give better error messages.
void analyzeArguments(Send send, DartType type) {
Link<Node> arguments = send.arguments;
if (type == null || identical(type, types.dynamicType)) {
@@ -268,17 +270,50 @@
} else {
FunctionType funType = type;
Link<DartType> parameterTypes = funType.parameterTypes;
- while (!arguments.isEmpty && !parameterTypes.isEmpty) {
- checkAssignable(arguments.head, parameterTypes.head,
- analyze(arguments.head));
+ Link<DartType> optionalParameterTypes = funType.optionalParameterTypes;
+ while (!arguments.isEmpty) {
+ Node argument = arguments.head;
+ NamedArgument namedArgument = argument.asNamedArgument();
+ if (namedArgument != null) {
+ argument = namedArgument.expression;
+ SourceString argumentName = namedArgument.name.source;
+ DartType namedParameterType =
+ funType.getNamedParameterType(argumentName);
+ if (namedParameterType == null) {
+ // TODO(johnniwinther): Provide better information on the called
+ // function.
+ reportTypeWarning(argument, MessageKind.NAMED_ARGUMENT_NOT_FOUND,
+ {'argumentName': argumentName});
+
+ analyze(argument);
+ } else {
+ checkAssignable(argument, namedParameterType, analyze(argument));
+ }
+ } else {
+ if (parameterTypes.isEmpty) {
+ if (optionalParameterTypes.isEmpty) {
+ // TODO(johnniwinther): Provide better information on the
+ // called function.
+ reportTypeWarning(argument, MessageKind.ADDITIONAL_ARGUMENT);
+
+ analyze(argument);
+ } else {
+ checkAssignable(argument, optionalParameterTypes.head,
+ analyze(argument));
+ optionalParameterTypes = optionalParameterTypes.tail;
+ }
+ } else {
+ checkAssignable(argument, parameterTypes.head, analyze(argument));
+ parameterTypes = parameterTypes.tail;
+ }
+ }
arguments = arguments.tail;
- parameterTypes = parameterTypes.tail;
}
- if (!arguments.isEmpty) {
- reportTypeWarning(arguments.head, MessageKind.ADDITIONAL_ARGUMENT);
- } else if (!parameterTypes.isEmpty) {
+ if (!parameterTypes.isEmpty) {
+ // TODO(johnniwinther): Provide better information on the called
+ // function.
reportTypeWarning(send, MessageKind.MISSING_ARGUMENT,
- {'argumentType': parameterTypes.head});
+ {'argumentType': parameterTypes.head});
}
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/universe/function_set.dart b/sdk/lib/_internal/compiler/implementation/universe/function_set.dart
index f55ad50..23bc782 100644
--- a/sdk/lib/_internal/compiler/implementation/universe/function_set.dart
+++ b/sdk/lib/_internal/compiler/implementation/universe/function_set.dart
@@ -67,7 +67,7 @@
Element member = node.membersByName[selector.name];
// Since we're running through the entire tree we have to use
// the applies method that takes types into account.
- if (member != null && selector.applies(member, compiler)) {
+ if (member != null && selector.appliesUnnamed(member, compiler)) {
result.add(member);
}
return true;
@@ -95,7 +95,7 @@
Element member = node.membersByName[selector.name];
// Since we're running through the entire tree we have to use
// the applies method that takes types into account.
- if (member != null && selector.applies(member, compiler)) {
+ if (member != null && selector.appliesUnnamed(member, compiler)) {
result = true;
// End the traversal.
return false;
diff --git a/sdk/lib/_internal/compiler/implementation/universe/selector_map.dart b/sdk/lib/_internal/compiler/implementation/universe/selector_map.dart
index f4a416d..cf98a10 100644
--- a/sdk/lib/_internal/compiler/implementation/universe/selector_map.dart
+++ b/sdk/lib/_internal/compiler/implementation/universe/selector_map.dart
@@ -90,7 +90,7 @@
Selector selector = existing.selector;
// Since we're running through the entire tree we have to use
// the applies method that takes types into account.
- if (selector.applies(member, compiler)) {
+ if (selector.appliesUnnamed(member, compiler)) {
if (!visit(selector, existing.value)) return false;
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/universe/universe.dart b/sdk/lib/_internal/compiler/implementation/universe/universe.dart
index 34954ec..6b64382 100644
--- a/sdk/lib/_internal/compiler/implementation/universe/universe.dart
+++ b/sdk/lib/_internal/compiler/implementation/universe/universe.dart
@@ -35,6 +35,18 @@
final Map<SourceString, Set<Selector>> invokedNames;
final Map<SourceString, Set<Selector>> invokedGetters;
final Map<SourceString, Set<Selector>> invokedSetters;
+
+ /**
+ * Fields accessed. Currently only the codegen knows this
+ * information. The resolver is too conservative when seeing a
+ * getter and only registers an invoked getter.
+ */
+ final Map<SourceString, Set<Selector>> fieldGetters;
+
+ /**
+ * Fields set. See comment in [fieldGetters].
+ */
+ final Map<SourceString, Set<Selector>> fieldSetters;
final Set<DartType> isChecks;
Universe() : instantiatedClasses = new Set<ClassElement>(),
@@ -42,6 +54,8 @@
staticFunctionsNeedingGetter = new Set<FunctionElement>(),
invokedNames = new Map<SourceString, Set<Selector>>(),
invokedGetters = new Map<SourceString, Set<Selector>>(),
+ fieldGetters = new Map<SourceString, Set<Selector>>(),
+ fieldSetters = new Map<SourceString, Set<Selector>>(),
invokedSetters = new Map<SourceString, Set<Selector>>(),
isChecks = new Set<DartType>();
@@ -50,7 +64,7 @@
Compiler compiler) {
if (selectors == null) return false;
for (Selector selector in selectors) {
- if (selector.applies(member, compiler)) return true;
+ if (selector.appliesUnnamed(member, compiler)) return true;
}
return false;
}
@@ -66,46 +80,6 @@
bool hasInvokedSetter(Element member, Compiler compiler) {
return hasMatchingSelector(invokedSetters[member.name], member, compiler);
}
-}
-
-/// [Universe] which is specific to resolution.
-class ResolutionUniverse extends Universe {
-}
-
-/// [Universe] which is specific to code generation.
-class CodegenUniverse extends Universe {
- /**
- * Documentation wanted -- johnniwinther
- *
- * Invariant: Key elements are declaration elements.
- */
- Map<Element, js.Expression> generatedCode;
-
- /**
- * Documentation wanted -- johnniwinther
- *
- * Invariant: Key elements are declaration elements.
- */
- Map<Element, js.Expression> generatedBailoutCode;
-
- final Map<SourceString, Set<Selector>> fieldGetters;
- final Map<SourceString, Set<Selector>> fieldSetters;
-
- CodegenUniverse()
- : generatedCode = new Map<Element, js.Expression>(),
- generatedBailoutCode = new Map<Element, js.Expression>(),
- fieldGetters = new Map<SourceString, Set<Selector>>(),
- fieldSetters = new Map<SourceString, Set<Selector>>();
-
- void addGeneratedCode(CodegenWorkItem work, js.Expression code) {
- assert(invariant(work.element, work.element.isDeclaration));
- generatedCode[work.element] = code;
- }
-
- void addBailoutCode(CodegenWorkItem work, js.Expression code) {
- assert(invariant(work.element, work.element.isDeclaration));
- generatedBailoutCode[work.element] = code;
- }
bool hasFieldGetter(Element member, Compiler compiler) {
return hasMatchingSelector(fieldGetters[member.name], member, compiler);
@@ -236,6 +210,8 @@
int get positionalArgumentCount => argumentCount - namedArgumentCount;
DartType get receiverType => null;
+ Selector get asUntyped => this;
+
/**
* The member name for invocation mirrors created from this selector.
*/
@@ -255,10 +231,13 @@
return kind;
}
- bool applies(Element element, Compiler compiler)
- => appliesUntyped(element, compiler);
+ bool appliesUnnamed(Element element, Compiler compiler) {
+ assert(sameNameHack(element, compiler));
+ return appliesUntyped(element, compiler);
+ }
bool appliesUntyped(Element element, Compiler compiler) {
+ assert(sameNameHack(element, compiler));
if (Elements.isUnresolved(element)) return false;
if (name.isPrivate() && library != element.getLibrary()) return false;
if (element.isForeign(compiler)) return true;
@@ -301,7 +280,27 @@
}
}
+ bool sameNameHack(Element element, Compiler compiler) {
+ // TODO(ngeoffray): Remove workaround checks.
+ return element == compiler.assertMethod
+ || element.isConstructor()
+ || name == element.name;
+ }
+
+ bool applies(Element element, Compiler compiler) {
+ if (!sameNameHack(element, compiler)) return false;
+ return appliesUnnamed(element, compiler);
+ }
+
/**
+ * Fills [list] with the arguments in a defined order.
+ *
+ * [compileArgument] is a function that returns a compiled version
+ * of an argument located in [arguments].
+ *
+ * [compileConstant] is a function that returns a compiled constant
+ * of an optional argument that is not in [arguments.
+ *
* Returns [:true:] if the selector and the [element] match; [:false:]
* otherwise.
*
@@ -415,14 +414,18 @@
*/
final DartType receiverType;
+ final Selector asUntyped;
+
TypedSelector(DartType this.receiverType, Selector selector)
- : super(selector.kind,
- selector.name,
- selector.library,
- selector.argumentCount,
- selector.namedArguments) {
+ : asUntyped = selector.asUntyped,
+ super(selector.kind,
+ selector.name,
+ selector.library,
+ selector.argumentCount,
+ selector.namedArguments) {
// Invariant: Typed selector can not be based on a malformed type.
assert(!identical(receiverType.kind, TypeKind.MALFORMED_TYPE));
+ assert(asUntyped.receiverType == null);
}
/**
@@ -430,12 +433,14 @@
* invoked on an instance of [cls].
*/
bool hasElementIn(ClassElement cls, Element element) {
- Element resolved = cls.lookupMember(element.name);
- if (identical(resolved, element)) return true;
+ // Use the selector for the lookup instead of [:element.name:]
+ // because the selector has the right privacy information.
+ Element resolved = cls.lookupSelector(this);
+ if (resolved == element) return true;
if (resolved == null) return false;
- if (identical(resolved.kind, ElementKind.ABSTRACT_FIELD)) {
+ if (resolved.isAbstractField()) {
AbstractFieldElement field = resolved;
- if (identical(element, field.getter) || identical(element, field.setter)) {
+ if (element == field.getter || element == field.setter) {
return true;
} else {
ClassElement otherCls = field.getEnclosingClass();
@@ -447,7 +452,8 @@
return false;
}
- bool applies(Element element, Compiler compiler) {
+ bool appliesUnnamed(Element element, Compiler compiler) {
+ assert(sameNameHack(element, compiler));
// [TypedSelector] are only used when compiling.
assert(compiler.phase == Compiler.PHASE_COMPILING);
if (!element.isMember()) return false;
diff --git a/sdk/lib/_internal/compiler/implementation/warnings.dart b/sdk/lib/_internal/compiler/implementation/warnings.dart
index 343ad14..56f3698 100644
--- a/sdk/lib/_internal/compiler/implementation/warnings.dart
+++ b/sdk/lib/_internal/compiler/implementation/warnings.dart
@@ -24,6 +24,8 @@
'missing argument of type #{argumentType}');
static const ADDITIONAL_ARGUMENT = const MessageKind(
'additional argument');
+ static const NAMED_ARGUMENT_NOT_FOUND = const MessageKind(
+ "no named argument '#{argumentName}' found on method");
static const METHOD_NOT_FOUND = const MessageKind(
'no method named #{methodName} in class #{className}');
static const MEMBER_NOT_STATIC = const MessageKind(
@@ -360,31 +362,6 @@
File: #{fileName}
Length: #{length}''');
- static const PATCH_RETURN_TYPE_MISMATCH = const MessageKind(
- "Patch return type '#{patchReturnType}' doesn't match "
- "'#{originReturnType}' on origin method '#{methodName}'.");
-
- static const PATCH_REQUIRED_PARAMETER_COUNT_MISMATCH = const MessageKind(
- "Required parameter count of patch method (#{patchParameterCount}) "
- "doesn't match parameter count on origin method '#{methodName}' "
- "(#{originParameterCount}).");
-
- static const PATCH_OPTIONAL_PARAMETER_COUNT_MISMATCH = const MessageKind(
- "Optional parameter count of patch method (#{patchParameterCount}) "
- "doesn't match parameter count on origin method '#{methodName}' "
- "(#{originParameterCount}).");
-
- static const PATCH_OPTIONAL_PARAMETER_NAMED_MISMATCH = const MessageKind(
- "Optional parameters of origin and patch method '#{methodName}' must "
- "both be either named or positional.");
-
- static const PATCH_PARAMETER_MISMATCH = const MessageKind(
- "Patch method parameter '#{patchParameter}' doesn't match "
- "'#{originParameter}' on origin method #{methodName}.");
-
- static const EXTERNAL_WITHOUT_IMPLEMENTATION = const MessageKind(
- "External method without an implementation.");
-
static const TOP_LEVEL_VARIABLE_DECLARED_STATIC = const MessageKind(
"Top-level variable cannot be declared static.");
@@ -424,6 +401,87 @@
below as well as the source location above).
''');
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Patch errors start.
+ //////////////////////////////////////////////////////////////////////////////
+
+ static const PATCH_RETURN_TYPE_MISMATCH = const MessageKind(
+ "Patch return type '#{patchReturnType}' doesn't match "
+ "'#{originReturnType}' on origin method '#{methodName}'.");
+
+ static const PATCH_REQUIRED_PARAMETER_COUNT_MISMATCH = const MessageKind(
+ "Required parameter count of patch method (#{patchParameterCount}) "
+ "doesn't match parameter count on origin method '#{methodName}' "
+ "(#{originParameterCount}).");
+
+ static const PATCH_OPTIONAL_PARAMETER_COUNT_MISMATCH = const MessageKind(
+ "Optional parameter count of patch method (#{patchParameterCount}) "
+ "doesn't match parameter count on origin method '#{methodName}' "
+ "(#{originParameterCount}).");
+
+ static const PATCH_OPTIONAL_PARAMETER_NAMED_MISMATCH = const MessageKind(
+ "Optional parameters of origin and patch method '#{methodName}' must "
+ "both be either named or positional.");
+
+ static const PATCH_PARAMETER_MISMATCH = const MessageKind(
+ "Patch method parameter '#{patchParameter}' doesn't match "
+ "'#{originParameter}' on origin method #{methodName}.");
+
+ static const PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION = const MessageKind(
+ "External method without an implementation.");
+
+ static const PATCH_POINT_TO_FUNCTION = const MessageKind(
+ "Info: This is the function patch '#{functionName}'.");
+
+ static const PATCH_POINT_TO_CLASS = const MessageKind(
+ "Info: This is the class patch '#{className}'.");
+
+ static const PATCH_POINT_TO_GETTER = const MessageKind(
+ "Info: This is the getter patch '#{getterName}'.");
+
+ static const PATCH_POINT_TO_SETTER = const MessageKind(
+ "Info: This is the setter patch '#{setterName}'.");
+
+ static const PATCH_POINT_TO_CONSTRUCTOR = const MessageKind(
+ "Info: This is the constructor patch '#{constructorName}'.");
+
+ static const PATCH_NON_EXISTING = const MessageKind(
+ "Error: Origin does not exist for patch '#{name}'.");
+
+ static const PATCH_NONPATCHABLE = const MessageKind(
+ "Error: Only classes and functions can be patched.");
+
+ static const PATCH_NON_EXTERNAL = const MessageKind(
+ "Error: Only external functions can be patched.");
+
+ static const PATCH_NON_CLASS = const MessageKind(
+ "Error: Patching non-class with class patch '#{className}'.");
+
+ static const PATCH_NON_GETTER = const MessageKind(
+ "Error: Cannot patch non-getter '#{name}' with getter patch.");
+
+ static const PATCH_NO_GETTER = const MessageKind(
+ "Error: No getter found for getter patch '#{getterName}'.");
+
+ static const PATCH_NON_SETTER = const MessageKind(
+ "Error: Cannot patch non-setter '#{name}' with setter patch.");
+
+ static const PATCH_NO_SETTER = const MessageKind(
+ "Error: No setter found for setter patch '#{setterName}'.");
+
+ static const PATCH_NON_CONSTRUCTOR = const MessageKind(
+ "Error: Cannot patch non-constructor with constructor patch "
+ "'#{constructorName}'.");
+
+ static const PATCH_NON_FUNCTION = const MessageKind(
+ "Error: Cannot patch non-function with function patch "
+ "'#{functionName}'.");
+
+ //////////////////////////////////////////////////////////////////////////////
+ // Patch errors end.
+ //////////////////////////////////////////////////////////////////////////////
+
toString() => template;
Message message([Map arguments = const {}]) {
diff --git a/sdk/lib/_internal/dartdoc/lib/dartdoc.dart b/sdk/lib/_internal/dartdoc/lib/dartdoc.dart
index 2520489..e9882ff 100644
--- a/sdk/lib/_internal/dartdoc/lib/dartdoc.dart
+++ b/sdk/lib/_internal/dartdoc/lib/dartdoc.dart
@@ -1465,9 +1465,6 @@
}
}
- DocComment createDocComment(String text, [ClassMirror inheritedFrom]) =>
- new DocComment(text, inheritedFrom);
-
/** Get the doc comment associated with the given library. */
DocComment getLibraryComment(LibraryMirror library) => getComment(library);
@@ -1511,7 +1508,7 @@
}
}
if (comment == null) return null;
- return createDocComment(comment, inheritedFrom);
+ return new DocComment(comment, inheritedFrom);
}
/**
diff --git a/sdk/lib/_internal/dartdoc/lib/src/client/client-live-nav.dart b/sdk/lib/_internal/dartdoc/lib/src/client/client-live-nav.dart
index 194bc5f..a5b04d6 100644
--- a/sdk/lib/_internal/dartdoc/lib/src/client/client-live-nav.dart
+++ b/sdk/lib/_internal/dartdoc/lib/src/client/client-live-nav.dart
@@ -20,8 +20,8 @@
setup();
// Request the navigation data so we can build the HTML for it.
- new HttpRequest.get('${prefix}nav.json', (request) {
- var json = jsonlib.parse(request.responseText);
+ HttpRequest.getString('${prefix}nav.json').then((text) {
+ var json = jsonlib.parse(text);
buildNavigation(json);
setupSearch(json);
});
@@ -54,7 +54,7 @@
// Insert it into the DOM.
final navElement = document.query('.nav');
- navElement.innerHTML = html.toString();
+ navElement.innerHtml = html.toString();
}
/** Writes the navigation for the types contained by [library] to [html]. */
diff --git a/sdk/lib/_internal/dartdoc/lib/src/client/client-shared.dart b/sdk/lib/_internal/dartdoc/lib/src/client/client-shared.dart
index 7348f2e..c90469a 100644
--- a/sdk/lib/_internal/dartdoc/lib/src/client/client-shared.dart
+++ b/sdk/lib/_internal/dartdoc/lib/src/client/client-shared.dart
@@ -48,7 +48,7 @@
var preList = elem.queryAll('pre.source');
- showCode.on.click.add((e) {
+ showCode.onClick.listen((e) {
for (final pre in preList) {
if (pre.classes.contains('expanded')) {
pre.classes.remove('expanded');
@@ -72,7 +72,7 @@
var showInherited = document.query('#show-inherited');
if (showInherited == null) return;
showInherited.dataAttributes.putIfAbsent('show-inherited', () => 'block');
- showInherited.on.click.add((e) {
+ showInherited.onClick.listen((e) {
String display = showInherited.dataAttributes['show-inherited'];
if (display == 'block') {
display = 'none';
diff --git a/sdk/lib/_internal/dartdoc/lib/src/client/dropdown.dart b/sdk/lib/_internal/dartdoc/lib/src/client/dropdown.dart
index 05798b3..b5e877a 100644
--- a/sdk/lib/_internal/dartdoc/lib/src/client/dropdown.dart
+++ b/sdk/lib/_internal/dartdoc/lib/src/client/dropdown.dart
@@ -345,7 +345,7 @@
* Setup window shortcuts.
*/
void setupShortcuts() {
- window.on.keyDown.add(shortcutHandler);
+ window.onKeyDown.listen(shortcutHandler);
}
/** Setup search hooks. */
@@ -354,10 +354,10 @@
searchInput = query('#q');
dropdown = query('#drop-down');
- searchInput.on.keyDown.add(handleUpDown);
- searchInput.on.keyUp.add(updateDropDown);
- searchInput.on.change.add(updateDropDown);
- searchInput.on.reset.add(updateDropDown);
- searchInput.on.focus.add((event) => showDropDown());
- searchInput.on.blur.add((event) => hideDropDown());
+ searchInput.onKeyDown.listen(handleUpDown);
+ searchInput.onKeyUp.listen(updateDropDown);
+ searchInput.onChange.listen(updateDropDown);
+ searchInput.onReset.listen(updateDropDown);
+ searchInput.onFocus.listen((event) => showDropDown());
+ searchInput.onBlur.listen((event) => hideDropDown());
}
\ No newline at end of file
diff --git a/sdk/lib/_internal/dartdoc/lib/src/client/search.dart b/sdk/lib/_internal/dartdoc/lib/src/client/search.dart
index 22f4880..9686755 100644
--- a/sdk/lib/_internal/dartdoc/lib/src/client/search.dart
+++ b/sdk/lib/_internal/dartdoc/lib/src/client/search.dart
@@ -108,9 +108,9 @@
row = table.insertRow(table.rows.length);
row.classes.add('drop-down-link-tr');
- row.on.mouseDown.add((event) => hideDropDownSuspend = true);
- row.on.click.add(clickHandler);
- row.on.mouseUp.add((event) => hideDropDownSuspend = false);
+ row.onMouseDown.listen((event) => hideDropDownSuspend = true);
+ row.onClick.listen(clickHandler);
+ row.onMouseUp.listen((event) => hideDropDownSuspend = false);
var sb = new StringBuffer();
sb.add('<td class="drop-down-link-td">');
sb.add('<table class="drop-down-table"><tr><td colspan="2">');
@@ -146,7 +146,7 @@
sb.add('library $library');
}
sb.add('</td></tr></table></td>');
- row.innerHTML = sb.toString();
+ row.innerHtml = sb.toString();
}
}
diff --git a/sdk/lib/_internal/libraries.dart b/sdk/lib/_internal/libraries.dart
index 98efa98..5c35483 100644
--- a/sdk/lib/_internal/libraries.dart
+++ b/sdk/lib/_internal/libraries.dart
@@ -35,10 +35,6 @@
"collection": const LibraryInfo("collection/collection.dart"),
- "collection-dev": const LibraryInfo(
- "collection_dev/collection_dev.dart",
- documented: false),
-
"core": const LibraryInfo(
"core/core.dart",
dart2jsPatchPath: "_internal/compiler/implementation/lib/core_patch.dart"),
@@ -111,6 +107,11 @@
category: "Client",
dart2jsPath: "web_audio/dart2js/web_audio_dart2js.dart"),
+ "_collection-dev": const LibraryInfo(
+ "_collection_dev/collection_dev.dart",
+ category: "Internal",
+ documented: false),
+
"_js_helper": const LibraryInfo(
"_internal/compiler/implementation/lib/js_helper.dart",
category: "Internal",
diff --git a/sdk/lib/async/async.dart b/sdk/lib/async/async.dart
index 80716fb..8998f83 100644
--- a/sdk/lib/async/async.dart
+++ b/sdk/lib/async/async.dart
@@ -5,6 +5,7 @@
library dart.async;
part 'async_error.dart';
+part 'collection_sink.dart';
part 'future.dart';
part 'future_impl.dart';
part 'stream.dart';
diff --git a/sdk/lib/async/async_sources.gypi b/sdk/lib/async/async_sources.gypi
index fe95d17..549a749 100644
--- a/sdk/lib/async/async_sources.gypi
+++ b/sdk/lib/async/async_sources.gypi
@@ -6,6 +6,7 @@
{
'sources': [
'async_error.dart',
+ 'collection_sink.dart',
'future.dart',
'future_impl.dart',
'stream.dart',
diff --git a/sdk/lib/async/collection_sink.dart b/sdk/lib/async/collection_sink.dart
new file mode 100644
index 0000000..a023fd1
--- /dev/null
+++ b/sdk/lib/async/collection_sink.dart
@@ -0,0 +1,46 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart.async;
+
+typedef void _CollectionSinkCallback<T>(Collection<T> collection);
+typedef void _CollectionSinkErrorCallback(AsyncError error);
+
+/** StreamSink that stores incoming data in a collection. */
+class CollectionSink<T> implements StreamSink<T> {
+ final Collection<T> collection;
+ final _CollectionSinkCallback<T> _callback;
+ final _CollectionSinkErrorCallback _errorCallback;
+ bool _isClosed = false;
+
+ /**
+ * Create a sink that stores incoming values in a collection.
+ *
+ * The [collection] is the collection to add the values to.
+ *
+ * If [callback] is provided, then it's called with the collection as arugment
+ * when the sink's [close] method is called.
+ */
+ CollectionSink(this.collection,
+ { void onClose(Collection<T> collection),
+ void onError(AsyncError error) })
+ : this._callback = onClose,
+ this._errorCallback = onError;
+
+ add(T value) {
+ if (_isClosed) throw new StateError("Adding to closed sink");
+ collection.add(value);
+ }
+
+ void signalError(AsyncError error) {
+ if (_isClosed) throw new StateError("Singalling error on closed sink");
+ if (_errorCallback != null) _errorCallback(error);
+ }
+
+ void close() {
+ if (_isClosed) throw new StateError("Closing closed sink");
+ _isClosed = true;
+ if (_callback != null) _callback(collection);
+ }
+}
diff --git a/sdk/lib/async/future.dart b/sdk/lib/async/future.dart
index 0d32aae..a36ffa1 100644
--- a/sdk/lib/async/future.dart
+++ b/sdk/lib/async/future.dart
@@ -276,17 +276,20 @@
*
* If the call to [action] returns a [Future], `f2`, then completion of
* `f` is delayed until `f2` completes. If `f2` completes with
- * an error, that will be the result of `f` too.
+ * an error, that will be the result of `f` too. The value of `f2` is always
+ * ignored.
*
* This method is equivalent to:
*
* Future<T> whenComplete(action()) {
* this.then((v) {
- * action();
+ * var f2 = action();
+ * if (f2 is Future) return f2.then((_) => v);
* return v
* },
* onError: (AsyncError e) {
- * action();
+ * var f2 = action();
+ * if (f2 is Future) return f2.then((_) { throw e; });
* throw e;
* });
* }
diff --git a/sdk/lib/async/stream.dart b/sdk/lib/async/stream.dart
index afdeaf3..c713d9e 100644
--- a/sdk/lib/async/stream.dart
+++ b/sdk/lib/async/stream.dart
@@ -215,13 +215,13 @@
}
// Deprecated method, previously called 'pipe', retained for compatibility.
- Future pipeInto(Sink<T> sink,
+ Future pipeInto(StreamSink<T> sink,
{void onError(AsyncError error),
bool unsubscribeOnError}) {
_FutureImpl<T> result = new _FutureImpl<T>();
this.listen(
sink.add,
- onError: onError,
+ onError: sink.signalError,
onDone: () {
sink.close();
result._setValue(null);
@@ -847,7 +847,7 @@
/**
* An interface that abstracts sending events into a [Stream].
*/
-abstract class StreamSink<T> implements Sink<T> {
+abstract class StreamSink<T> {
void add(T event);
/** Signal an async error to the receivers of this sink's values. */
void signalError(AsyncError errorEvent);
diff --git a/sdk/lib/async/stream_pipe.dart b/sdk/lib/async/stream_pipe.dart
index 8867ee0..aaa34b0 100644
--- a/sdk/lib/async/stream_pipe.dart
+++ b/sdk/lib/async/stream_pipe.dart
@@ -215,6 +215,8 @@
}
void _handleDone() {
+ // On a done-event, we have already been unsubscribed.
+ _subscription = null;
_stream._handleDone(this);
}
}
diff --git a/sdk/lib/collection/collection.dart b/sdk/lib/collection/collection.dart
index d63b8be..b1a8353 100644
--- a/sdk/lib/collection/collection.dart
+++ b/sdk/lib/collection/collection.dart
@@ -4,7 +4,7 @@
library dart.collection;
-import 'dart:collection-dev';
+import 'dart:_collection-dev';
part 'arrays.dart';
part 'collections.dart';
diff --git a/sdk/lib/collection/collections.dart b/sdk/lib/collection/collections.dart
index 369a3d3..81dd6da 100644
--- a/sdk/lib/collection/collections.dart
+++ b/sdk/lib/collection/collections.dart
@@ -326,6 +326,10 @@
return new MappedList(list, f);
}
+ static Iterable expand(Iterable iterable, Iterable f(var element)) {
+ return new ExpandIterable(iterable, f);
+ }
+
static Iterable takeList(List list, int n) {
// The generic type is currently lost. It will be fixed with mixins.
// This is currently a List as well as an Iterable.
@@ -365,107 +369,131 @@
*/
class Collections {
/** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+ @deprecated
static bool contains(Iterable iterable, var element)
=> IterableMixinWorkaround.contains(iterable, element);
/** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+ @deprecated
static void forEach(Iterable iterable, void f(o)) {
IterableMixinWorkaround.forEach(iterable, f);
}
/** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+ @deprecated
static bool any(Iterable iterable, bool f(o))
=> IterableMixinWorkaround.any(iterable, f);
/** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+ @deprecated
static bool every(Iterable iterable, bool f(o))
=> IterableMixinWorkaround.every(iterable, f);
/** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+ @deprecated
static dynamic reduce(Iterable iterable,
dynamic initialValue,
dynamic combine(dynamic previousValue, element))
=> IterableMixinWorkaround.reduce(iterable, initialValue, combine);
/** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+ @deprecated
static bool isEmpty(Iterable iterable)
=> IterableMixinWorkaround.isEmpty(iterable);
/** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+ @deprecated
static dynamic first(Iterable iterable)
=> IterableMixinWorkaround.first(iterable);
/** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+ @deprecated
static dynamic last(Iterable iterable)
=> IterableMixinWorkaround.last(iterable);
/** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+ @deprecated
static dynamic min(Iterable iterable, [int compare(var a, var b)])
=> IterableMixinWorkaround.min(iterable, compare);
/** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+ @deprecated
static dynamic max(Iterable iterable, [int compare(var a, var b)])
=> IterableMixinWorkaround.max(iterable, compare);
/** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+ @deprecated
static dynamic single(Iterable iterable)
=> IterableMixinWorkaround.single(iterable);
/** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+ @deprecated
static dynamic firstMatching(Iterable iterable,
bool test(dynamic value),
dynamic orElse())
=> IterableMixinWorkaround.firstMatching(iterable, test, orElse);
/** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+ @deprecated
static dynamic lastMatching(Iterable iterable,
bool test(dynamic value),
dynamic orElse())
=> IterableMixinWorkaround.lastMatching(iterable, test, orElse);
/** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+ @deprecated
static dynamic lastMatchingInList(List list,
bool test(dynamic value),
dynamic orElse())
=> IterableMixinWorkaround.lastMatchingInList(list, test, orElse);
/** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+ @deprecated
static dynamic singleMatching(Iterable iterable, bool test(dynamic value))
=> IterableMixinWorkaround.singleMatching(iterable, test);
/** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+ @deprecated
static dynamic elementAt(Iterable iterable, int index)
=> IterableMixinWorkaround.elementAt(iterable, index);
/** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+ @deprecated
static String join(Iterable iterable, [String separator])
=> IterableMixinWorkaround.join(iterable, separator);
/** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+ @deprecated
static String joinList(List list, [String separator])
=> IterableMixinWorkaround.joinList(list, separator);
/** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+ @deprecated
static Iterable where(Iterable iterable, bool f(var element))
=> IterableMixinWorkaround.where(iterable, f);
/** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+ @deprecated
static List mappedByList(List list, f(var element))
=> IterableMixinWorkaround.mappedByList(list, f);
/** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+ @deprecated
static Iterable takeList(List list, int n)
=> IterableMixinWorkaround.takeList(list, n);
/** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+ @deprecated
static Iterable takeWhile(Iterable iterable, bool test(var value))
=> IterableMixinWorkaround.takeWhile(iterable, test);
/** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+ @deprecated
static Iterable skipList(List list, int n)
=> IterableMixinWorkaround.skipList(list, n);
/** Deprecated. Use the same method in [IterableMixinWorkaround] instead.*/
+ @deprecated
static Iterable skipWhile(Iterable iterable, bool test(var value))
=> IterableMixinWorkaround.skipWhile(iterable, test);
diff --git a/sdk/lib/core/core.dart b/sdk/lib/core/core.dart
index 1d4e4b0..1c307253 100644
--- a/sdk/lib/core/core.dart
+++ b/sdk/lib/core/core.dart
@@ -5,7 +5,7 @@
library dart.core;
import "dart:collection";
-import "dart:collection-dev";
+import "dart:_collection-dev";
part "bool.dart";
part "collection.dart";
@@ -32,7 +32,6 @@
part "print.dart";
part "regexp.dart";
part "set.dart";
-part "sink.dart";
part "stopwatch.dart";
part "string.dart";
part "string_buffer.dart";
diff --git a/sdk/lib/core/corelib_sources.gypi b/sdk/lib/core/corelib_sources.gypi
index 0506c5d..a3d2202 100644
--- a/sdk/lib/core/corelib_sources.gypi
+++ b/sdk/lib/core/corelib_sources.gypi
@@ -29,7 +29,6 @@
'print.dart',
'regexp.dart',
'set.dart',
- 'sink.dart',
'stopwatch.dart',
'string.dart',
'strings.dart',
diff --git a/sdk/lib/core/date_time.dart b/sdk/lib/core/date_time.dart
index fadf0cc..cbeeccd 100644
--- a/sdk/lib/core/date_time.dart
+++ b/sdk/lib/core/date_time.dart
@@ -7,6 +7,7 @@
/**
* Deprecated class. Please use [DateTime] instead.
*/
+@deprecated
abstract class Date implements Comparable {
// Weekday constants that are returned by [weekday] method:
static const int MON = 1;
diff --git a/sdk/lib/core/exceptions.dart b/sdk/lib/core/exceptions.dart
index 7a6d332..8ee78bc 100644
--- a/sdk/lib/core/exceptions.dart
+++ b/sdk/lib/core/exceptions.dart
@@ -53,12 +53,13 @@
String toString() => "FormatException: $message";
}
-
-class IllegalJSRegExpException implements Exception {
- const IllegalJSRegExpException(String this._pattern, String this._errmsg);
- String toString() => "IllegalJSRegExpException: '$_pattern' '$_errmsg'";
- final String _pattern;
- final String _errmsg;
+/**
+ * Deprecated. Replaced by [FormatException].
+ */
+@deprecated
+class IllegalJSRegExpException extends FormatException {
+ IllegalJSRegExpException(String pattern, String errmsg)
+ : super("Illegal pattern: $pattern, $errmsg");
}
diff --git a/sdk/lib/core/expect.dart b/sdk/lib/core/expect.dart
index 68b765f..bf9053a 100644
--- a/sdk/lib/core/expect.dart
+++ b/sdk/lib/core/expect.dart
@@ -5,16 +5,20 @@
part of dart.core;
/**
+ * This class is *deprecated*.
+ *
* Expect is used for tests that do not want to make use of the
* Dart unit test library - for example, the core language tests.
* Third parties are discouraged from using this, and should use
* the expect() function in the unit test library instead for
* test assertions.
*/
+@deprecated
class Expect {
/**
* Checks whether the expected and actual values are equal (using `==`).
*/
+ @deprecated
static void equals(var expected, var actual, [String reason = null]) {
if (expected == actual) return;
String msg = _getMessage(reason);
@@ -24,6 +28,7 @@
/**
* Checks whether the actual value is a bool and its value is true.
*/
+ @deprecated
static void isTrue(var actual, [String reason = null]) {
if (_identical(actual, true)) return;
String msg = _getMessage(reason);
@@ -33,6 +38,7 @@
/**
* Checks whether the actual value is a bool and its value is false.
*/
+ @deprecated
static void isFalse(var actual, [String reason = null]) {
if (_identical(actual, false)) return;
String msg = _getMessage(reason);
@@ -42,6 +48,7 @@
/**
* Checks whether [actual] is null.
*/
+ @deprecated
static void isNull(actual, [String reason = null]) {
if (null == actual) return;
String msg = _getMessage(reason);
@@ -51,6 +58,7 @@
/**
* Checks whether [actual] is not null.
*/
+ @deprecated
static void isNotNull(actual, [String reason = null]) {
if (null != actual) return;
String msg = _getMessage(reason);
@@ -61,6 +69,7 @@
* Checks whether the expected and actual values are identical
* (using `identical`).
*/
+ @deprecated
static void identical(var expected, var actual, [String reason = null]) {
if (_identical(expected, actual)) return;
String msg = _getMessage(reason);
@@ -69,6 +78,7 @@
}
// Unconditional failure.
+ @deprecated
static void fail(String msg) {
_fail("Expect.fail('$msg')");
}
@@ -78,6 +88,7 @@
* given tolerance. If no tolerance is given, tolerance is assumed to be the
* value 4 significant digits smaller than the value given for expected.
*/
+ @deprecated
static void approxEquals(num expected,
num actual,
[num tolerance = null,
@@ -93,6 +104,7 @@
'tolerance:<$tolerance>$msg) fails');
}
+ @deprecated
static void notEquals(unexpected, actual, [String reason = null]) {
if (unexpected != actual) return;
String msg = _getMessage(reason);
@@ -106,6 +118,7 @@
* used by the standard list implementation. It should also produce nicer
* error messages than just calling `Expect.equals(expected, actual)`.
*/
+ @deprecated
static void listEquals(List expected, List actual, [String reason = null]) {
String msg = _getMessage(reason);
int n = (expected.length < actual.length) ? expected.length : actual.length;
@@ -130,6 +143,7 @@
* the semantics of [Map.containsKey] to determine what "same" means. For
* each key, checks that the values in both maps are equal using `==`.
*/
+ @deprecated
static void mapEquals(Map expected, Map actual, [String reason = null]) {
String msg = _getMessage(reason);
@@ -154,6 +168,7 @@
* Specialized equality test for strings. When the strings don't match,
* this method shows where the mismatch starts and ends.
*/
+ @deprecated
static void stringEquals(String expected,
String actual,
[String reason = null]) {
@@ -222,6 +237,7 @@
* Checks that every element of [expected] is also in [actual], and that
* every element of [actual] is also in [expected].
*/
+ @deprecated
static void setEquals(Iterable expected,
Iterable actual,
[String reason = null]) {
@@ -262,6 +278,7 @@
*
* Expect.throws(myThrowingFunction, (e) => e is MyException);
*/
+ @deprecated
static void throws(void f(),
[_CheckExceptionFn check = null,
String reason = null]) {
@@ -292,6 +309,7 @@
typedef bool _CheckExceptionFn(exception);
+@deprecated
class ExpectException implements Exception {
ExpectException(this.message);
String toString() => message;
diff --git a/sdk/lib/core/iterable.dart b/sdk/lib/core/iterable.dart
index 160e773..fc1a647 100644
--- a/sdk/lib/core/iterable.dart
+++ b/sdk/lib/core/iterable.dart
@@ -52,23 +52,35 @@
/**
* Deprecated alias for [map].
- *
- * @deprecated
*/
+ @deprecated
Iterable mappedBy(f(E element)) => map(f);
/**
- * Returns a lazy [Iterable] with all elements that satisfy the
- * predicate [f].
- *
- * This method returns a view of the mapped elements. As long as the
- * returned [Iterable] is not iterated over, the supplied function [f] will
- * not be invoked. Iterating will not cache results, and thus iterating
- * multiple times over the the returned [Iterable] will invoke the supplied
- * function [f] multiple times on the same element.
- */
+ * Returns a lazy [Iterable] with all elements that satisfy the
+ * predicate [f].
+ *
+ * This method returns a view of the mapped elements. As long as the
+ * returned [Iterable] is not iterated over, the supplied function [f] will
+ * not be invoked. Iterating will not cache results, and thus iterating
+ * multiple times over the the returned [Iterable] will invoke the supplied
+ * function [f] multiple times on the same element.
+ */
Iterable<E> where(bool f(E element)) => new WhereIterable<E>(this, f);
+
+ /**
+ * Expand each element of this [Iterable] into zero or more elements.
+ *
+ * The resulting Iterable will run through the elements returned
+ * by [f] for each element of this, in order.
+ *
+ * The returned [Iterable] is lazy, and will call [f] for each element
+ * of this every time it's iterated.
+ */
+ Iterable expand(Iterable f(E element)) =>
+ new ExpandIterable<E, dynamic>(this, f);
+
/**
* Check whether the collection contains an element equal to [element].
*/
diff --git a/sdk/lib/core/sink.dart b/sdk/lib/core/sink.dart
deleted file mode 100644
index d0dafc0..0000000
--- a/sdk/lib/core/sink.dart
+++ /dev/null
@@ -1,49 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-part of dart.core;
-/**
- * An interface for an object that can receive a sequence of values.
- */
-abstract class Sink<T> {
- /** Write a value to the sink. */
- add(T value);
- /** Tell the sink that no further values will be written. */
- void close();
-}
-
-// ----------------------------------------------------------------------
-// Collections/Sink interoperability
-// ----------------------------------------------------------------------
-
-typedef void _CollectionSinkCallback<T>(Collection<T> collection);
-
-/** Sink that stores incoming data in a collection. */
-class CollectionSink<T> implements Sink<T> {
- final Collection<T> collection;
- final _CollectionSinkCallback<T> callback;
- bool _isClosed = false;
-
- /**
- * Create a sink that stores incoming values in a collection.
- *
- * The [collection] is the collection to add the values to.
- *
- * If [callback] is provided, then it's called with the collection as arugment
- * when the sink's [close] method is called.
- */
- CollectionSink(this.collection, [void callback(Collection<T> collection)])
- : this.callback = callback;
-
- add(T value) {
- if (_isClosed) throw new StateError("Adding to closed sink");
- collection.add(value);
- }
-
- void close() {
- if (_isClosed) throw new StateError("Closing closed sink");
- _isClosed = true;
- if (callback != null) callback(collection);
- }
-}
diff --git a/sdk/lib/core/stopwatch.dart b/sdk/lib/core/stopwatch.dart
index 7d8ce33..5564801 100644
--- a/sdk/lib/core/stopwatch.dart
+++ b/sdk/lib/core/stopwatch.dart
@@ -7,65 +7,7 @@
/**
* A simple [Stopwatch] interface to measure elapsed time.
*/
-abstract class Stopwatch {
- /**
- * Creates a [Stopwatch] in stopped state with a zero elapsed count.
- *
- * The following example shows how to start a [Stopwatch]
- * right after allocation.
- *
- * Stopwatch stopwatch = new Stopwatch()..start();
- */
- factory Stopwatch() => new _StopwatchImpl();
-
- /**
- * Starts the [Stopwatch]. The [elapsed] count is increasing monotonically.
- * If the [Stopwatch] has been stopped, then calling start again restarts it
- * without resetting the [elapsed] count.
- * If the [Stopwatch] is currently running, then calling start does nothing.
- */
- void start();
-
- /**
- * Stops the [Stopwatch]. The [elapsed] count stops increasing.
- * If the [Stopwatch] is currently not running, then calling stop does
- * nothing.
- */
- void stop();
-
- /**
- * Resets the [elapsed] count to zero. This method does not stop or start
- * the [Stopwatch].
- */
- void reset();
-
- /**
- * Returns the elapsed number of clock ticks since calling [start] while the
- * [Stopwatch] is running.
- * Returns the elapsed number of clock ticks between calling [start] and
- * calling [stop].
- * Returns 0 if the [Stopwatch] has never been started.
- * The elapsed number of clock ticks increases by [frequency] every second.
- */
- int get elapsedTicks;
-
- /**
- * Returns the [elapsedTicks] counter converted to microseconds.
- */
- int get elapsedMicroseconds;
-
- /**
- * Returns the [elapsedTicks] counter converted to milliseconds.
- */
- int get elapsedMilliseconds;
-
- /**
- * Returns the frequency of the elapsed counter in Hz.
- */
- int get frequency;
-}
-
-class _StopwatchImpl implements Stopwatch {
+class Stopwatch {
// The _start and _stop fields capture the time when [start] and [stop]
// are called respectively.
// If _start is null, then the [Stopwatch] has not been started yet.
@@ -74,30 +16,49 @@
int _start;
int _stop;
- _StopwatchImpl() : _start = null, _stop = null {}
+ /**
+ * Creates a [Stopwatch] in stopped state with a zero elapsed count.
+ *
+ * The following example shows how to start a [Stopwatch]
+ * right after allocation.
+ *
+ * Stopwatch stopwatch = new Stopwatch()..start();
+ */
+ Stopwatch() : _start = null, _stop = null {}
+ /**
+ * Starts the [Stopwatch]. The [elapsed] count is increasing monotonically.
+ * If the [Stopwatch] has been stopped, then calling start again restarts it
+ * without resetting the [elapsed] count.
+ * If the [Stopwatch] is currently running, then calling start does nothing.
+ */
void start() {
+ if (isRunning) return;
if (_start == null) {
// This stopwatch has never been started.
_start = _now();
} else {
- if (_stop == null) {
- return;
- }
- // Restarting this stopwatch. Prepend the elapsed time to the current
+ // Restart this stopwatch. Prepend the elapsed time to the current
// start time.
_start = _now() - (_stop - _start);
_stop = null;
}
}
+ /**
+ * Stops the [Stopwatch]. The [elapsed] count stops increasing.
+ * If the [Stopwatch] is currently not running, then calling stop does
+ * nothing.
+ */
void stop() {
- if (_start == null || _stop != null) {
- return;
- }
+ if (!isRunning) return;
_stop = _now();
}
+ /**
+ * Resets the [elapsed] count to zero. This method does not stop or start
+ * the [Stopwatch].
+ */
void reset() {
if (_start == null) return;
// If [_start] is not null, then the stopwatch had already been started. It
@@ -110,6 +71,14 @@
}
}
+ /**
+ * Returns the elapsed number of clock ticks since calling [start] while the
+ * [Stopwatch] is running.
+ * Returns the elapsed number of clock ticks between calling [start] and
+ * calling [stop].
+ * Returns 0 if the [Stopwatch] has never been started.
+ * The elapsed number of clock ticks increases by [frequency] every second.
+ */
int get elapsedTicks {
if (_start == null) {
return 0;
@@ -117,16 +86,30 @@
return (_stop == null) ? (_now() - _start) : (_stop - _start);
}
+ /**
+ * Returns the [elapsedTicks] counter converted to microseconds.
+ */
int get elapsedMicroseconds {
return (elapsedTicks * 1000000) ~/ frequency;
}
+ /**
+ * Returns the [elapsedTicks] counter converted to milliseconds.
+ */
int get elapsedMilliseconds {
return (elapsedTicks * 1000) ~/ frequency;
}
+ /**
+ * Returns the frequency of the elapsed counter in Hz.
+ */
int get frequency => _frequency();
+ /**
+ * Returns wether the [StopWatch] is currently running.
+ */
+ bool get isRunning => _start != null && _stop == null;
+
external static int _frequency();
external static int _now();
}
diff --git a/sdk/lib/core/string.dart b/sdk/lib/core/string.dart
index 247bdef..6fb1b90 100644
--- a/sdk/lib/core/string.dart
+++ b/sdk/lib/core/string.dart
@@ -30,6 +30,7 @@
/**
* *Deprecated*. Use [String.fromCharCode] instead.
*/
+ @deprecated
factory String.character(int charCode) => new String.fromCharCode(charCode);
/**
@@ -75,6 +76,7 @@
*
* *This method is deprecated. Please use [codeUnitAt] instead.*
*/
+ @deprecated
int charCodeAt(int index);
/**
@@ -237,6 +239,7 @@
* Iterable<String> characters =
* string.runes.map((c) => new String.fromCharCode(c));
*/
+ @deprecated
List<String> splitChars();
/**
diff --git a/sdk/lib/core/strings.dart b/sdk/lib/core/strings.dart
index 412e23f..c8a2afc 100644
--- a/sdk/lib/core/strings.dart
+++ b/sdk/lib/core/strings.dart
@@ -4,12 +4,14 @@
part of dart.core;
+@deprecated
abstract class Strings {
/**
* Joins all the given strings to create a new string.
*
* *Deprecated* Use `strings.join(separator)` instead.
*/
+ @deprecated
external static String join(Iterable<String> strings, String separator);
/**
@@ -17,5 +19,6 @@
*
* *Deprecated* Use `strings.join()` instead.
*/
+ @deprecated
external static String concatAll(Iterable<String> strings);
}
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 6e2a270..321b381 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -1413,6 +1413,10 @@
@DocsEditable
bool isPointInPath(num x, num y, [String winding]) native;
+ @DomName('CanvasRenderingContext2D.isPointInStroke')
+ @DocsEditable
+ bool isPointInStroke(num x, num y) native;
+
@DomName('CanvasRenderingContext2D.lineTo')
@DocsEditable
void lineTo(num x, num y) native;
@@ -1592,10 +1596,6 @@
@DocsEditable
void insertData(int offset, String data) native;
- @DomName('CharacterData.remove')
- @DocsEditable
- void remove() native;
-
@DomName('CharacterData.replaceData')
@DocsEditable
void replaceData(int offset, int length, String data) native;
@@ -2342,6 +2342,8 @@
static const int UNKNOWN_RULE = 0;
+ static const int WEBKIT_FILTER_RULE = 17;
+
static const int WEBKIT_KEYFRAMES_RULE = 7;
static const int WEBKIT_KEYFRAME_RULE = 8;
@@ -7098,7 +7100,7 @@
// BSD-style license that can be found in the LICENSE file.
-/// @domName DOMException
+@DomName('DOMException')
class DomException native "*DOMException" {
static const String INDEX_SIZE = 'IndexSizeError';
@@ -7249,6 +7251,9 @@
Iterable<DomMimeType> where(bool f(DomMimeType element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(DomMimeType element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(DomMimeType element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(DomMimeType element)) => IterableMixinWorkaround.any(this, f);
@@ -7503,6 +7508,9 @@
Iterable<DomPlugin> where(bool f(DomPlugin element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(DomPlugin element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(DomPlugin element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(DomPlugin element)) => IterableMixinWorkaround.any(this, f);
@@ -7864,6 +7872,9 @@
Iterable<String> where(bool f(String element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(String element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(String element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(String element)) => IterableMixinWorkaround.any(this, f);
@@ -8126,6 +8137,10 @@
return IterableMixinWorkaround.where(this, f);
}
+ Iterable expand(Iterable f(Element element)) {
+ return IterableMixinWorkaround.expand(this, f);
+ }
+
bool get isEmpty {
return _element.$dom_firstElementChild == null;
}
@@ -8343,6 +8358,10 @@
return IterableMixinWorkaround.where(this, f);
}
+ Iterable expand(Iterable f(Element element)) {
+ return IterableMixinWorkaround.expand(this, f);
+ }
+
bool every(bool f(Element element)) {
for(Element element in this) {
if (!f(element)) {
@@ -10785,6 +10804,9 @@
Iterable<File> where(bool f(File element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(File element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(File element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(File element)) => IterableMixinWorkaround.any(this, f);
@@ -11400,6 +11422,9 @@
Iterable<num> where(bool f(num element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(num element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(num element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(num element)) => IterableMixinWorkaround.any(this, f);
@@ -11616,6 +11641,9 @@
Iterable<num> where(bool f(num element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(num element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(num element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(num element)) => IterableMixinWorkaround.any(this, f);
@@ -12131,6 +12159,9 @@
Iterable<Node> where(bool f(Node element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(Node element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(Node element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(Node element)) => IterableMixinWorkaround.any(this, f);
@@ -12338,6 +12369,9 @@
Iterable<Node> where(bool f(Node element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(Node element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(Node element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(Node element)) => IterableMixinWorkaround.any(this, f);
@@ -12730,6 +12764,11 @@
* * The `Access-Control-Allow-Credentials` header of `url` must be set to true.
* * If `Access-Control-Expose-Headers` has not been set to true, only a subset of all the response headers will be returned when calling [getAllRequestHeaders].
*
+ * Note that requests for file:// URIs are only supported by Chrome extensions
+ * with appropriate permissions in their manifest. Requests to file:// URIs
+ * will also never fail- the Future will always complete successfully, even
+ * when the file cannot be found.
+ *
* See also: [authorization headers](http://en.wikipedia.org/wiki/Basic_access_authentication).
*/
static Future<HttpRequest> request(String url,
@@ -12756,8 +12795,9 @@
}
xhr.onLoad.listen((e) {
- if (xhr.status >= 200 && xhr.status < 300 ||
- xhr.status == 304 ) {
+ // Note: file:// URIs have status of 0.
+ if ((xhr.status >= 200 && xhr.status < 300) ||
+ xhr.status == 0 || xhr.status == 304) {
completer.complete(xhr);
} else {
completer.completeError(e);
@@ -14374,6 +14414,9 @@
Iterable<int> where(bool f(int element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(int element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(int element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(int element)) => IterableMixinWorkaround.any(this, f);
@@ -14590,6 +14633,9 @@
Iterable<int> where(bool f(int element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(int element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(int element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(int element)) => IterableMixinWorkaround.any(this, f);
@@ -14806,6 +14852,9 @@
Iterable<int> where(bool f(int element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(int element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(int element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(int element)) => IterableMixinWorkaround.any(this, f);
@@ -16155,8 +16204,7 @@
// BSD-style license that can be found in the LICENSE file.
-/// @domName MediaStream; @docsEditable true@DomName('MediaStream')
-
+@DomName('MediaStream')
class MediaStream extends EventTarget native "*MediaStream" {
@DomName('MediaStream.endedEvent')
@@ -17121,6 +17169,9 @@
Iterable<Node> where(bool f(Node element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(Node element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(Node element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(Node element)) => IterableMixinWorkaround.any(this, f);
@@ -17594,6 +17645,10 @@
return IterableMixinWorkaround.where(this, f);
}
+ Iterable expand(Iterable f(Node element)) {
+ return IterableMixinWorkaround.expand(this, f);
+ }
+
bool every(bool f(Node element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(Node element)) => IterableMixinWorkaround.any(this, f);
@@ -17983,6 +18038,9 @@
Iterable<Node> where(bool f(Node element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(Node element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(Node element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(Node element)) => IterableMixinWorkaround.any(this, f);
@@ -18588,7 +18646,7 @@
@DomName('HTMLOutputElement.htmlFor')
@DocsEditable
- DomSettableTokenList htmlFor;
+ final DomSettableTokenList htmlFor;
@DomName('HTMLOutputElement.labels')
@DocsEditable
@@ -20366,6 +20424,9 @@
Iterable<SourceBuffer> where(bool f(SourceBuffer element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(SourceBuffer element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(SourceBuffer element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(SourceBuffer element)) => IterableMixinWorkaround.any(this, f);
@@ -20646,6 +20707,9 @@
Iterable<SpeechGrammar> where(bool f(SpeechGrammar element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(SpeechGrammar element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(SpeechGrammar element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(SpeechGrammar element)) => IterableMixinWorkaround.any(this, f);
@@ -21260,6 +21324,9 @@
Iterable<Map> where(bool f(Map element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(Map element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(Map element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(Map element)) => IterableMixinWorkaround.any(this, f);
@@ -22375,6 +22442,9 @@
Iterable<TextTrackCue> where(bool f(TextTrackCue element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(TextTrackCue element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(TextTrackCue element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(TextTrackCue element)) => IterableMixinWorkaround.any(this, f);
@@ -22586,6 +22656,9 @@
Iterable<TextTrack> where(bool f(TextTrack element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(TextTrack element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(TextTrack element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(TextTrack element)) => IterableMixinWorkaround.any(this, f);
@@ -22992,6 +23065,9 @@
Iterable<Touch> where(bool f(Touch element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(Touch element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(Touch element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(Touch element)) => IterableMixinWorkaround.any(this, f);
@@ -23215,16 +23291,20 @@
@DocsEditable
-@DomName('WebKitTransitionEvent')
-class TransitionEvent extends Event native "*WebKitTransitionEvent" {
+@DomName('TransitionEvent')
+class TransitionEvent extends Event native "*TransitionEvent" {
- @DomName('WebKitTransitionEvent.elapsedTime')
+ @DomName('TransitionEvent.elapsedTime')
@DocsEditable
final num elapsedTime;
- @DomName('WebKitTransitionEvent.propertyName')
+ @DomName('TransitionEvent.propertyName')
@DocsEditable
final String propertyName;
+
+ @DomName('TransitionEvent.pseudoElement')
+ @DocsEditable
+ final String pseudoElement;
}
// 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
@@ -23434,6 +23514,9 @@
Iterable<int> where(bool f(int element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(int element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(int element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(int element)) => IterableMixinWorkaround.any(this, f);
@@ -23650,6 +23733,9 @@
Iterable<int> where(bool f(int element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(int element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(int element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(int element)) => IterableMixinWorkaround.any(this, f);
@@ -23866,6 +23952,9 @@
Iterable<int> where(bool f(int element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(int element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(int element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(int element)) => IterableMixinWorkaround.any(this, f);
@@ -24079,6 +24168,9 @@
Iterable<int> where(bool f(int element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(int element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(int element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(int element)) => IterableMixinWorkaround.any(this, f);
@@ -25860,6 +25952,19 @@
@DocsEditable
+@DomName('WebKitCSSFilterRule')
+class WebKitCssFilterRule extends CssRule native "*WebKitCSSFilterRule" {
+
+ @DomName('WebKitCSSFilterRule.style')
+ @DocsEditable
+ final CssStyleDeclaration style;
+}
+// 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('WebKitCSSFilterValue')
class WebKitCssFilterValue extends _CssValueList native "*WebKitCSSFilterValue" {
@@ -25959,6 +26064,27 @@
@DocsEditable
+@DomName('WebKitTransitionEvent')
+class WebKitTransitionEvent extends Event native "*WebKitTransitionEvent" {
+
+ @DomName('WebKitTransitionEvent.elapsedTime')
+ @DocsEditable
+ final num elapsedTime;
+
+ @DomName('WebKitTransitionEvent.propertyName')
+ @DocsEditable
+ final String propertyName;
+
+ @DomName('WebKitTransitionEvent.pseudoElement')
+ @DocsEditable
+ final String pseudoElement;
+}
+// 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
/**
* Use the WebSocket interface to connect to a WebSocket,
* and to send and receive data on that WebSocket.
@@ -27966,6 +28092,9 @@
Iterable<ClientRect> where(bool f(ClientRect element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(ClientRect element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(ClientRect element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(ClientRect element)) => IterableMixinWorkaround.any(this, f);
@@ -28163,6 +28292,9 @@
Iterable<CssRule> where(bool f(CssRule element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(CssRule element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(CssRule element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(CssRule element)) => IterableMixinWorkaround.any(this, f);
@@ -28360,6 +28492,9 @@
Iterable<CssValue> where(bool f(CssValue element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(CssValue element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(CssValue element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(CssValue element)) => IterableMixinWorkaround.any(this, f);
@@ -28557,6 +28692,9 @@
Iterable<Entry> where(bool f(Entry element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(Entry element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(Entry element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(Entry element)) => IterableMixinWorkaround.any(this, f);
@@ -28754,6 +28892,9 @@
Iterable<EntrySync> where(bool f(EntrySync element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(EntrySync element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(EntrySync element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(EntrySync element)) => IterableMixinWorkaround.any(this, f);
@@ -28951,6 +29092,9 @@
Iterable<Gamepad> where(bool f(Gamepad element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(Gamepad element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(Gamepad element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(Gamepad element)) => IterableMixinWorkaround.any(this, f);
@@ -29263,6 +29407,9 @@
Iterable<MediaStream> where(bool f(MediaStream element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(MediaStream element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(MediaStream element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(MediaStream element)) => IterableMixinWorkaround.any(this, f);
@@ -29460,6 +29607,9 @@
Iterable<SpeechInputResult> where(bool f(SpeechInputResult element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(SpeechInputResult element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(SpeechInputResult element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(SpeechInputResult element)) => IterableMixinWorkaround.any(this, f);
@@ -29657,6 +29807,9 @@
Iterable<SpeechRecognitionResult> where(bool f(SpeechRecognitionResult element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(SpeechRecognitionResult element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(SpeechRecognitionResult element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(SpeechRecognitionResult element)) => IterableMixinWorkaround.any(this, f);
@@ -29854,6 +30007,9 @@
Iterable<StyleSheet> where(bool f(StyleSheet element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(StyleSheet element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(StyleSheet element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(StyleSheet element)) => IterableMixinWorkaround.any(this, f);
@@ -30402,13 +30558,15 @@
Iterable<String> where(bool f(String element)) => readClasses().where(f);
+ Iterable expand(Iterable f(String element)) => readClasses.expand(f);
+
bool every(bool f(String element)) => readClasses().every(f);
bool any(bool f(String element)) => readClasses().any(f);
bool get isEmpty => readClasses().isEmpty;
- int get length =>readClasses().length;
+ int get length => readClasses().length;
dynamic reduce(dynamic initialValue,
dynamic combine(dynamic previousValue, String element)) {
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index 8884e11..50b3922a 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -1816,6 +1816,10 @@
@DocsEditable
bool _isPointInPath_2(x, y) native "CanvasRenderingContext2D__isPointInPath_2_Callback";
+ @DomName('CanvasRenderingContext2D.isPointInStroke')
+ @DocsEditable
+ bool isPointInStroke(num x, num y) native "CanvasRenderingContext2D_isPointInStroke_Callback";
+
@DomName('CanvasRenderingContext2D.lineTo')
@DocsEditable
void lineTo(num x, num y) native "CanvasRenderingContext2D_lineTo_Callback";
@@ -2023,10 +2027,6 @@
@DocsEditable
void insertData(int offset, String data) native "CharacterData_insertData_Callback";
- @DomName('CharacterData.remove')
- @DocsEditable
- void remove() native "CharacterData_remove_Callback";
-
@DomName('CharacterData.replaceData')
@DocsEditable
void replaceData(int offset, int length, String data) native "CharacterData_replaceData_Callback";
@@ -2946,6 +2946,8 @@
static const int UNKNOWN_RULE = 0;
+ static const int WEBKIT_FILTER_RULE = 17;
+
static const int WEBKIT_KEYFRAMES_RULE = 7;
static const int WEBKIT_KEYFRAME_RULE = 8;
@@ -7847,7 +7849,7 @@
// BSD-style license that can be found in the LICENSE file.
-/// @domName DOMException
+@DomName('DOMException')
class DomException extends NativeFieldWrapperClass1 {
static const String INDEX_SIZE = 'IndexSizeError';
@@ -8002,6 +8004,9 @@
Iterable<DomMimeType> where(bool f(DomMimeType element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(DomMimeType element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(DomMimeType element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(DomMimeType element)) => IterableMixinWorkaround.any(this, f);
@@ -8270,6 +8275,9 @@
Iterable<DomPlugin> where(bool f(DomPlugin element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(DomPlugin element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(DomPlugin element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(DomPlugin element)) => IterableMixinWorkaround.any(this, f);
@@ -8656,6 +8664,9 @@
Iterable<String> where(bool f(String element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(String element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(String element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(String element)) => IterableMixinWorkaround.any(this, f);
@@ -8939,6 +8950,10 @@
return IterableMixinWorkaround.where(this, f);
}
+ Iterable expand(Iterable f(Element element)) {
+ return IterableMixinWorkaround.expand(this, f);
+ }
+
bool get isEmpty {
return _element.$dom_firstElementChild == null;
}
@@ -9156,6 +9171,10 @@
return IterableMixinWorkaround.where(this, f);
}
+ Iterable expand(Iterable f(Element element)) {
+ return IterableMixinWorkaround.expand(this, f);
+ }
+
bool every(bool f(Element element)) {
for(Element element in this) {
if (!f(element)) {
@@ -11566,6 +11585,9 @@
Iterable<File> where(bool f(File element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(File element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(File element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(File element)) => IterableMixinWorkaround.any(this, f);
@@ -12235,6 +12257,9 @@
Iterable<num> where(bool f(num element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(num element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(num element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(num element)) => IterableMixinWorkaround.any(this, f);
@@ -12470,6 +12495,9 @@
Iterable<num> where(bool f(num element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(num element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(num element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(num element)) => IterableMixinWorkaround.any(this, f);
@@ -13055,6 +13083,9 @@
Iterable<Node> where(bool f(Node element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(Node element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(Node element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(Node element)) => IterableMixinWorkaround.any(this, f);
@@ -13264,6 +13295,9 @@
Iterable<Node> where(bool f(Node element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(Node element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(Node element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(Node element)) => IterableMixinWorkaround.any(this, f);
@@ -13673,6 +13707,11 @@
* * The `Access-Control-Allow-Credentials` header of `url` must be set to true.
* * If `Access-Control-Expose-Headers` has not been set to true, only a subset of all the response headers will be returned when calling [getAllRequestHeaders].
*
+ * Note that requests for file:// URIs are only supported by Chrome extensions
+ * with appropriate permissions in their manifest. Requests to file:// URIs
+ * will also never fail- the Future will always complete successfully, even
+ * when the file cannot be found.
+ *
* See also: [authorization headers](http://en.wikipedia.org/wiki/Basic_access_authentication).
*/
static Future<HttpRequest> request(String url,
@@ -13699,8 +13738,9 @@
}
xhr.onLoad.listen((e) {
- if (xhr.status >= 200 && xhr.status < 300 ||
- xhr.status == 304 ) {
+ // Note: file:// URIs have status of 0.
+ if ((xhr.status >= 200 && xhr.status < 300) ||
+ xhr.status == 0 || xhr.status == 304) {
completer.complete(xhr);
} else {
completer.completeError(e);
@@ -15636,6 +15676,9 @@
Iterable<int> where(bool f(int element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(int element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(int element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(int element)) => IterableMixinWorkaround.any(this, f);
@@ -15871,6 +15914,9 @@
Iterable<int> where(bool f(int element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(int element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(int element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(int element)) => IterableMixinWorkaround.any(this, f);
@@ -16106,6 +16152,9 @@
Iterable<int> where(bool f(int element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(int element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(int element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(int element)) => IterableMixinWorkaround.any(this, f);
@@ -17748,8 +17797,7 @@
// BSD-style license that can be found in the LICENSE file.
-/// @domName MediaStream; @docsEditable true@DomName('MediaStream')
-
+@DomName('MediaStream')
class MediaStream extends EventTarget {
MediaStream.internal() : super.internal();
@@ -18725,6 +18773,9 @@
Iterable<Node> where(bool f(Node element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(Node element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(Node element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(Node element)) => IterableMixinWorkaround.any(this, f);
@@ -19195,6 +19246,10 @@
return IterableMixinWorkaround.where(this, f);
}
+ Iterable expand(Iterable f(Node element)) {
+ return IterableMixinWorkaround.expand(this, f);
+ }
+
bool every(bool f(Node element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(Node element)) => IterableMixinWorkaround.any(this, f);
@@ -19581,6 +19636,9 @@
Iterable<Node> where(bool f(Node element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(Node element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(Node element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(Node element)) => IterableMixinWorkaround.any(this, f);
@@ -20296,10 +20354,6 @@
@DocsEditable
DomSettableTokenList get htmlFor native "HTMLOutputElement_htmlFor_Getter";
- @DomName('HTMLOutputElement.htmlFor')
- @DocsEditable
- void set htmlFor(DomSettableTokenList value) native "HTMLOutputElement_htmlFor_Setter";
-
@DomName('HTMLOutputElement.labels')
@DocsEditable
List<Node> get labels native "HTMLOutputElement_labels_Getter";
@@ -22290,6 +22344,9 @@
Iterable<SourceBuffer> where(bool f(SourceBuffer element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(SourceBuffer element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(SourceBuffer element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(SourceBuffer element)) => IterableMixinWorkaround.any(this, f);
@@ -22608,6 +22665,9 @@
Iterable<SpeechGrammar> where(bool f(SpeechGrammar element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(SpeechGrammar element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(SpeechGrammar element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(SpeechGrammar element)) => IterableMixinWorkaround.any(this, f);
@@ -23309,6 +23369,9 @@
Iterable<Map> where(bool f(Map element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(Map element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(Map element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(Map element)) => IterableMixinWorkaround.any(this, f);
@@ -24663,6 +24726,9 @@
Iterable<TextTrackCue> where(bool f(TextTrackCue element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(TextTrackCue element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(TextTrackCue element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(TextTrackCue element)) => IterableMixinWorkaround.any(this, f);
@@ -24878,6 +24944,9 @@
Iterable<TextTrack> where(bool f(TextTrack element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(TextTrack element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(TextTrack element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(TextTrack element)) => IterableMixinWorkaround.any(this, f);
@@ -25292,6 +25361,9 @@
Iterable<Touch> where(bool f(Touch element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(Touch element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(Touch element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(Touch element)) => IterableMixinWorkaround.any(this, f);
@@ -25544,17 +25616,21 @@
@DocsEditable
-@DomName('WebKitTransitionEvent')
+@DomName('TransitionEvent')
class TransitionEvent extends Event {
TransitionEvent.internal() : super.internal();
- @DomName('WebKitTransitionEvent.elapsedTime')
+ @DomName('TransitionEvent.elapsedTime')
@DocsEditable
- num get elapsedTime native "WebKitTransitionEvent_elapsedTime_Getter";
+ num get elapsedTime native "TransitionEvent_elapsedTime_Getter";
- @DomName('WebKitTransitionEvent.propertyName')
+ @DomName('TransitionEvent.propertyName')
@DocsEditable
- String get propertyName native "WebKitTransitionEvent_propertyName_Getter";
+ String get propertyName native "TransitionEvent_propertyName_Getter";
+
+ @DomName('TransitionEvent.pseudoElement')
+ @DocsEditable
+ String get pseudoElement native "TransitionEvent_pseudoElement_Getter";
}
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
@@ -25779,6 +25855,9 @@
Iterable<int> where(bool f(int element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(int element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(int element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(int element)) => IterableMixinWorkaround.any(this, f);
@@ -26014,6 +26093,9 @@
Iterable<int> where(bool f(int element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(int element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(int element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(int element)) => IterableMixinWorkaround.any(this, f);
@@ -26249,6 +26331,9 @@
Iterable<int> where(bool f(int element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(int element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(int element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(int element)) => IterableMixinWorkaround.any(this, f);
@@ -26482,6 +26567,9 @@
Iterable<int> where(bool f(int element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(int element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(int element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(int element)) => IterableMixinWorkaround.any(this, f);
@@ -28458,6 +28546,23 @@
@DocsEditable
+@DomName('WebKitCSSFilterRule')
+class WebKitCssFilterRule extends CssRule {
+ WebKitCssFilterRule.internal() : super.internal();
+
+ @DomName('WebKitCSSFilterRule.style')
+ @DocsEditable
+ CssStyleDeclaration get style native "WebKitCSSFilterRule_style_Getter";
+
+}
+// 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('WebKitCSSFilterValue')
class WebKitCssFilterValue extends _CssValueList {
WebKitCssFilterValue.internal() : super.internal();
@@ -28561,6 +28666,31 @@
@DocsEditable
+@DomName('WebKitTransitionEvent')
+class WebKitTransitionEvent extends Event {
+ WebKitTransitionEvent.internal() : super.internal();
+
+ @DomName('WebKitTransitionEvent.elapsedTime')
+ @DocsEditable
+ num get elapsedTime native "WebKitTransitionEvent_elapsedTime_Getter";
+
+ @DomName('WebKitTransitionEvent.propertyName')
+ @DocsEditable
+ String get propertyName native "WebKitTransitionEvent_propertyName_Getter";
+
+ @DomName('WebKitTransitionEvent.pseudoElement')
+ @DocsEditable
+ String get pseudoElement native "WebKitTransitionEvent_pseudoElement_Getter";
+
+}
+// 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
/**
* Use the WebSocket interface to connect to a WebSocket,
* and to send and receive data on that WebSocket.
@@ -30371,6 +30501,9 @@
Iterable<ClientRect> where(bool f(ClientRect element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(ClientRect element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(ClientRect element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(ClientRect element)) => IterableMixinWorkaround.any(this, f);
@@ -30572,6 +30705,9 @@
Iterable<CssRule> where(bool f(CssRule element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(CssRule element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(CssRule element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(CssRule element)) => IterableMixinWorkaround.any(this, f);
@@ -30773,6 +30909,9 @@
Iterable<CssValue> where(bool f(CssValue element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(CssValue element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(CssValue element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(CssValue element)) => IterableMixinWorkaround.any(this, f);
@@ -31111,6 +31250,9 @@
Iterable<Entry> where(bool f(Entry element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(Entry element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(Entry element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(Entry element)) => IterableMixinWorkaround.any(this, f);
@@ -31312,6 +31454,9 @@
Iterable<EntrySync> where(bool f(EntrySync element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(EntrySync element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(EntrySync element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(EntrySync element)) => IterableMixinWorkaround.any(this, f);
@@ -31513,6 +31658,9 @@
Iterable<Gamepad> where(bool f(Gamepad element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(Gamepad element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(Gamepad element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(Gamepad element)) => IterableMixinWorkaround.any(this, f);
@@ -31857,6 +32005,9 @@
Iterable<MediaStream> where(bool f(MediaStream element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(MediaStream element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(MediaStream element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(MediaStream element)) => IterableMixinWorkaround.any(this, f);
@@ -32058,6 +32209,9 @@
Iterable<SpeechInputResult> where(bool f(SpeechInputResult element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(SpeechInputResult element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(SpeechInputResult element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(SpeechInputResult element)) => IterableMixinWorkaround.any(this, f);
@@ -32259,6 +32413,9 @@
Iterable<SpeechRecognitionResult> where(bool f(SpeechRecognitionResult element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(SpeechRecognitionResult element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(SpeechRecognitionResult element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(SpeechRecognitionResult element)) => IterableMixinWorkaround.any(this, f);
@@ -32460,6 +32617,9 @@
Iterable<StyleSheet> where(bool f(StyleSheet element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(StyleSheet element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(StyleSheet element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(StyleSheet element)) => IterableMixinWorkaround.any(this, f);
@@ -33009,13 +33169,15 @@
Iterable<String> where(bool f(String element)) => readClasses().where(f);
+ Iterable expand(Iterable f(String element)) => readClasses.expand(f);
+
bool every(bool f(String element)) => readClasses().every(f);
bool any(bool f(String element)) => readClasses().any(f);
bool get isEmpty => readClasses().isEmpty;
- int get length =>readClasses().length;
+ int get length => readClasses().length;
dynamic reduce(dynamic initialValue,
dynamic combine(dynamic previousValue, String element)) {
diff --git a/sdk/lib/html/html_common/filtered_element_list.dart b/sdk/lib/html/html_common/filtered_element_list.dart
index a16d42c..330b0df 100644
--- a/sdk/lib/html/html_common/filtered_element_list.dart
+++ b/sdk/lib/html/html_common/filtered_element_list.dart
@@ -104,6 +104,7 @@
Iterable map(f(Element element)) => _filtered.map(f);
List mappedBy(f(Element element)) => _filtered.mappedBy(f);
Iterable<Element> where(bool f(Element element)) => _filtered.where(f);
+ Iterable expand(Iterable f(Element element)) => _filtered.expand(f);
Element removeAt(int index) {
final result = this[index];
diff --git a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
index fdc5c72..6390ff3 100644
--- a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
+++ b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
@@ -234,7 +234,7 @@
@DomName('IDBDatabase.versionchangeEvent')
@DocsEditable
- static const EventStreamProvider<UpgradeNeededEvent> versionChangeEvent = const EventStreamProvider<UpgradeNeededEvent>('versionchange');
+ static const EventStreamProvider<VersionChangeEvent> versionChangeEvent = const EventStreamProvider<VersionChangeEvent>('versionchange');
@DocsEditable
@DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
@@ -304,7 +304,7 @@
@DomName('IDBDatabase.onversionchange')
@DocsEditable
- Stream<UpgradeNeededEvent> get onVersionChange => versionChangeEvent.forTarget(this);
+ Stream<VersionChangeEvent> get onVersionChange => versionChangeEvent.forTarget(this);
}
@DocsEditable
@@ -350,7 +350,7 @@
@DomName('IDBFactory.deleteDatabase')
@DocsEditable
- VersionChangeRequest deleteDatabase(String name) native;
+ OpenDBRequest deleteDatabase(String name) native;
@DomName('IDBFactory.open')
@DocsEditable
@@ -867,61 +867,15 @@
@DocsEditable
@DomName('IDBVersionChangeEvent')
-class UpgradeNeededEvent extends Event native "*IDBVersionChangeEvent" {
-
- @DomName('IDBUpgradeNeededEvent.newVersion')
- @DocsEditable
- final int newVersion;
-
- @DomName('IDBUpgradeNeededEvent.oldVersion')
- @DocsEditable
- final int oldVersion;
-}
-// 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('IDBVersionChangeEvent')
class VersionChangeEvent extends Event native "*IDBVersionChangeEvent" {
- @DomName('IDBVersionChangeEvent.version')
+ @DomName('IDBVersionChangeEvent.newVersion')
@DocsEditable
- final String version;
-}
-// 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.
+ final dynamic newVersion;
-
-@DocsEditable
-@DomName('IDBVersionChangeRequest')
-class VersionChangeRequest extends Request implements EventTarget native "*IDBVersionChangeRequest" {
-
- @DomName('IDBVersionChangeRequest.blockedEvent')
+ @DomName('IDBVersionChangeEvent.oldVersion')
@DocsEditable
- static const EventStreamProvider<Event> blockedEvent = const EventStreamProvider<Event>('blocked');
-
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- VersionChangeRequestEvents get on =>
- new VersionChangeRequestEvents(this);
-
- @DomName('IDBVersionChangeRequest.onblocked')
- @DocsEditable
- Stream<Event> get onBlocked => blockedEvent.forTarget(this);
-}
-
-@DocsEditable
-@deprecated
-class VersionChangeRequestEvents extends RequestEvents {
- @DocsEditable
- VersionChangeRequestEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get blocked => this['blocked'];
+ final dynamic oldVersion;
}
// 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
diff --git a/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart b/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
index 44cdb37..b044500 100644
--- a/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
+++ b/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
@@ -134,7 +134,7 @@
@DomName('IDBDatabase.versionchangeEvent')
@DocsEditable
- static const EventStreamProvider<UpgradeNeededEvent> versionChangeEvent = const EventStreamProvider<UpgradeNeededEvent>('versionchange');
+ static const EventStreamProvider<VersionChangeEvent> versionChangeEvent = const EventStreamProvider<VersionChangeEvent>('versionchange');
@DocsEditable
@DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
@@ -213,7 +213,7 @@
@DomName('IDBDatabase.onversionchange')
@DocsEditable
- Stream<UpgradeNeededEvent> get onVersionChange => versionChangeEvent.forTarget(this);
+ Stream<VersionChangeEvent> get onVersionChange => versionChangeEvent.forTarget(this);
}
@@ -258,7 +258,7 @@
@DomName('IDBFactory.deleteDatabase')
@DocsEditable
- VersionChangeRequest deleteDatabase(String name) native "IDBFactory_deleteDatabase_Callback";
+ OpenDBRequest deleteDatabase(String name) native "IDBFactory_deleteDatabase_Callback";
OpenDBRequest open(String name, [int version]) {
if (?version) {
@@ -981,71 +981,17 @@
@DocsEditable
@DomName('IDBVersionChangeEvent')
-class UpgradeNeededEvent extends Event {
- UpgradeNeededEvent.internal() : super.internal();
-
- @DomName('IDBUpgradeNeededEvent.newVersion')
- @DocsEditable
- int get newVersion native "IDBUpgradeNeededEvent_newVersion_Getter";
-
- @DomName('IDBUpgradeNeededEvent.oldVersion')
- @DocsEditable
- int get oldVersion native "IDBUpgradeNeededEvent_oldVersion_Getter";
-
-}
-// 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('IDBVersionChangeEvent')
class VersionChangeEvent extends Event {
VersionChangeEvent.internal() : super.internal();
- @DomName('IDBVersionChangeEvent.version')
+ @DomName('IDBVersionChangeEvent.newVersion')
@DocsEditable
- String get version native "IDBVersionChangeEvent_version_Getter";
+ dynamic get newVersion native "IDBVersionChangeEvent_newVersion_Getter";
-}
-// 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('IDBVersionChangeRequest')
-class VersionChangeRequest extends Request implements EventTarget {
- VersionChangeRequest.internal() : super.internal();
-
- @DomName('IDBVersionChangeRequest.blockedEvent')
+ @DomName('IDBVersionChangeEvent.oldVersion')
@DocsEditable
- static const EventStreamProvider<Event> blockedEvent = const EventStreamProvider<Event>('blocked');
+ dynamic get oldVersion native "IDBVersionChangeEvent_oldVersion_Getter";
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- VersionChangeRequestEvents get on =>
- new VersionChangeRequestEvents(this);
-
- @DomName('IDBVersionChangeRequest.onblocked')
- @DocsEditable
- Stream<Event> get onBlocked => blockedEvent.forTarget(this);
-
-}
-
-@DocsEditable
-@deprecated
-class VersionChangeRequestEvents extends RequestEvents {
- @DocsEditable
- VersionChangeRequestEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get blocked => this['blocked'];
}
// 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
diff --git a/sdk/lib/io/http_impl.dart b/sdk/lib/io/http_impl.dart
index 993cbee..efa341c 100644
--- a/sdk/lib/io/http_impl.dart
+++ b/sdk/lib/io/http_impl.dart
@@ -401,6 +401,7 @@
int _streamReadInto(List<int> buffer, int offset, int len) {
List<int> data = _buffer.readBytes(len);
buffer.setRange(offset, data.length, data);
+ return data.length;
}
void _streamSetErrorHandler(callback(e)) {
diff --git a/sdk/lib/svg/dart2js/svg_dart2js.dart b/sdk/lib/svg/dart2js/svg_dart2js.dart
index 092dc7c..9f47721 100644
--- a/sdk/lib/svg/dart2js/svg_dart2js.dart
+++ b/sdk/lib/svg/dart2js/svg_dart2js.dart
@@ -3217,6 +3217,9 @@
Iterable<Length> where(bool f(Length element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(Length element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(Length element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(Length element)) => IterableMixinWorkaround.any(this, f);
@@ -3841,6 +3844,9 @@
Iterable<Number> where(bool f(Number element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(Number element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(Number element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(Number element)) => IterableMixinWorkaround.any(this, f);
@@ -4741,6 +4747,9 @@
Iterable<PathSeg> where(bool f(PathSeg element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(PathSeg element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(PathSeg element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(PathSeg element)) => IterableMixinWorkaround.any(this, f);
@@ -5625,6 +5634,9 @@
Iterable<String> where(bool f(String element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(String element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(String element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(String element)) => IterableMixinWorkaround.any(this, f);
@@ -6788,6 +6800,9 @@
Iterable<Transform> where(bool f(Transform element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(Transform element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(Transform element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(Transform element)) => IterableMixinWorkaround.any(this, f);
@@ -7305,6 +7320,9 @@
Iterable<ElementInstance> where(bool f(ElementInstance element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(ElementInstance element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(ElementInstance element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(ElementInstance element)) => IterableMixinWorkaround.any(this, f);
diff --git a/sdk/lib/svg/dartium/svg_dartium.dart b/sdk/lib/svg/dartium/svg_dartium.dart
index 12ead7f..70fbe36 100644
--- a/sdk/lib/svg/dartium/svg_dartium.dart
+++ b/sdk/lib/svg/dartium/svg_dartium.dart
@@ -3481,6 +3481,9 @@
Iterable<Length> where(bool f(Length element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(Length element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(Length element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(Length element)) => IterableMixinWorkaround.any(this, f);
@@ -4182,6 +4185,9 @@
Iterable<Number> where(bool f(Number element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(Number element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(Number element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(Number element)) => IterableMixinWorkaround.any(this, f);
@@ -5359,6 +5365,9 @@
Iterable<PathSeg> where(bool f(PathSeg element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(PathSeg element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(PathSeg element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(PathSeg element)) => IterableMixinWorkaround.any(this, f);
@@ -6341,6 +6350,9 @@
Iterable<String> where(bool f(String element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(String element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(String element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(String element)) => IterableMixinWorkaround.any(this, f);
@@ -7593,6 +7605,9 @@
Iterable<Transform> where(bool f(Transform element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(Transform element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(Transform element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(Transform element)) => IterableMixinWorkaround.any(this, f);
@@ -8164,6 +8179,9 @@
Iterable<ElementInstance> where(bool f(ElementInstance element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f(ElementInstance element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f(ElementInstance element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(ElementInstance element)) => IterableMixinWorkaround.any(this, f);
diff --git a/tests/compiler/dart2js/compiler_helper.dart b/tests/compiler/dart2js/compiler_helper.dart
index 668ac80..57ef07d 100644
--- a/tests/compiler/dart2js/compiler_helper.dart
+++ b/tests/compiler/dart2js/compiler_helper.dart
@@ -16,6 +16,8 @@
import "../../../sdk/lib/_internal/compiler/implementation/ssa/ssa.dart" as ssa;
import "../../../sdk/lib/_internal/compiler/implementation/util/util.dart";
import '../../../sdk/lib/_internal/compiler/implementation/source_file.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart'
+ show Compiler;
import "mock_compiler.dart";
import "parser_helper.dart";
@@ -34,6 +36,7 @@
compiler.parseScript(code);
lego.Element element = compiler.mainApp.find(buildSourceString(entry));
if (element == null) return null;
+ compiler.phase = Compiler.PHASE_RESOLVING;
compiler.backend.enqueueHelpers(compiler.enqueuer.resolution);
compiler.processQueue(compiler.enqueuer.resolution, element);
var context = new js.JavaScriptItemCompilationContext();
@@ -42,19 +45,24 @@
resolutionWork.run(compiler, compiler.enqueuer.resolution);
leg.CodegenWorkItem work =
new leg.CodegenWorkItem(element, resolutionWork.resolutionTree, context);
+ compiler.phase = Compiler.PHASE_COMPILING;
work.run(compiler, compiler.enqueuer.codegen);
- return compiler.enqueuer.codegen.assembleCode(element);
+ js.JavaScriptBackend backend = compiler.backend;
+ return backend.assembleCode(element);
}
-MockCompiler compilerFor(String code, Uri uri, {bool analyzeAll: false}) {
- MockCompiler compiler = new MockCompiler(analyzeAll: analyzeAll);
+MockCompiler compilerFor(String code, Uri uri,
+ {bool analyzeAll: false,
+ String coreSource: DEFAULT_CORELIB}) {
+ MockCompiler compiler = new MockCompiler(
+ analyzeAll: analyzeAll, coreSource: coreSource);
compiler.sourceFiles[uri.toString()] = new SourceFile(uri.toString(), code);
return compiler;
}
-String compileAll(String code) {
+String compileAll(String code, {String coreSource: DEFAULT_CORELIB}) {
Uri uri = new Uri.fromComponents(scheme: 'source');
- MockCompiler compiler = compilerFor(code, uri);
+ MockCompiler compiler = compilerFor(code, uri, coreSource: coreSource);
compiler.runCompiler(uri);
Expect.isFalse(compiler.compilationFailed,
'Unexpected compilation error');
diff --git a/tests/compiler/dart2js/interceptor_test.dart b/tests/compiler/dart2js/interceptor_test.dart
index c7be7c5..3a346e1 100644
--- a/tests/compiler/dart2js/interceptor_test.dart
+++ b/tests/compiler/dart2js/interceptor_test.dart
@@ -22,6 +22,16 @@
}
""";
+const String TEST_THREE = r"""
+ class A {
+ var length;
+ }
+ foo(a) {
+ print([]); // Make sure the array class is instantiated.
+ return new A().length + a.length;
+ }
+""";
+
main() {
var generated = compile(TEST_ONE, entry: 'foo');
// Check that the one shot interceptor got converted to a direct
@@ -33,4 +43,12 @@
generated = compile(TEST_TWO, entry: 'foo');
Expect.isTrue(generated.contains('\$.\$\$add(a, 42)'));
Expect.isTrue(generated.contains('myVariableName'));
+
+ // Check that an intercepted getter that does not need to be
+ // intercepted, is turned into a regular getter call or field
+ // access.
+ generated = compile(TEST_THREE, entry: 'foo');
+ Expect.isFalse(generated.contains(r'get$length'));
+ Expect.isTrue(generated.contains(r'$.A$().length'));
+ Expect.isTrue(generated.contains(r'length(a)'));
}
diff --git a/tests/compiler/dart2js/literal_map_test.dart b/tests/compiler/dart2js/literal_map_test.dart
new file mode 100644
index 0000000..88be94d
--- /dev/null
+++ b/tests/compiler/dart2js/literal_map_test.dart
@@ -0,0 +1,22 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "compiler_helper.dart";
+
+const String TEST = """
+foo() {
+ var a = {};
+ var index = foo(); // Make sure we want to optimize this method.
+ while (true) a[index] = 1;
+}
+""";
+
+main() {
+ String generated = compile(TEST, entry: 'foo');
+ // Make sure we have all the type information we need.
+ Expect.isFalse(generated.contains('bailout'));
+ Expect.isFalse(generated.contains('interceptor'));
+ // Make sure we don't go through an interceptor.
+ Expect.isTrue(generated.contains('a.\$indexSet'));
+}
diff --git a/tests/compiler/dart2js/metadata_test.dart b/tests/compiler/dart2js/metadata_test.dart
index 79a0595..1591ebc 100644
--- a/tests/compiler/dart2js/metadata_test.dart
+++ b/tests/compiler/dart2js/metadata_test.dart
@@ -9,6 +9,22 @@
import '../../../sdk/lib/_internal/compiler/implementation/elements/elements.dart';
import '../../../sdk/lib/_internal/compiler/implementation/dart2jslib.dart';
+import '../../../sdk/lib/_internal/compiler/implementation/util/util.dart'
+ show Spannable, Link;
+import '../../../sdk/lib/_internal/compiler/implementation/tree/tree.dart'
+ show Node, LibraryTag;
+
+void checkPosition(Spannable spannable, Node node, String source, compiler) {
+ SourceSpan span = compiler.spanFromSpannable(spannable);
+ Expect.isTrue(span.begin < span.end,
+ 'begin = ${span.begin}; end = ${span.end}');
+ Expect.isTrue(span.end < source.length,
+ 'end = ${span.end}; length = ${source.length}');
+ String yield = source.substring(span.begin, span.end);
+
+ // TODO(ahe): The node does not include "@". Fix that.
+ Expect.stringEquals('@$node', yield);
+}
void checkAnnotation(String name, String declaration,
{bool isTopLevelOnly: false}) {
@@ -24,10 +40,12 @@
compileAndCheck(source, name, (compiler, element) {
compiler.enqueuer.resolution.queueIsClosed = false;
Expect.equals(1, length(element.metadata));
- MetadataAnnotation annotation = element.metadata.head;
+ PartialMetadataAnnotation annotation = element.metadata.head;
annotation.ensureResolved(compiler);
Constant value = annotation.value;
Expect.stringEquals('xyz', value.value.slowToString());
+
+ checkPosition(annotation, annotation.cachedNode, source, compiler);
});
// Ensure that each repeated annotation has a unique instance of
@@ -40,8 +58,8 @@
compileAndCheck(source, name, (compiler, element) {
compiler.enqueuer.resolution.queueIsClosed = false;
Expect.equals(2, length(element.metadata));
- MetadataAnnotation annotation1 = element.metadata.head;
- MetadataAnnotation annotation2 = element.metadata.tail.head;
+ PartialMetadataAnnotation annotation1 = element.metadata.head;
+ PartialMetadataAnnotation annotation2 = element.metadata.tail.head;
annotation1.ensureResolved(compiler);
annotation2.ensureResolved(compiler);
Expect.isFalse(identical(annotation1, annotation2),
@@ -52,6 +70,9 @@
Expect.identical(value1, value2, 'expected same compile-time constant');
Expect.stringEquals('xyz', value1.value.slowToString());
Expect.stringEquals('xyz', value2.value.slowToString());
+
+ checkPosition(annotation1, annotation1.cachedNode, source, compiler);
+ checkPosition(annotation2, annotation2.cachedNode, source, compiler);
});
if (isTopLevelOnly) return;
@@ -72,10 +93,12 @@
Expect.equals(0, length(element.metadata));
element = element.lookupLocalMember(buildSourceString(name));
Expect.equals(1, length(element.metadata));
- MetadataAnnotation annotation = element.metadata.head;
+ PartialMetadataAnnotation annotation = element.metadata.head;
annotation.ensureResolved(compiler);
Constant value = annotation.value;
Expect.stringEquals('xyz', value.value.slowToString());
+
+ checkPosition(annotation, annotation.cachedNode, source, compiler);
});
// Ensure that each repeated annotation has a unique instance of
@@ -94,8 +117,8 @@
Expect.equals(0, length(element.metadata));
element = element.lookupLocalMember(buildSourceString(name));
Expect.equals(2, length(element.metadata));
- MetadataAnnotation annotation1 = element.metadata.head;
- MetadataAnnotation annotation2 = element.metadata.tail.head;
+ PartialMetadataAnnotation annotation1 = element.metadata.head;
+ PartialMetadataAnnotation annotation2 = element.metadata.tail.head;
annotation1.ensureResolved(compiler);
annotation2.ensureResolved(compiler);
Expect.isFalse(identical(annotation1, annotation2),
@@ -106,6 +129,9 @@
Expect.identical(value1, value2, 'expected same compile-time constant');
Expect.stringEquals('xyz', value1.value.slowToString());
Expect.stringEquals('xyz', value2.value.slowToString());
+
+ checkPosition(annotation1, annotation1.cachedNode, source, compiler);
+ checkPosition(annotation1, annotation2.cachedNode, source, compiler);
});
}
@@ -121,8 +147,74 @@
checkAnnotation('foo', 'var foo;');
}
+void testLibraryTags() {
+ void compileAndCheckLibrary(
+ String source,
+ Link<MetadataAnnotation> extractMetadata(LibraryElement element)) {
+ Uri partUri = new Uri.fromComponents(scheme: 'source', path: 'part.dart');
+ String partSource = '@native part of foo;';
+
+ Uri libUri = new Uri.fromComponents(scheme: 'source', path: 'lib.dart');
+ String libSource = 'library lib;';
+
+ Uri uri = new Uri.fromComponents(scheme: 'source', path: 'main.dart');
+
+ var compiler = compilerFor(source, uri)
+ ..registerSource(partUri, partSource)
+ ..registerSource(libUri, libSource)
+ ..runCompiler(uri);
+ compiler.enqueuer.resolution.queueIsClosed = false;
+ LibraryElement element = compiler.libraries['$uri'];
+ Expect.isNotNull(element, 'Cannot find $uri');
+
+ Link<MetadataAnnotation> metadata = extractMetadata(element);
+ Expect.equals(1, length(metadata));
+
+ PartialMetadataAnnotation annotation = metadata.head;
+ annotation.ensureResolved(compiler);
+ Constant value = annotation.value;
+ Expect.stringEquals('xyz', value.value.slowToString());
+
+ checkPosition(annotation, annotation.cachedNode, source, compiler);
+ }
+
+ var source;
+
+ source = """@native
+ library foo;
+ const native = 'xyz';
+ main() {}""";
+ compileAndCheckLibrary(source, (e) => e.libraryTag.metadata);
+
+ source = """@native
+ import 'lib.dart';
+ const native = 'xyz';
+ main() {}""";
+ compileAndCheckLibrary(source, (e) => e.tags.single.metadata);
+
+ source = """@native
+ export 'lib.dart';
+ const native = 'xyz';
+ main() {}""";
+ compileAndCheckLibrary(source, (e) => e.tags.single.metadata);
+
+ source = """@native
+ part 'part.dart';
+ const native = 'xyz';
+ main() {}""";
+ compileAndCheckLibrary(source, (e) => e.tags.single.metadata);
+
+ source = """@native
+ part 'part.dart';
+ const native = 'xyz';
+ main() {}""";
+ compileAndCheckLibrary(source,
+ (e) => e.compilationUnits.first.partTag.metadata);
+}
+
void main() {
testClassMetadata();
testTopLevelMethodMetadata();
testTopLevelFieldMetadata();
+ testLibraryTags();
}
diff --git a/tests/compiler/dart2js/mock_compiler.dart b/tests/compiler/dart2js/mock_compiler.dart
index b12336e..2ab105e 100644
--- a/tests/compiler/dart2js/mock_compiler.dart
+++ b/tests/compiler/dart2js/mock_compiler.dart
@@ -47,6 +47,9 @@
boolConversionCheck(x) {}
abstract class JavaScriptIndexingBehavior {}
class JSInvocationMirror {}
+ class Closure {}
+ class Null {}
+ class Dynamic_ {}
S() {}
assertHelper(a){}
throwNoSuchMethod(obj, name, arguments, expectedArgumentNames) {}
@@ -62,6 +65,7 @@
class JSString {
var length;
operator[](index) {}
+ toString() {}
}
class JSNumber {
operator-() {}
@@ -111,9 +115,6 @@
class Function {}
class List<E> {}
abstract class Map<K,V> {}
- class Closure {}
- class Null {}
- class Dynamic_ {}
bool identical(Object a, Object b) {}''';
const String DEFAULT_ISOLATE_HELPERLIB = r'''
diff --git a/tests/compiler/dart2js/patch_test.dart b/tests/compiler/dart2js/patch_test.dart
index 883ca27..272bf9d 100644
--- a/tests/compiler/dart2js/patch_test.dart
+++ b/tests/compiler/dart2js/patch_test.dart
@@ -44,7 +44,8 @@
bool expectIsPatch: false,
bool checkHasBody: false,
bool expectIsGetter: false,
- bool expectIsFound: true}) {
+ bool expectIsFound: true,
+ bool expectIsRegular: false}) {
var element = lookup(buildSourceString(name));
if (!expectIsFound) {
Expect.isNull(element);
@@ -86,7 +87,7 @@
} else {
Expect.isTrue(element.isDeclaration);
}
- if (!(element.isPatched || element.isPatch)) {
+ if (expectIsRegular) {
Expect.isNull(element.origin);
Expect.isNull(element.patch);
@@ -116,6 +117,43 @@
"Unexpected errors: ${compiler.errors}");
}
+testPatchConstructor() {
+ var compiler = applyPatch(
+ """
+ class Class {
+ external Class();
+ }
+ """,
+ """
+ patch class Class {
+ patch Class();
+ }
+ """);
+ var classOrigin = ensure(compiler, "Class", compiler.coreLibrary.find,
+ expectIsPatched: true);
+ classOrigin.ensureResolved(compiler);
+ var classPatch = ensure(compiler, "Class", compiler.coreLibrary.patch.find,
+ expectIsPatch: true);
+
+ Expect.equals(classPatch, classOrigin.patch);
+ Expect.equals(classOrigin, classPatch.origin);
+
+ var constructorOrigin = ensure(compiler, "Class",
+ (name) => classOrigin.localLookup(name),
+ expectIsPatched: true);
+ var constructorPatch = ensure(compiler, "Class",
+ (name) => classPatch.localLookup(name),
+ expectIsPatch: true);
+
+ Expect.equals(constructorPatch, constructorOrigin.patch);
+ Expect.equals(constructorOrigin, constructorPatch.origin);
+
+ Expect.isTrue(compiler.warnings.isEmpty,
+ "Unexpected warnings: ${compiler.warnings}");
+ Expect.isTrue(compiler.errors.isEmpty,
+ "Unexpected errors: ${compiler.errors}");
+}
+
testPatchMember() {
var compiler = applyPatch(
"""
@@ -197,9 +235,9 @@
expectIsPatch: true);
ensure(compiler, "regular", container.lookupLocalMember,
- checkHasBody: true);
+ checkHasBody: true, expectIsRegular: true);
ensure(compiler, "regular", container.patch.lookupLocalMember,
- checkHasBody: true);
+ checkHasBody: true, expectIsRegular: true);
Expect.isTrue(compiler.warnings.isEmpty,
"Unexpected warnings: ${compiler.warnings}");
@@ -227,7 +265,7 @@
ensure(compiler, "ghost", container.lookupLocalMember,
expectIsFound: false);
ensure(compiler, "ghost", container.patch.lookupLocalMember,
- checkHasBody: true);
+ checkHasBody: true, expectIsRegular: true);
Expect.isTrue(compiler.warnings.isEmpty,
"Unexpected warnings: ${compiler.warnings}");
@@ -246,7 +284,7 @@
ensure(compiler,
"_function",
compiler.coreLibrary.patch.find,
- checkHasBody: true);
+ checkHasBody: true, expectIsRegular: true);
Expect.isTrue(compiler.warnings.isEmpty,
"Unexpected warnings: ${compiler.warnings}");
@@ -380,7 +418,7 @@
Expect.equals(1, compiler.errors.length);
Expect.isTrue(
compiler.errors[0].message.kind ==
- MessageKind.EXTERNAL_WITHOUT_IMPLEMENTATION);
+ MessageKind.PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION);
Expect.equals('External method without an implementation.',
compiler.errors[0].message.toString());
}
@@ -411,12 +449,255 @@
Expect.equals(1, compiler.errors.length);
Expect.isTrue(
compiler.errors[0].message.kind ==
- MessageKind.EXTERNAL_WITHOUT_IMPLEMENTATION);
+ MessageKind.PATCH_EXTERNAL_WITHOUT_IMPLEMENTATION);
Expect.equals('External method without an implementation.',
compiler.errors[0].message.toString());
}
+testIsSubclass() {
+ var compiler = applyPatch(
+ """
+ class A {}
+ """,
+ """
+ patch class A {}
+ """);
+ ClassElement cls = ensure(compiler, "A", compiler.coreLibrary.find,
+ expectIsPatched: true);
+ ClassElement patch = cls.patch;
+ Expect.isTrue(cls != patch);
+ Expect.isTrue(cls.isSubclassOf(patch));
+ Expect.isTrue(patch.isSubclassOf(cls));
+}
+
+testPatchNonExistingTopLevel() {
+ var compiler = applyPatch(
+ """
+ // class Class {}
+ """,
+ """
+ patch class Class {}
+ """);
+ Expect.isTrue(compiler.warnings.isEmpty,
+ "Unexpected warnings: ${compiler.warnings}");
+ print('testPatchNonExistingTopLevel:${compiler.errors}');
+ Expect.equals(1, compiler.errors.length);
+ Expect.isTrue(
+ compiler.errors[0].message.kind == MessageKind.PATCH_NON_EXISTING);
+}
+
+testPatchNonExistingMember() {
+ var compiler = applyPatch(
+ """
+ class Class {}
+ """,
+ """
+ patch class Class {
+ patch void foo() {}
+ }
+ """);
+ var container = ensure(compiler, "Class", compiler.coreLibrary.find,
+ expectIsPatched: true);
+ container.parseNode(compiler);
+
+ Expect.isTrue(compiler.warnings.isEmpty,
+ "Unexpected warnings: ${compiler.warnings}");
+ print('testPatchNonExistingMember:${compiler.errors}');
+ Expect.equals(1, compiler.errors.length);
+ Expect.isTrue(
+ compiler.errors[0].message.kind == MessageKind.PATCH_NON_EXISTING);
+}
+
+testPatchNonPatchablePatch() {
+ var compiler = applyPatch(
+ """
+ external get foo;
+ """,
+ """
+ patch var foo;
+ """);
+ ensure(compiler, "foo", compiler.coreLibrary.find);
+
+ Expect.isTrue(compiler.warnings.isEmpty,
+ "Unexpected warnings: ${compiler.warnings}");
+ print('testPatchNonPatchablePatch:${compiler.errors}');
+ Expect.equals(1, compiler.errors.length);
+ Expect.isTrue(
+ compiler.errors[0].message.kind == MessageKind.PATCH_NONPATCHABLE);
+}
+
+testPatchNonPatchableOrigin() {
+ var compiler = applyPatch(
+ """
+ external var foo;
+ """,
+ """
+ patch get foo => 0;
+ """);
+ ensure(compiler, "foo", compiler.coreLibrary.find);
+
+ Expect.isTrue(compiler.warnings.isEmpty,
+ "Unexpected warnings: ${compiler.warnings}");
+ print('testPatchNonPatchableOrigin:${compiler.errors}');
+ Expect.equals(1, compiler.errors.length);
+ Expect.isTrue(
+ compiler.errors[0].message.kind == MessageKind.PATCH_NONPATCHABLE);
+}
+
+testPatchNonExternalTopLevel() {
+ var compiler = applyPatch(
+ """
+ void foo() {}
+ """,
+ """
+ patch void foo() {}
+ """);
+ print('testPatchNonExternalTopLevel.errors:${compiler.errors}');
+ print('testPatchNonExternalTopLevel.warnings:${compiler.warnings}');
+ Expect.equals(1, compiler.errors.length);
+ Expect.isTrue(
+ compiler.errors[0].message.kind == MessageKind.PATCH_NON_EXTERNAL);
+ Expect.equals(1, compiler.warnings.length);
+ Expect.isTrue(
+ compiler.warnings[0].message.kind == MessageKind.PATCH_POINT_TO_FUNCTION);
+}
+
+testPatchNonExternalMember() {
+ var compiler = applyPatch(
+ """
+ class Class {
+ void foo() {}
+ }
+ """,
+ """
+ patch class Class {
+ patch void foo() {}
+ }
+ """);
+ var container = ensure(compiler, "Class", compiler.coreLibrary.find,
+ expectIsPatched: true);
+ container.parseNode(compiler);
+
+ print('testPatchNonExternalMember.errors:${compiler.errors}');
+ print('testPatchNonExternalMember.warnings:${compiler.warnings}');
+ Expect.equals(1, compiler.errors.length);
+ Expect.isTrue(
+ compiler.errors[0].message.kind == MessageKind.PATCH_NON_EXTERNAL);
+ Expect.equals(1, compiler.warnings.length);
+ Expect.isTrue(
+ compiler.warnings[0].message.kind == MessageKind.PATCH_POINT_TO_FUNCTION);
+}
+
+testPatchNonClass() {
+ var compiler = applyPatch(
+ """
+ external void Class() {}
+ """,
+ """
+ patch class Class {}
+ """);
+ print('testPatchNonClass.errors:${compiler.errors}');
+ print('testPatchNonClass.warnings:${compiler.warnings}');
+ Expect.equals(1, compiler.errors.length);
+ Expect.isTrue(
+ compiler.errors[0].message.kind == MessageKind.PATCH_NON_CLASS);
+ Expect.equals(1, compiler.warnings.length);
+ Expect.isTrue(
+ compiler.warnings[0].message.kind == MessageKind.PATCH_POINT_TO_CLASS);
+}
+
+testPatchNonGetter() {
+ var compiler = applyPatch(
+ """
+ external void foo() {}
+ """,
+ """
+ patch get foo => 0;
+ """);
+ print('testPatchNonClass.errors:${compiler.errors}');
+ print('testPatchNonClass.warnings:${compiler.warnings}');
+ Expect.equals(1, compiler.errors.length);
+ Expect.isTrue(
+ compiler.errors[0].message.kind == MessageKind.PATCH_NON_GETTER);
+ Expect.equals(1, compiler.warnings.length);
+ Expect.isTrue(
+ compiler.warnings[0].message.kind == MessageKind.PATCH_POINT_TO_GETTER);
+}
+
+testPatchNoGetter() {
+ var compiler = applyPatch(
+ """
+ external set foo(var value) {}
+ """,
+ """
+ patch get foo => 0;
+ """);
+ print('testPatchNonClass.errors:${compiler.errors}');
+ print('testPatchNonClass.warnings:${compiler.warnings}');
+ Expect.equals(1, compiler.errors.length);
+ Expect.isTrue(
+ compiler.errors[0].message.kind == MessageKind.PATCH_NO_GETTER);
+ Expect.equals(1, compiler.warnings.length);
+ Expect.isTrue(
+ compiler.warnings[0].message.kind == MessageKind.PATCH_POINT_TO_GETTER);
+}
+
+testPatchNonSetter() {
+ var compiler = applyPatch(
+ """
+ external void foo() {}
+ """,
+ """
+ patch set foo(var value) {}
+ """);
+ print('testPatchNonClass.errors:${compiler.errors}');
+ print('testPatchNonClass.warnings:${compiler.warnings}');
+ Expect.equals(1, compiler.errors.length);
+ Expect.isTrue(
+ compiler.errors[0].message.kind == MessageKind.PATCH_NON_SETTER);
+ Expect.equals(1, compiler.warnings.length);
+ Expect.isTrue(
+ compiler.warnings[0].message.kind == MessageKind.PATCH_POINT_TO_SETTER);
+}
+
+testPatchNoSetter() {
+ var compiler = applyPatch(
+ """
+ external get foo;
+ """,
+ """
+ patch set foo(var value) {}
+ """);
+ print('testPatchNonClass.errors:${compiler.errors}');
+ print('testPatchNonClass.warnings:${compiler.warnings}');
+ Expect.equals(1, compiler.errors.length);
+ Expect.isTrue(
+ compiler.errors[0].message.kind == MessageKind.PATCH_NO_SETTER);
+ Expect.equals(1, compiler.warnings.length);
+ Expect.isTrue(
+ compiler.warnings[0].message.kind == MessageKind.PATCH_POINT_TO_SETTER);
+}
+
+testPatchNonFunction() {
+ var compiler = applyPatch(
+ """
+ external get foo;
+ """,
+ """
+ patch void foo() {}
+ """);
+ print('testPatchNonClass.errors:${compiler.errors}');
+ print('testPatchNonClass.warnings:${compiler.warnings}');
+ Expect.equals(1, compiler.errors.length);
+ Expect.isTrue(
+ compiler.errors[0].message.kind == MessageKind.PATCH_NON_FUNCTION);
+ Expect.equals(1, compiler.warnings.length);
+ Expect.isTrue(
+ compiler.warnings[0].message.kind == MessageKind.PATCH_POINT_TO_FUNCTION);
+}
+
main() {
+ testPatchConstructor();
testPatchFunction();
testPatchMember();
testPatchGetter();
@@ -427,4 +708,19 @@
testExternalWithoutImplementationTopLevel();
testExternalWithoutImplementationMember();
+
+ testIsSubclass();
+
+ testPatchNonExistingTopLevel();
+ testPatchNonExistingMember();
+ testPatchNonPatchablePatch();
+ testPatchNonPatchableOrigin();
+ testPatchNonExternalTopLevel();
+ testPatchNonExternalMember();
+ testPatchNonClass();
+ testPatchNonGetter();
+ testPatchNoGetter();
+ testPatchNonSetter();
+ testPatchNoSetter();
+ testPatchNonFunction();
}
diff --git a/tests/compiler/dart2js/resolver_test.dart b/tests/compiler/dart2js/resolver_test.dart
index a2e3742..a8b08ed 100644
--- a/tests/compiler/dart2js/resolver_test.dart
+++ b/tests/compiler/dart2js/resolver_test.dart
@@ -35,7 +35,7 @@
}
}
var definitions = new NodeList(null, new Link.fromList(locals), null, null);
- return new VariableDefinitions(null, Modifiers.EMPTY, definitions, null);
+ return new VariableDefinitions(null, Modifiers.EMPTY, definitions);
}
testLocals(List variables) {
diff --git a/tests/compiler/dart2js/size_test.dart b/tests/compiler/dart2js/size_test.dart
new file mode 100644
index 0000000..d25c4b1
--- /dev/null
+++ b/tests/compiler/dart2js/size_test.dart
@@ -0,0 +1,30 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "mock_compiler.dart";
+import "compiler_helper.dart";
+
+const String TEST = "main() => [];";
+
+const String DEFAULT_CORELIB_WITH_LIST = r'''
+ class Object {}
+ class bool {}
+ abstract class List {}
+ class num {}
+ class int {}
+ class double {}
+ class String {}
+ class Function {}
+ class Type {}
+ class Map {}
+''';
+
+main() {
+ String generated = compileAll(TEST, coreSource: DEFAULT_CORELIB_WITH_LIST);
+ MockCompiler compiler = new MockCompiler();
+ var backend = compiler.backend;
+
+ // Make sure no class is emitted.
+ Expect.isFalse(generated.contains(backend.emitter.defineClassName));
+}
diff --git a/tests/compiler/dart2js/type_checker_test.dart b/tests/compiler/dart2js/type_checker_test.dart
index e51a50f..f69acf9 100644
--- a/tests/compiler/dart2js/type_checker_test.dart
+++ b/tests/compiler/dart2js/type_checker_test.dart
@@ -195,6 +195,73 @@
analyze("${header}c.intTwoArgumentMethod(1, 2, 3); }",
MessageKind.ADDITIONAL_ARGUMENT);
// analyze("${header}c.untypedField(); }");
+
+ analyze("${header}c.intOneArgumentOneOptionalMethod(); }",
+ [MessageKind.MISSING_ARGUMENT]);
+ analyze("${header}c.intOneArgumentOneOptionalMethod(0); }");
+ analyze("${header}c.intOneArgumentOneOptionalMethod(0, 1); }");
+ analyze("${header}c.intOneArgumentOneOptionalMethod(0, 1, 2); }",
+ [MessageKind.ADDITIONAL_ARGUMENT]);
+ analyze("${header}c.intOneArgumentOneOptionalMethod(0, 1, c: 2); }",
+ [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+ analyze("${header}c.intOneArgumentOneOptionalMethod(0, b: 1); }",
+ [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+ analyze("${header}c.intOneArgumentOneOptionalMethod(a: 0, b: 1); }",
+ [MessageKind.NAMED_ARGUMENT_NOT_FOUND,
+ MessageKind.NAMED_ARGUMENT_NOT_FOUND,
+ MessageKind.MISSING_ARGUMENT]);
+
+ analyze("${header}c.intTwoOptionalMethod(); }");
+ analyze("${header}c.intTwoOptionalMethod(0); }");
+ analyze("${header}c.intTwoOptionalMethod(0, 1); }");
+ analyze("${header}c.intTwoOptionalMethod(0, 1, 2); }",
+ [MessageKind.ADDITIONAL_ARGUMENT]);
+ analyze("${header}c.intTwoOptionalMethod(a: 0); }",
+ [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+ analyze("${header}c.intTwoOptionalMethod(0, b: 1); }",
+ [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+
+ analyze("${header}c.intOneArgumentOneNamedMethod(); }",
+ [MessageKind.MISSING_ARGUMENT]);
+ analyze("${header}c.intOneArgumentOneNamedMethod(0); }");
+ analyze("${header}c.intOneArgumentOneNamedMethod(0, b: 1); }");
+ analyze("${header}c.intOneArgumentOneNamedMethod(b: 1); }",
+ [MessageKind.MISSING_ARGUMENT]);
+ analyze("${header}c.intOneArgumentOneNamedMethod(0, b: 1, c: 2); }",
+ [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+ analyze("${header}c.intOneArgumentOneNamedMethod(0, 1); }",
+ [MessageKind.ADDITIONAL_ARGUMENT]);
+ analyze("${header}c.intOneArgumentOneNamedMethod(0, 1, c: 2); }",
+ [MessageKind.ADDITIONAL_ARGUMENT,
+ MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+ analyze("${header}c.intOneArgumentOneNamedMethod(a: 1, b: 1); }",
+ [MessageKind.NAMED_ARGUMENT_NOT_FOUND,
+ MessageKind.MISSING_ARGUMENT]);
+
+ analyze("${header}c.intTwoNamedMethod(); }");
+ analyze("${header}c.intTwoNamedMethod(a: 0); }");
+ analyze("${header}c.intTwoNamedMethod(b: 1); }");
+ analyze("${header}c.intTwoNamedMethod(a: 0, b: 1); }");
+ analyze("${header}c.intTwoNamedMethod(b: 1, a: 0); }");
+ analyze("${header}c.intTwoNamedMethod(0); }",
+ [MessageKind.ADDITIONAL_ARGUMENT]);
+ analyze("${header}c.intTwoNamedMethod(c: 2); }",
+ [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+ analyze("${header}c.intTwoNamedMethod(a: 0, c: 2); }",
+ [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+ analyze("${header}c.intTwoNamedMethod(a: 0, b: 1, c: 2); }",
+ [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+ analyze("${header}c.intTwoNamedMethod(c: 2, b: 1, a: 0); }",
+ [MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+ analyze("${header}c.intTwoNamedMethod(0, b: 1); }",
+ [MessageKind.ADDITIONAL_ARGUMENT]);
+ analyze("${header}c.intTwoNamedMethod(0, 1); }",
+ [MessageKind.ADDITIONAL_ARGUMENT,
+ MessageKind.ADDITIONAL_ARGUMENT]);
+ analyze("${header}c.intTwoNamedMethod(0, c: 2); }",
+ [MessageKind.ADDITIONAL_ARGUMENT,
+ MessageKind.NAMED_ARGUMENT_NOT_FOUND]);
+
}
void testMethodInvocations() {
@@ -514,6 +581,11 @@
int intOneArgumentMethod(int argument) {}
int intTwoArgumentMethod(int argument1, int argument2) {}
+ void intOneArgumentOneOptionalMethod(int a, [int b]) {}
+ void intTwoOptionalMethod([int a, int b]) {}
+ void intOneArgumentOneNamedMethod(int a, {int b}) {}
+ void intTwoNamedMethod({int a, int b}) {}
+
Function functionField;
var untypedField;
int intField;
diff --git a/tests/compiler/dart2js/unparser_test.dart b/tests/compiler/dart2js/unparser_test.dart
index cecb766..ee7b710 100644
--- a/tests/compiler/dart2js/unparser_test.dart
+++ b/tests/compiler/dart2js/unparser_test.dart
@@ -304,6 +304,43 @@
testUnparseTopLevelWithMetadata('typedef C = S with M1,M2<A,B>;');
}
+testUnparseParameters(List<String> variableDeclarations) {
+ var sb = new StringBuffer();
+ sb.add('Constructor(');
+ int index = 0;
+ for (String variableDeclaration in variableDeclarations) {
+ if (index != 0) {
+ sb.add(', ');
+ }
+ sb.add(variableDeclaration);
+ index++;
+ }
+ sb.add(');');
+
+ FunctionExpression node = parseMember(sb.toString());
+ index = 0;
+ for (VariableDefinitions parameter in node.parameters.nodes) {
+ Expect.equals(variableDeclarations[index], unparse(parameter));
+ index++;
+ }
+
+}
+
+testParameters() {
+ testUnparseParameters(
+ ["foo", "bar=0", "int baz", "int boz=0"]);
+ testUnparseParameters(
+ ["this.foo", "this.bar=0", "int this.baz", "int this.boz=0"]);
+ testUnparseParameters(
+ ["foo()", "void bar()", "int baz(a)", "int boz(int a,int b)=null"]);
+ testUnparseParameters(
+ ["this.foo()",
+ //"void this.bar()", // Commented out due to Issue 7852
+ //"int this.baz(a)", // Commented out due to Issue 7852
+ //"int this.boz(int a,int b)=null" // Commented out due to Issue 7852
+ ]);
+}
+
main() {
testSignedConstants();
testGenericTypes();
@@ -324,4 +361,5 @@
testRedirectingFactoryConstructors();
testClassDeclarations();
testMixinApplications();
+ testParameters();
}
diff --git a/tests/corelib/hidden_library2_test.dart b/tests/corelib/hidden_library2_test.dart
new file mode 100644
index 0000000..d47aca7
--- /dev/null
+++ b/tests/corelib/hidden_library2_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.
+// Test that the internal hidden library doesn't make problems with taking
+// stack-traces.
+
+main() {
+ print(['x'].where((_) {
+ // We actually don't really care for the successful case. We just want to
+ // make sure that the test doesn't crash when it is negative.
+ throw 'fisk'; /// 1: runtime error
+ return true;
+ }));
+}
diff --git a/tests/corelib/iterable_expand_test.dart b/tests/corelib/iterable_expand_test.dart
new file mode 100644
index 0000000..67aaf5b
--- /dev/null
+++ b/tests/corelib/iterable_expand_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.
+
+main() {
+ test(expectation, iterable) {
+ Expect.listEquals(expectation, iterable.toList());
+ }
+
+ // Function not called on empty iterable.
+ test([], [].expand((x) { throw "not called"; }));
+
+ // Creating the iterable doesn't call the function.
+ [1].expand((x) { throw "not called"; });
+
+ test([1], [1].expand((x) => [x]));
+ test([1, 2, 3], [1, 2, 3].expand((x) => [x]));
+
+ test([], [1].expand((x) => []));
+ test([], [1, 2, 3].expand((x) => []));
+ test([2], [1, 2, 3].expand((x) => x == 2 ? [2] : []));
+
+ test([1, 1, 2, 2, 3, 3], [1, 2, 3].expand((x) => [x, x]));
+ test([1, 1, 2], [1, 2, 3].expand((x) => [x, x, x].skip(x)));
+
+ // if function throws, iteration is stopped.
+ Iterable iterable = [1, 2, 3].expand((x) {
+ if (x == 2) throw "FAIL";
+ return [x, x];
+ });
+ Iterator it = iterable.iterator;
+ Expect.isTrue(it.moveNext());
+ Expect.equals(1, it.current);
+ Expect.isTrue(it.moveNext());
+ Expect.equals(1, it.current);
+ Expect.throws(it.moveNext, (e) => e == "FAIL");
+ // After throwing, iteration is ended.
+ Expect.equals(null, it.current);
+ Expect.isFalse(it.moveNext());
+}
diff --git a/tests/corelib/stopwatch_test.dart b/tests/corelib/stopwatch_test.dart
index b688ab3..2b9c1a6 100644
--- a/tests/corelib/stopwatch_test.dart
+++ b/tests/corelib/stopwatch_test.dart
@@ -8,7 +8,9 @@
class StopwatchTest {
static bool checkTicking(Stopwatch sw) {
+ Expect.isFalse(sw.isRunning);
sw.start();
+ Expect.isTrue(sw.isRunning);
for (int i = 0; i < 10000; i++) {
int.parse(i.toString());
if (sw.elapsedTicks > 0) {
@@ -20,10 +22,12 @@
static bool checkStopping(Stopwatch sw) {
sw.stop();
+ Expect.isFalse(sw.isRunning);
int v1 = sw.elapsedTicks;
Expect.isTrue(v1 > 0); // Expect a non-zero elapsed time.
Stopwatch sw2 = new Stopwatch(); // Used for verification.
sw2.start();
+ Expect.isTrue(sw2.isRunning);
int sw2LastElapsed = 0;
for (int i = 0; i < 100000; i++) {
int.parse(i.toString());
@@ -46,7 +50,9 @@
static checkRestart() {
Stopwatch sw = new Stopwatch();
+ Expect.isFalse(sw.isRunning);
sw.start();
+ Expect.isTrue(sw.isRunning);
for (int i = 0; i < 100000; i++) {
int.parse(i.toString());
if (sw.elapsedTicks > 0) {
@@ -54,8 +60,10 @@
}
}
sw.stop();
+ Expect.isFalse(sw.isRunning);
int initial = sw.elapsedTicks;
sw.start();
+ Expect.isTrue(sw.isRunning);
for (int i = 0; i < 100000; i++) {
int.parse(i.toString());
if (sw.elapsedTicks > initial) {
@@ -63,12 +71,15 @@
}
}
sw.stop();
+ Expect.isFalse(sw.isRunning);
Expect.isTrue(sw.elapsedTicks > initial);
}
static checkReset() {
Stopwatch sw = new Stopwatch();
+ Expect.isFalse(sw.isRunning);
sw.start();
+ Expect.isTrue(sw.isRunning);
for (int i = 0; i < 100000; i++) {
int.parse(i.toString());
if (sw.elapsedTicks > 0) {
@@ -76,9 +87,12 @@
}
}
sw.stop();
+ Expect.isFalse(sw.isRunning);
sw.reset();
+ Expect.isFalse(sw.isRunning);
Expect.equals(0, sw.elapsedTicks);
sw.start();
+ Expect.isTrue(sw.isRunning);
for (int i = 0; i < 100000; i++) {
int.parse(i.toString());
if (sw.elapsedTicks > 0) {
@@ -86,6 +100,7 @@
}
}
sw.reset();
+ Expect.isTrue(sw.isRunning);
for (int i = 0; i < 100000; i++) {
int.parse(i.toString());
if (sw.elapsedTicks > 0) {
@@ -93,6 +108,7 @@
}
}
sw.stop();
+ Expect.isFalse(sw.isRunning);
Expect.isTrue(sw.elapsedTicks > 0);
}
diff --git a/tests/html/cdata_test.dart b/tests/html/cdata_test.dart
new file mode 100644
index 0000000..b23a397
--- /dev/null
+++ b/tests/html/cdata_test.dart
@@ -0,0 +1,24 @@
+// 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 cdata_test;
+import '../../pkg/unittest/lib/unittest.dart';
+import '../../pkg/unittest/lib/html_config.dart';
+import 'dart:html';
+
+
+main() {
+ useHtmlConfiguration();
+
+ test('remove', () {
+ var div = new Element.html('<div>content</div>');
+ var cdata = div.nodes[0];
+ expect(cdata is CharacterData, true);
+ expect(cdata, isNotNull);
+ expect(div.innerHtml, 'content');
+
+ cdata.remove();
+ expect(div.innerHtml, '');
+ });
+}
diff --git a/tests/html/indexeddb_1_test.dart b/tests/html/indexeddb_1_test.dart
index 92eef20..eac993f 100644
--- a/tests/html/indexeddb_1_test.dart
+++ b/tests/html/indexeddb_1_test.dart
@@ -39,8 +39,9 @@
step1() {
var transaction = db.transaction([storeName], 'readwrite');
var request = transaction.objectStore(storeName).put(value, key);
- request.onSuccess.listen(expectAsync1(step2));
request.onError.listen(fail);
+
+ transaction.onComplete.listen(expectAsync1(step2));
}
initDb(e) {
@@ -115,8 +116,9 @@
step1() {
idb.Transaction transaction = db.transaction([storeName], 'readwrite');
idb.Request request = transaction.objectStore(storeName).put(value, key);
- request.onSuccess.listen(expectAsync1(step2));
request.onError.listen(fail);
+
+ transaction.onComplete.listen(expectAsync1(step2));
}
initDb(e) {
diff --git a/tests/html/indexeddb_2_test.dart b/tests/html/indexeddb_2_test.dart
index 66fef6c..b5053c9 100644
--- a/tests/html/indexeddb_2_test.dart
+++ b/tests/html/indexeddb_2_test.dart
@@ -43,8 +43,9 @@
step1() {
var transaction = db.transaction([storeName], 'readwrite');
var request = transaction.objectStore(storeName).put(value, key);
- request.onSuccess.listen(expectAsync1(step2));
request.onError.listen(fail);
+
+ transaction.onComplete.listen(expectAsync1(step2));
}
initDb(e) {
diff --git a/tests/isolate/count_test.dart b/tests/isolate/count_test.dart
index 7ad82d6..2010c88 100644
--- a/tests/isolate/count_test.dart
+++ b/tests/isolate/count_test.dart
@@ -46,7 +46,7 @@
if (count == 10) {
remote.send(-1, reply);
}
- }, 11));
+ }, count: 11));
remote.send(count++, reply);
});
}
diff --git a/tests/language/import_private_test.dart b/tests/language/import_private_test.dart
new file mode 100644
index 0000000..e269c7a
--- /dev/null
+++ b/tests/language/import_private_test.dart
@@ -0,0 +1,10 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+// Check that private dart:_ libraries cannot be imported.
+
+import "dart:_collection-dev"; /// 01: compile-time error
+
+main() {
+ print("Done.");
+}
diff --git a/tests/language/invocation_mirror_invoke_on2_test.dart b/tests/language/invocation_mirror_invoke_on2_test.dart
new file mode 100644
index 0000000..b8bec8a
--- /dev/null
+++ b/tests/language/invocation_mirror_invoke_on2_test.dart
@@ -0,0 +1,78 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+class Proxy {
+ final proxied;
+ Proxy(this.proxied);
+ noSuchMethod(mirror) => mirror.invokeOn(proxied);
+}
+
+main() {
+ testList();
+ testString();
+ testInt();
+ testDouble();
+}
+
+testList() {
+ var list = [];
+ var proxy = new Proxy(list);
+
+ Expect.isTrue(proxy.isEmpty);
+ Expect.isTrue(list.isEmpty);
+
+ proxy.add(42);
+
+ Expect.isFalse(proxy.isEmpty);
+ Expect.equals(1, proxy.length);
+ Expect.equals(42, proxy[0]);
+
+ Expect.isFalse(list.isEmpty);
+ Expect.equals(1, list.length);
+ Expect.equals(42, list[0]);
+
+ proxy.add(87);
+
+ Expect.equals(2, proxy.length);
+ Expect.equals(87, proxy[1]);
+
+ Expect.equals(2, list.length);
+ Expect.equals(87, list[1]);
+
+ Expect.throws(() => proxy.funky(), (e) => e is NoSuchMethodError);
+ Expect.throws(() => list.funky(), (e) => e is NoSuchMethodError);
+}
+
+testString() {
+ var string = "funky";
+ var proxy = new Proxy(string);
+
+ Expect.equals(string.charCodeAt(0), proxy.charCodeAt(0));
+ Expect.equals(string.length, proxy.length);
+
+ Expect.throws(() => proxy.funky(), (e) => e is NoSuchMethodError);
+ Expect.throws(() => string.funky(), (e) => e is NoSuchMethodError);
+}
+
+testInt() {
+ var number = 42;
+ var proxy = new Proxy(number);
+
+ Expect.equals(number + 87, proxy + 87);
+ Expect.equals(number.toDouble(), proxy.toDouble());
+
+ Expect.throws(() => proxy.funky(), (e) => e is NoSuchMethodError);
+ Expect.throws(() => number.funky(), (e) => e is NoSuchMethodError);
+}
+
+testDouble() {
+ var number = 42.99;
+ var proxy = new Proxy(number);
+
+ Expect.equals(number + 87, proxy + 87);
+ Expect.equals(number.toInt(), proxy.toInt());
+
+ Expect.throws(() => proxy.funky(), (e) => e is NoSuchMethodError);
+ Expect.throws(() => number.funky(), (e) => e is NoSuchMethodError);
+}
diff --git a/tests/language/language.status b/tests/language/language.status
index 85b14a8..9ffdffd 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -104,6 +104,7 @@
[ $compiler == dartc ]
class_literal_test/none : Fail # Issue 7630.
+import_private_test/01: Fail # Issue 8365.
# test issue 7749
list_literal1_negative_test: Fail
diff --git a/tests/language/null_no_such_method_test.dart b/tests/language/null_no_such_method_test.dart
new file mode 100644
index 0000000..adfab89
--- /dev/null
+++ b/tests/language/null_no_such_method_test.dart
@@ -0,0 +1,11 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+var array = [1];
+
+main() {
+ Expect.throws(() => -null, (e) => e is NoSuchMethodError);
+ // Make sure we have an untyped call to operator-.
+ print(-array[0]);
+}
diff --git a/tests/language/private_selector_lib.dart b/tests/language/private_selector_lib.dart
new file mode 100644
index 0000000..c9a11c9
--- /dev/null
+++ b/tests/language/private_selector_lib.dart
@@ -0,0 +1,19 @@
+// 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 private_selector_lib;
+
+import 'private_selector_test.dart';
+
+bool executed = false;
+
+class A {
+ public() {
+ new B()._private();
+ }
+
+ _private() {
+ executed = true;
+ }
+}
diff --git a/tests/language/private_selector_test.dart b/tests/language/private_selector_test.dart
new file mode 100644
index 0000000..53dca839
--- /dev/null
+++ b/tests/language/private_selector_test.dart
@@ -0,0 +1,15 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+library private_selector_test;
+
+import 'private_selector_lib.dart';
+
+class B extends A {
+}
+
+main() {
+ new A().public();
+ Expect.isTrue(executed);
+}
diff --git a/tests/language/reg_exp3_test.dart b/tests/language/reg_exp3_test.dart
index 0ac8064..b0410ed 100644
--- a/tests/language/reg_exp3_test.dart
+++ b/tests/language/reg_exp3_test.dart
@@ -9,7 +9,7 @@
try {
RegExp exp = new RegExp("[");
i = 100; // Should not reach here.
- } on IllegalJSRegExpException catch (e) {
+ } on FormatException catch (e) {
i = 0;
}
Expect.equals(0, i);
diff --git a/tests/lib/async/event_helper.dart b/tests/lib/async/event_helper.dart
index e6816e6..c8a3cb2 100644
--- a/tests/lib/async/event_helper.dart
+++ b/tests/lib/async/event_helper.dart
@@ -72,7 +72,7 @@
factory Events.capture(Stream stream,
{ bool unsubscribeOnError: false }) = CaptureEvents;
- // Sink interface.
+ // StreamSink interface.
add(var value) { events.add(new DataEvent(value)); }
void signalError(AsyncError error) {
diff --git a/tests/lib/async/stream_transform_test.dart b/tests/lib/async/stream_transform_test.dart
new file mode 100644
index 0000000..436c229
--- /dev/null
+++ b/tests/lib/async/stream_transform_test.dart
@@ -0,0 +1,48 @@
+// 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 stream_transform_test;
+
+import 'dart:async';
+import '../../../pkg/unittest/lib/unittest.dart';
+import 'event_helper.dart';
+
+
+main() {
+ // Regression tests for http://dartbug.com/8311
+
+ test("simpleDone", () {
+ StreamController c = new StreamController();
+ Stream out = c.stream.handleError((x){}).handleError((x){});
+ out.listen((v){}, onDone: expectAsync0(() {}));
+ // Should not throw.
+ c.close();
+ });
+
+ test("with events", () {
+ StreamController c = new StreamController();
+ Events expected = new Events.fromIterable([10, 12]);
+ Events input = new Events.fromIterable([1, 2, 3, 4, 5, 6, 7]);
+ Events actual = new Events.capture(
+ c.stream.map((x) => x * 2).where((x) => x > 5).skip(2).take(2));
+ actual.onDone(expectAsync0(() {
+ Expect.listEquals(expected.events, actual.events);
+ }));
+ input.replay(c);
+ });
+
+ test("paused events", () {
+ StreamController c = new StreamController();
+ Events expected = new Events.fromIterable([10, 12]);
+ Events input = new Events.fromIterable([1, 2, 3, 4, 5, 6, 7]);
+ Events actual = new Events.capture(
+ c.stream.map((x) => x * 2).where((x) => x > 5).skip(2).take(2));
+ actual.onDone(expectAsync0(() {
+ Expect.listEquals(expected.events, actual.events);
+ }));
+ actual.pause();
+ input.replay(c);
+ actual.resume();
+ });
+}
diff --git a/tests/standalone/pow_test.dart b/tests/standalone/pow_test.dart
new file mode 100644
index 0000000..02ad5a3
--- /dev/null
+++ b/tests/standalone/pow_test.dart
@@ -0,0 +1,97 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+//
+// Dart test program for testing math's pow.
+
+library pow_test;
+
+import 'dart:math';
+
+var expectedResults =
+[
+ 1,
+ 2,
+ 4,
+ 8,
+ 16,
+ 32,
+ 64,
+ 128,
+ 256,
+ 512,
+ 1024,
+ 2048,
+ 4096,
+ 8192,
+ 16384,
+ 32768,
+ 65536,
+ 131072,
+ 262144,
+ 524288,
+ 1048576,
+ 2097152,
+ 4194304,
+ 8388608,
+ 16777216,
+ 33554432,
+ 67108864,
+ 134217728,
+ 268435456,
+ 536870912,
+ 1073741824,
+ 2147483648,
+ 4294967296,
+ 8589934592,
+ 17179869184,
+ 34359738368,
+ 68719476736,
+ 137438953472,
+ 274877906944,
+ 549755813888,
+ 1099511627776,
+ 2199023255552,
+ 4398046511104,
+ 8796093022208,
+ 17592186044416,
+ 35184372088832,
+ 70368744177664,
+ 140737488355328,
+ 281474976710656,
+ 562949953421312,
+ 1125899906842624,
+ 2251799813685248,
+ 4503599627370496,
+ 9007199254740992,
+ 18014398509481984,
+ 36028797018963968,
+ 72057594037927936,
+ 144115188075855872,
+ 288230376151711744,
+ 576460752303423488,
+ 1152921504606846976,
+ 2305843009213693952,
+ 4611686018427387904,
+ 9223372036854775808,
+ 18446744073709551616,
+ 36893488147419103232,
+ 73786976294838206464,
+ 147573952589676412928
+];
+
+
+void main() {
+ int exp = 0;
+ for (int val in expectedResults) {
+ Expect.equals(val, pow(2, exp++));
+ }
+ // Optimize it.
+ for (int i = 0; i < 8888; i++) {
+ pow(2, 3);
+ }
+ exp = 0;
+ for (int val in expectedResults) {
+ Expect.equals(val, pow(2, exp++));
+ }
+}
diff --git a/tests/utils/dummy_compiler_test.dart b/tests/utils/dummy_compiler_test.dart
index 5bd9dce..696713c 100644
--- a/tests/utils/dummy_compiler_test.dart
+++ b/tests/utils/dummy_compiler_test.dart
@@ -48,6 +48,7 @@
var length;
var split;
var concat;
+ var toString;
}
class JSFunction {}
class JSInt {}
diff --git a/tools/VERSION b/tools/VERSION
index 6e24da0..da7071a 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -1,4 +1,4 @@
MAJOR 0
MINOR 3
-BUILD 4
+BUILD 5
PATCH 0
diff --git a/tools/create_sdk.py b/tools/create_sdk.py
index 28882b9..a8df879 100755
--- a/tools/create_sdk.py
+++ b/tools/create_sdk.py
@@ -25,7 +25,7 @@
# ......_internal/
# ......async/
# ......collection/
-# ......collection_dev/
+# ......_collection_dev/
# ......core/
# ......crypto/
# ......html/
@@ -199,7 +199,7 @@
#
os.makedirs(join(LIB, 'html'))
- for library in ['_internal', 'async', 'collection', 'collection_dev', 'core',
+ for library in ['_internal', 'async', 'collection', '_collection_dev', 'core',
'crypto', 'io', 'isolate',
join('chrome', 'dart2js'), join('chrome', 'dartium'),
join('html', 'dart2js'), join('html', 'dartium'),
diff --git a/tools/dom/scripts/htmleventgenerator.py b/tools/dom/scripts/htmleventgenerator.py
index 4fd609b..a05dd1b 100644
--- a/tools/dom/scripts/htmleventgenerator.py
+++ b/tools/dom/scripts/htmleventgenerator.py
@@ -301,7 +301,7 @@
'HTMLMediaElement.webkitkeyerror': ('keyError', 'MediaKeyEvent'),
'HTMLMediaElement.webkitkeymessage': ('keyMessage', 'MediaKeyEvent'),
'HTMLMediaElement.webkitneedkey': ('needKey', 'MediaKeyEvent'),
- 'IDBDatabase.versionchange': ('versionChange', 'UpgradeNeededEvent'),
+ 'IDBDatabase.versionchange': ('versionChange', 'VersionChangeEvent'),
'IDBOpenDBRequest.blocked': ('blocked', 'Event'),
'IDBOpenDBRequest.upgradeneeded': ('upgradeNeeded', 'VersionChangeEvent'),
'IDBRequest.success': ('success', 'Event'),
diff --git a/tools/dom/scripts/htmlrenamer.py b/tools/dom/scripts/htmlrenamer.py
index 69b90af..bdc24fe 100644
--- a/tools/dom/scripts/htmlrenamer.py
+++ b/tools/dom/scripts/htmlrenamer.py
@@ -31,7 +31,6 @@
'WebKitCSSMatrix': 'CssMatrix',
'WebKitCSSTransformValue': 'CssTransformValue',
'WebKitPoint': 'DomPoint',
- 'WebKitTransitionEvent': 'TransitionEvent',
'XMLHttpRequest': 'HttpRequest',
'XMLHttpRequestException': 'HttpRequestException',
'XMLHttpRequestProgressEvent': 'HttpRequestProgressEvent',
@@ -231,6 +230,7 @@
'CanvasRenderingContext2D.setMiterLimit',
'CanvasRenderingContext2D.setShadow',
'CanvasRenderingContext2D.setStrokeColor',
+ 'CharacterData.remove',
'DOMWindow.call:blur',
'DOMWindow.clientInformation',
'DOMWindow.call:focus',
diff --git a/tools/dom/src/CssClassSet.dart b/tools/dom/src/CssClassSet.dart
index c688181..d018108 100644
--- a/tools/dom/src/CssClassSet.dart
+++ b/tools/dom/src/CssClassSet.dart
@@ -50,13 +50,15 @@
Iterable<String> where(bool f(String element)) => readClasses().where(f);
+ Iterable expand(Iterable f(String element)) => readClasses.expand(f);
+
bool every(bool f(String element)) => readClasses().every(f);
bool any(bool f(String element)) => readClasses().any(f);
bool get isEmpty => readClasses().isEmpty;
- int get length =>readClasses().length;
+ int get length => readClasses().length;
dynamic reduce(dynamic initialValue,
dynamic combine(dynamic previousValue, String element)) {
diff --git a/tools/dom/templates/html/impl/impl_DOMException.darttemplate b/tools/dom/templates/html/impl/impl_DOMException.darttemplate
index 593fd4c..caba0d2 100644
--- a/tools/dom/templates/html/impl/impl_DOMException.darttemplate
+++ b/tools/dom/templates/html/impl/impl_DOMException.darttemplate
@@ -4,8 +4,7 @@
part of $LIBRARYNAME;
-/// @domName $DOMNAME
-class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC {
+$(ANNOTATIONS)class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC {
static const String INDEX_SIZE = 'IndexSizeError';
static const String HIERARCHY_REQUEST = 'HierarchyRequestError';
diff --git a/tools/dom/templates/html/impl/impl_Element.darttemplate b/tools/dom/templates/html/impl/impl_Element.darttemplate
index c47ffe1..890938e 100644
--- a/tools/dom/templates/html/impl/impl_Element.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Element.darttemplate
@@ -73,6 +73,10 @@
return IterableMixinWorkaround.where(this, f);
}
+ Iterable expand(Iterable f(Element element)) {
+ return IterableMixinWorkaround.expand(this, f);
+ }
+
bool get isEmpty {
return _element.$dom_firstElementChild == null;
}
@@ -290,6 +294,10 @@
return IterableMixinWorkaround.where(this, f);
}
+ Iterable expand(Iterable f(Element element)) {
+ return IterableMixinWorkaround.expand(this, f);
+ }
+
bool every(bool f(Element element)) {
for(Element element in this) {
if (!f(element)) {
diff --git a/tools/dom/templates/html/impl/impl_MediaStream.darttemplate b/tools/dom/templates/html/impl/impl_MediaStream.darttemplate
index 9691338..7b62c0c 100644
--- a/tools/dom/templates/html/impl/impl_MediaStream.darttemplate
+++ b/tools/dom/templates/html/impl/impl_MediaStream.darttemplate
@@ -4,8 +4,7 @@
part of $LIBRARYNAME;
-/// @domName $DOMNAME; @docsEditable true$ANNOTATIONS
-class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC {
+$(ANNOTATIONS)class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC {
$!MEMBERS
/**
diff --git a/tools/dom/templates/html/impl/impl_Node.darttemplate b/tools/dom/templates/html/impl/impl_Node.darttemplate
index 63d0e49..5f3a0c9 100644
--- a/tools/dom/templates/html/impl/impl_Node.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Node.darttemplate
@@ -150,6 +150,10 @@
return IterableMixinWorkaround.where(this, f);
}
+ Iterable expand(Iterable f(Node element)) {
+ return IterableMixinWorkaround.expand(this, f);
+ }
+
bool every(bool f(Node element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f(Node element)) => IterableMixinWorkaround.any(this, f);
diff --git a/tools/dom/templates/html/impl/impl_XMLHttpRequest.darttemplate b/tools/dom/templates/html/impl/impl_XMLHttpRequest.darttemplate
index 078d873..1b75464 100644
--- a/tools/dom/templates/html/impl/impl_XMLHttpRequest.darttemplate
+++ b/tools/dom/templates/html/impl/impl_XMLHttpRequest.darttemplate
@@ -69,6 +69,11 @@
* * The `Access-Control-Allow-Credentials` header of `url` must be set to true.
* * If `Access-Control-Expose-Headers` has not been set to true, only a subset of all the response headers will be returned when calling [getAllRequestHeaders].
*
+ * Note that requests for file:// URIs are only supported by Chrome extensions
+ * with appropriate permissions in their manifest. Requests to file:// URIs
+ * will also never fail- the Future will always complete successfully, even
+ * when the file cannot be found.
+ *
* See also: [authorization headers](http://en.wikipedia.org/wiki/Basic_access_authentication).
*/
static Future<HttpRequest> request(String url,
@@ -95,8 +100,9 @@
}
xhr.onLoad.listen((e) {
- if (xhr.status >= 200 && xhr.status < 300 ||
- xhr.status == 304 ) {
+ // Note: file:// URIs have status of 0.
+ if ((xhr.status >= 200 && xhr.status < 300) ||
+ xhr.status == 0 || xhr.status == 304) {
completer.complete(xhr);
} else {
completer.completeError(e);
diff --git a/tools/dom/templates/immutable_list_mixin.darttemplate b/tools/dom/templates/immutable_list_mixin.darttemplate
index 77fdd0d..2c8bf68 100644
--- a/tools/dom/templates/immutable_list_mixin.darttemplate
+++ b/tools/dom/templates/immutable_list_mixin.darttemplate
@@ -38,6 +38,9 @@
Iterable<$E> where(bool f($E element)) =>
IterableMixinWorkaround.where(this, f);
+ Iterable expand(Iterable f($E element)) =>
+ IterableMixinWorkaround.expand(this, f);
+
bool every(bool f($E element)) => IterableMixinWorkaround.every(this, f);
bool any(bool f($E element)) => IterableMixinWorkaround.any(this, f);
diff --git a/tools/html_json_doc/bin/html_json_doc.dart b/tools/html_json_doc/bin/html_json_doc.dart
deleted file mode 100644
index c37d302..0000000
--- a/tools/html_json_doc/bin/html_json_doc.dart
+++ /dev/null
@@ -1,69 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-/**
- * TODO(amouravski): Document stuff here.
- */
-
-import 'dart:io';
-
-import '../lib/html_to_json.dart' as html_to_json;
-import '../lib/json_to_html.dart' as json_to_html;
-import '../../../pkg/args/lib/args.dart';
-
-// Need this because ArgParser.getUsage doesn't show command invocation.
-const USAGE = 'Usage htmlJsonDoc [options] --mode=<mode> <HTML.dart directory> '
- '<json path>\n[options] include:';
-final argParser = new ArgParser();
-
-main() {
- final args = new Options().arguments;
-
- if (args.isEmpty) {
- printUsage('No arguments provided.');
- return;
- }
-
- var mode;
- argParser.addOption('mode', abbr: 'm',
- help: '(Required) Convert from HTML docs to JSON or vice versa.',
- allowed: ['html-to-json', 'json-to-html'], allowedHelp: {
- 'html-to-json': 'Processes all HTML .dart files at given\n'
- 'location and outputs JSON.',
- 'json-to-html': 'Takes JSON file at location and inserts docs into\n'
- 'HTML .dart files.'},
- callback: (m) => mode = m
- );
-
- final argResults = argParser.parse(args);
-
- if (mode == null) {
- printUsage('Mode is a required option.');
- return;
- } else if (argResults.rest.length < 2) {
- printUsage('Insufficient arguments.');
- return;
- }
-
- var htmlPath = new Path(argResults.rest[0]);
- var jsonPath = new Path(argResults.rest[1]);
-
- var convertFuture;
- if (mode == 'html-to-json') {
- convertFuture = html_to_json.convert(htmlPath, jsonPath);
- } else {
- convertFuture = json_to_html.convert(htmlPath, jsonPath);
- }
-
- convertFuture.then((anyErrors) {
- print('Completed ${anyErrors ? "with" : "without"} errors.');
- });
-}
-
-/// Prints the usage of the tool. [message] is printed if provided.
-void printUsage([String message]) {
- print(message);
- print(USAGE);
- print(argParser.getUsage());
-}
diff --git a/tools/html_json_doc/lib/html_to_json.dart b/tools/html_json_doc/lib/html_to_json.dart
deleted file mode 100644
index 2013640..0000000
--- a/tools/html_json_doc/lib/html_to_json.dart
+++ /dev/null
@@ -1,318 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-/**
- * Library for extracting the documentation comments from files generated by
- * the HTML library. The comments are stored in a JSON file.
- *
- * Comments must be in either the block style with leading *s:
- *
- * /**
- * * Comment here.
- * */
- *
- * Or the triple-slash style:
- *
- * /// Docs go here.
- * /// And here.
- *
- * Each member that is to be documented should be preceeded by a meta-comment
- * containing the string `@docsEditable` such as:
- *
- * /// @docsEditable
- */
-library html_to_json;
-
-import 'dart:json';
-import 'dart:io';
-import 'dart:async';
-
-
-/// True if any errors were triggered through the conversion.
-bool _anyErrors = false;
-
-
-/**
- * Convert files on [htmlPath] and write JSON to [jsonPath].
- */
-Future<bool> convert(Path htmlPath, Path jsonPath) {
- var completer = new Completer();
-
- // TODO(amouravski): make this transform once I know what I want this file to
- // return.
- _convertFiles(htmlPath).then((convertedJson) {
- final jsonFile = new File.fromPath(jsonPath);
- var writeJson = convertedJson;
-
- if (jsonFile.existsSync()) {
- writeJson = _mergeJsonAndFile(convertedJson, jsonFile);
- }
-
- var outputStream = jsonFile.openOutputStream();
- outputStream.writeString(prettyPrintJson(writeJson));
-
- outputStream.onNoPendingWrites = () {
- completer.complete(_anyErrors);
- };
-
- outputStream.onClosed = () {
- completer.complete(_anyErrors);
- };
-
- outputStream.onError = completer.completeError;
- });
-
- return completer.future;
-}
-
-
-/**
- * Convert all files on [htmlPath].
- *
- * Returns a future that completes to the converted JSON object.
- */
-Future<Object> _convertFiles(Path htmlPath) {
- var completer = new Completer();
-
- List<Future> fileFutures = [];
-
- // Get a list of all HTML dart files.
- // TODO(amouravski): discriminate .dart files.
- final htmlDir = new Directory.fromPath(htmlPath);
- final lister = htmlDir.list(recursive: false);
-
- lister.onFile = (String path) {
- final name = new Path(path).filename;
-
- // Ignore private classes.
- if (name.startsWith('_')) return;
-
- // Ignore non-dart files.
- if (!name.endsWith('.dart')) return;
-
- File file = new File(path);
-
- // TODO(amouravski): Handle missing file.
- if (!file.existsSync()) {
- print('ERROR: cannot find file $path');
- _anyErrors = true;
- return;
- }
-
- fileFutures.add(_convertFile(file));
- };
-
-
- // Combine all JSON objects
- lister.onDone = (_) {
- Futures.wait(fileFutures).then((jsonList) {
- var convertedJson = {};
- jsonList.forEach((json) {
- final k = json.keys[0];
- convertedJson.putIfAbsent(k, () => json[k]);
- });
- completer.complete(convertedJson);
- });
- };
-
- // TODO(amouravski): add more error handling.
-
- return completer.future;
-}
-
-
-/**
- * Convert a single file to JSON docs.
- *
- * Returns a map with one entry whose key is the file name and whose value is
- * the list of comment lines.
- */
-Future<Map> _convertFile(File file) {
- var completer = new Completer();
-
- var comments = {};
-
- // Find all /// @docsEditable annotations.
- InputStream file_stream = file.openInputStream();
- StringInputStream inputLines = new StringInputStream(file_stream);
-
- // TODO(amouravski): Re-write as file.readAsLine().thin((lines) {...}
- inputLines.onLine = () {
- var comment = <String>[];
-
- var docCommentFound = false;
- String line;
- while ((line = inputLines.readLine()) != null) {
- var trimmedLine = line.trim();
-
- // Sentinel found. Process the comment block.
- if (trimmedLine.startsWith('///') &&
- trimmedLine.contains('@docsEditable')) {
- if (docCommentFound == true) {
- var nextLine = inputLines.readLine();
-
- if (nextLine == null) return false;
-
- var lineObject = {};
-
- if (comments[nextLine] != null) {
- print('WARNING: duplicate line ${nextLine} found in'
- '${new Path(file.fullPathSync()).filename}');
- }
- comments.putIfAbsent(nextLine, () => comment);
- }
-
- // Reset.
- docCommentFound = false;
- comment = <String>[];
- } else if ( // Start a comment block.
- trimmedLine.startsWith('/**') ||
- trimmedLine.startsWith('///')) {
- docCommentFound = true;
- comment.add(line);
- } else if (docCommentFound &&
- // TODO(amouravski): This will barf on:
- // /// blah
- // *
- (trimmedLine.startsWith('*') || trimmedLine.startsWith('///'))) {
- comment.add(line);
- } else {
- // Reset if we're not in a comment.
- docCommentFound = false;
- comment = <String>[];
- }
- }
- };
-
- inputLines.onClosed = () {
- var jsonObject = {};
- jsonObject[new Path(file.fullPathSync()).filename] = comments;
- completer.complete(jsonObject);
- };
-
- // TODO(amouravski): better error handling.
-
- return completer.future;
-}
-
-
-/**
- * Merge the new JSON object and the existing file.
- */
-Object _mergeJsonAndFile(Object json, File file) {
- var completer = new Completer();
-
- var fileJson = {};
- var jsonRead = file.readAsStringSync();
-
- if (jsonRead == '') {
- print('WARNING: no data read from '
- '${new Path(file.fullPathSync()).filename}');
- _anyErrors = true;
- } else {
- fileJson = JSON.parse(jsonRead);
- }
- return _mergeJson(json, fileJson);
-}
-
-
-/**
- * Merge two JSON objects, such that the returned JSON object is the
- * union of both.
- *
- * Each JSON must be a map, with each value being a map.
- */
-Object _mergeJson(Object json1, Object json2) {
- if (json1 is Map && json2 is Map) {
- // Then check if [json2] contains any key form [json1], in which case
- // add all of the values from [json2] to the values of [json1].
- json2.forEach((k, v) {
- if (json1.containsKey(k)) {
- v.forEach((vk, vv) {
- if (json1[k].containsKey(vk) &&
- !_listsEqual(json1[k][vk],vv)) {
- // Assume that json1 is more current and take its data as opposed
- // to json2's.
- // TODO(amouravski): add better warning message and only if there's
- // a conflict.
- print('INFO: duplicate keys.');
- _anyErrors = false;
- } else {
- json1[k].putIfAbsent(vk, () => vv);
- }
- });
- } else {
- json1.putIfAbsent(k, () => v);
- }
- });
- } else {
- throw new ArgumentError('JSON objects must both be Maps');
- }
-
- // TODO(amouravski): more error handling.
-
- return json1;
-}
-
-
-/**
- * Tests for equality between two lists.
- *
- * This checks the first level of depth, so does not work for nested lists.
- */
-bool _listsEqual(List list1, List list2) {
- return list1.every((e) => list2.contains(e)) &&
- list2.every((e) => list1.contains(e));
-}
-
-
-/**
- * Print JSON in a much nicer format.
- *
- * For example:
- *
- * {"foo":["bar","baz"],"boo":{"far:"faz"}}
- *
- * becomes:
- *
- * {
- * "foo":
- * [
- * "bar",
- * "baz"
- * ],
- * "boo":
- * {
- * "far":
- * "faz"
- * }
- * }
- */
-String prettyPrintJson(Object json, [String indentation = '']) {
- var output;
-
- if (json is List) {
- var recursiveOutput =
- Strings.join(json.map((e) =>
- prettyPrintJson(e, '$indentation ')), ',\n');
- output = '$indentation[\n'
- '$recursiveOutput'
- '\n$indentation]';
- } else if (json is Map) {
- var keys = json.keys
- ..sort();
-
- // TODO(amouravski): No newline after :
- var mapList = keys.map((key) =>
- '$indentation${JSON.stringify(key)}:\n'
- '${prettyPrintJson(json[key], '$indentation ')}');
- var recursiveOutput = Strings.join(mapList, ',\n');
- output = '$indentation{\n'
- '$recursiveOutput'
- '\n$indentation}';
- } else {
- output = '$indentation${JSON.stringify(json)}';
- }
- return output;
-}
diff --git a/tools/html_json_doc/lib/json_to_html.dart b/tools/html_json_doc/lib/json_to_html.dart
deleted file mode 100644
index 1b56111..0000000
--- a/tools/html_json_doc/lib/json_to_html.dart
+++ /dev/null
@@ -1,155 +0,0 @@
-// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-/**
- * Library for taking a JSON file and putting the comments located within into
- * the HTML files the comments are associated with.
- *
- * The format of the JSON file is:
- *
- * {
- * "$filename":
- * {
- * "$lineInHtml":
- * [
- * "lines of comment",
- * "here"
- * ]
- * },
- * ...
- * }
- */
-library json_to_html;
-
-import 'dart:json' as JSON;
-import 'dart:io';
-import 'dart:async';
-
-/// True if any errors were triggered through the conversion.
-bool _anyErrors = false;
-
-
-/**
- * Take comments from [jsonPath] and apply them to all the files found in
- * [htmlPath]. This will overwrite the files in htmlPath.
- */
-Future<bool> convert(Path htmlPath, Path jsonPath) {
- final completer = new Completer();
-
- final jsonFile = new File.fromPath(jsonPath);
- final htmlDir = new Directory.fromPath(htmlPath);
-
- if (!jsonFile.existsSync()) {
- print("ERROR: No JSON file found at: ${jsonPath}");
- _anyErrors = true;
- completer.complete(false);
- } else if (!htmlDir.existsSync()) {
- print("ERROR: No HTML directory found at: ${htmlPath}");
- _anyErrors = true;
- completer.complete(false);
- }
-
-
- var fileJson = {};
- var jsonRead = jsonFile.readAsStringSync();
-
- if (jsonRead == '') {
- print('WARNING: no data read from ${jsonPath.filename}');
- _anyErrors = true;
- completer.complete(false);
- } else {
- fileJson = JSON.parse(jsonRead);
- }
-
- // TODO(amouravski): Refactor to not duplicate code here and in html-to-json.
- // Find html files. (lister)
- final lister = htmlDir.list(recursive: false);
-
- lister.onFile = (String path) {
- final name = new Path(path).filename;
-
- // Ignore private classes.
- if (name.startsWith('_')) return;
-
- // Ignore non-dart files.
- if (!name.endsWith('.dart')) return;
-
- File file = new File(path);
-
- // TODO(amouravski): Handle missing file.
- if (!file.existsSync()) {
- print('ERROR: cannot find file: $path');
- _anyErrors = true;
- return;
- }
-
- if (!fileJson.containsKey(name)) {
- print('WARNING: file found that is not in JSON: $path');
- _anyErrors = true;
- return;
- }
-
- var comments = fileJson[name];
-
- _convertFile(file, comments);
-
- fileJson.remove(name);
- };
-
- lister.onDone = (_) {
-
- fileJson.forEach((key, _) {
- print('WARNING: the following filename was found in the JSON but not in '
- '${htmlDir.path}:\n"$key"');
- _anyErrors = true;
- });
-
- completer.complete(_anyErrors);
- };
-
- return completer.future;
-}
-
-
-/**
- * Inserts the comments from JSON into a single file.
- */
-void _convertFile(File file, Map<String, List<String>> comments) {
- var fileLines = file.readAsLinesSync();
-
- var unusedComments = {};
-
- comments.forEach((key, comments) {
- var index = fileLines.indexOf(key);
- // If the key is found in any line past the first one.
- if (index > 0 && fileLines[index - 1].trim().startsWith('///') &&
- fileLines[index - 1].contains('@docsEditable')) {
-
- // Add comments.
- fileLines.insertRange(index - 1, comments.length);
- fileLines.setRange(index - 1, comments.length, comments);
- } else {
- unusedComments.putIfAbsent(key, () => comments);
- }
- });
-
- unusedComments.forEach((String key, _) {
- print('WARNING: the following key was found in the JSON but not in '
- '${new Path(file.fullPathSync()).filename}:\n"$key"');
- _anyErrors = true;
- });
-
- for (var i = 0; i < fileLines.length; ++i) {
- fileLines[i] = fileLines[i].replaceAll(new RegExp(r'\s+$'), '');
- }
-
- // TODO(amouravski): file.writeAsStringSync('${Strings.join(fileLines, '\n')}\n');
- var outputStream = file.openOutputStream();
- outputStream.writeString(Strings.join(fileLines, '\n'));
- outputStream.writeString('\n');
-
- outputStream.onNoPendingWrites = () {
- outputStream.close();
- };
-}
diff --git a/tools/html_json_doc/test/html_json_doc_test.dart b/tools/html_json_doc/test/html_json_doc_test.dart
deleted file mode 100644
index 352d2aa8..0000000
--- a/tools/html_json_doc/test/html_json_doc_test.dart
+++ /dev/null
@@ -1,103 +0,0 @@
-import '../../../pkg/unittest/lib/unittest.dart';
-import '../lib/html_to_json.dart' as html_to_json;
-import '../lib/json_to_html.dart' as json_to_html;
-import 'dart:json';
-import 'dart:io';
-
-void main() {
- var scriptPath = new Path(new Options().script).directoryPath.toString();
-
- test('HTML Doc to JSON', () {
- var htmlPath = new Path('$scriptPath/test_data/html_to_json');
- var jsonPath = new Path('$scriptPath/test_output/html_to_json_test.json');
-
- var convertFuture = html_to_json.convert(htmlPath, jsonPath);
-
- convertFuture.then(expectAsync1((anyErrors) {
- var output = new File.fromPath(jsonPath);
-
- var goldenFile = new File(
- '$scriptPath/test_data/html_to_json/'
- 'html_to_json_test_golden_output.json');
-
- expect(anyErrors, false, reason:'The conversion completed with errors.');
- expect(output.readAsStringSync(), goldenFile.readAsStringSync());
- }));
- });
-
- test('JSON to HTML Doc', () {
- var preHtmlPath = new Path('$scriptPath/test_data/json_to_html');
- var goldenHtmlPath = new Path('$scriptPath/test_data/html_to_json');
- var htmlPath = new Path('$scriptPath/test_output');
- var jsonPath = new Path('$scriptPath/test_output/html_to_json_test.json');
-
- var copyFuture = _copyFiles(preHtmlPath, htmlPath);
-
- copyFuture.then(expectAsync1((_) {
- var convertFuture = json_to_html.convert(htmlPath, jsonPath);
-
- convertFuture.then((anyErrors) {
- expect(anyErrors, false,
- reason:'The conversion completed with errors.');
-
- _compareFilesInDirectories(goldenHtmlPath, htmlPath);
-
- });
- }));
- });
-}
-
-void _compareFilesInDirectories(Path path1, Path path2) {
- final dir1 = new Directory.fromPath(path1);
- final dir2 = new Directory.fromPath(path2);
- final lister1 = dir1.list(recursive: false);
- final lister2 = dir2.list(recursive: false);
-
- // True once one of the listers is finished.
- var oneFinished = false;
-
- var list1 = <String, File>{};
-
- lister1.onFile = (String path) {
- if (path.endsWith('.dart')) {
- list1.putIfAbsent(new Path(path).filename, () => new File(path));
- }
- };
-
- lister1.onDone = (_) {
- lister2.onFile = (String path) {
- if (path.endsWith('.dart')) {
- expect(list1[new Path(path).filename].readAsStringSync(),
- new File(path).readAsStringSync());
- }
- };
- };
-}
-
-Future _copyFiles(Path fromDir, Path toDir) {
- // First copy the files into a new place to keep the old files.
- final completer = new Completer();
- final htmlDir = new Directory.fromPath(fromDir);
- final lister = htmlDir.list(recursive: false);
-
- lister.onFile = (String path) {
- final name = new Path(path).filename;
-
- // Ignore private classes.
- if (name.startsWith('_')) return;
-
- // Ignore non-dart files.
- if (!name.endsWith('.dart')) return;
-
- File file = new File(path);
- File newFile = new File.fromPath(toDir.append(name));
-
- var outputStream = newFile.openOutputStream();
- outputStream.writeString(file.readAsStringSync());
- };
-
- lister.onDone = (_) {
- completer.complete(null);
- };
- return completer.future;
-}
diff --git a/tools/html_json_doc/test/test_data/html_to_json/html_to_json_test_golden_output.json b/tools/html_json_doc/test/test_data/html_to_json/html_to_json_test_golden_output.json
deleted file mode 100644
index 8495eed..0000000
--- a/tools/html_json_doc/test/test_data/html_to_json/html_to_json_test_golden_output.json
+++ /dev/null
@@ -1,79 +0,0 @@
-{
-"test_html_input2.dart":
- {
- "class InputTestCase1 {":
- [
- "/**",
- " * This is a multi-line dartdoc comment.",
- " * This is one line.",
- " * And it keeps going to this line, too.",
- " */"
- ],
- "class InputTestCase2 extends InputTestCase1 {":
- [
- "/// This is a single line dartdoc comment."
- ],
- "class InputTestCase3 extends InputTestCase2 {":
- [
- "/// This is a multi-line dartdoc comment.",
- "/// It happens to use multiple single line dartdoc comments."
- ],
- " var InputTestCase8;":
- [
- " /**",
- " * This is a multi-line comment on a member.",
- " */"
- ],
- " var InputTestCase9;":
- [
- " /// This is a single line dartdoc comment on a member."
- ],
- " var InputTestCase10;":
- [
- " /// This is a multi-line dartdoc comment on a member.",
- " /// It is split over two lines."
- ]
- },
-"test_html_input.dart":
- {
- "library testInput;":
- [
- "/**",
- " * YES. This is a library level dartdoc comment.",
- " * This should show up correctly in the JSON.",
- " */"
- ],
- "class InputTestCase1 {":
- [
- "/**",
- " * YES. This is a multi-line dartdoc comment.",
- " * This is one line.",
- " * And it keeps going to this line, too.",
- " */"
- ],
- "class InputTestCase2 extends InputTestCase1 {":
- [
- "/// YES. This is a single line dartdoc comment."
- ],
- "class InputTestCase3 extends InputTestCase2 {":
- [
- "/// YES. This is a multi-line dartdoc comment.",
- "/// It happens to use multiple single line dartdoc comments."
- ],
- " var InputTestCase8;":
- [
- " /**",
- " * YES. This is a multi-line comment on a member.",
- " */"
- ],
- " var InputTestCase9;":
- [
- " /// YES. This is a single line dartdoc comment on a member."
- ],
- " var InputTestCase10;":
- [
- " /// YES. This is a multi-line dartdoc comment on a member.",
- " /// It is split over two lines."
- ]
- }
-}
\ No newline at end of file
diff --git a/tools/html_json_doc/test/test_data/html_to_json/test_html_input.dart b/tools/html_json_doc/test/test_data/html_to_json/test_html_input.dart
deleted file mode 100644
index 291d0dd..0000000
--- a/tools/html_json_doc/test/test_data/html_to_json/test_html_input.dart
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * YES. This is a library level dartdoc comment.
- * This should show up correctly in the JSON.
- */
-/// @docsEditable
-library testInput;
-
-/**
- * YES. This is a multi-line dartdoc comment.
- * This is one line.
- * And it keeps going to this line, too.
- */
-/// @docsEditable
-class InputTestCase1 {
-
-}
-
-/// YES. This is a single line dartdoc comment.
-/// @docsEditable
-class InputTestCase2 extends InputTestCase1 {
-
-}
-
-/// YES. This is a multi-line dartdoc comment.
-/// It happens to use multiple single line dartdoc comments.
-/// @docsEditable
-class InputTestCase3 extends InputTestCase2 {
-
-}
-
-/*
- * NO. This is not a dartdoc comment and should not be picked up.
- * The output of this comment should be nothing.
- */
-/// @docsEditable
-class InputTestCase4 {
-
-}
-
-/**
- * NO. This multi-line dartdoc comment doesn't have the /// @docsEditable stuff.
- * This comment should not show up in the JSON.
- * Note that the /// @docsEditable in this line and the one above are ignored.
- */
-class InputTestCase5 {
-
-}
-
-/// NO. This is a single line dartdoc comment that is ignored.
-class InputTestCase6 {
-
-}
-
-/// NO. This is a multi-line dartdoc comment that is ignored.
-/// It is made of multiple single line dartdoc comments.
-class InputTestCase7 {
-
- /**
- * YES. This is a multi-line comment on a member.
- */
- /// @docsEditable
- var InputTestCase8;
-
- /// YES. This is a single line dartdoc comment on a member.
- /// @docsEditable
- var InputTestCase9;
-
- /// YES. This is a multi-line dartdoc comment on a member.
- /// It is split over two lines.
- /// @docsEditable
- var InputTestCase10;
-
- /**
- * NO.This multi-line comment on a member is ignored.
- */
- var InputTestCase11;
-
- /// NO. This single line dartdoc comment on a member is ignored.
- var InputTestCase12;
-}
diff --git a/tools/html_json_doc/test/test_data/html_to_json/test_html_input2.dart b/tools/html_json_doc/test/test_data/html_to_json/test_html_input2.dart
deleted file mode 100644
index 1f9615b..0000000
--- a/tools/html_json_doc/test/test_data/html_to_json/test_html_input2.dart
+++ /dev/null
@@ -1,79 +0,0 @@
-/**
- * This is a library level dartdoc comment.
- * This should be ignored.
- */
-library testInput2;
-
-/**
- * This is a multi-line dartdoc comment.
- * This is one line.
- * And it keeps going to this line, too.
- */
-/// @docsEditable
-class InputTestCase1 {
-
-}
-
-/// This is a single line dartdoc comment.
-/// @docsEditable
-class InputTestCase2 extends InputTestCase1 {
-
-}
-
-/// This is a multi-line dartdoc comment.
-/// It happens to use multiple single line dartdoc comments.
-/// @docsEditable
-class InputTestCase3 extends InputTestCase2 {
-
-}
-
-/*
- * This is not a dartdoc comment and should not be picked up.
- * The output of this comment should be nothing.
- */
-/// @docsEditable
-class InputTestCase4 {
-
-}
-
-/**
- * This multi-line dartdoc comment doesn't have the /// @docsEditable stuff.
- * This comment should not show up in the JSON.
- * Note that the /// @docsEditable in this line and the one above are ignored.
- */
-class InputTestCase5 {
-
-}
-
-/// This is a single line dartdoc comment that is ignored.
-class InputTestCase6 {
-
-}
-
-/// This is a multi-line dartdoc comment that is ignored.
-/// It is made of multiple single line dartdoc comments.
-class InputTestCase7 {
-
- /**
- * This is a multi-line comment on a member.
- */
- /// @docsEditable
- var InputTestCase8;
-
- /// This is a single line dartdoc comment on a member.
- /// @docsEditable
- var InputTestCase9;
-
- /// This is a multi-line dartdoc comment on a member.
- /// It is split over two lines.
- /// @docsEditable
- var InputTestCase10;
-
- /**
- * This multi-line comment on a member is ignored.
- */
- var InputTestCase11;
-
- /// This single line dartdoc comment on a member is ignored.
- var InputTestCase12;
-}
diff --git a/tools/html_json_doc/test/test_data/json_to_html/test_html_input.dart b/tools/html_json_doc/test/test_data/json_to_html/test_html_input.dart
deleted file mode 100644
index 70b6041..0000000
--- a/tools/html_json_doc/test/test_data/json_to_html/test_html_input.dart
+++ /dev/null
@@ -1,62 +0,0 @@
-/// @docsEditable
-library testInput;
-
-/// @docsEditable
-class InputTestCase1 {
-
-}
-
-/// @docsEditable
-class InputTestCase2 extends InputTestCase1 {
-
-}
-
-/// @docsEditable
-class InputTestCase3 extends InputTestCase2 {
-
-}
-
-/*
- * NO. This is not a dartdoc comment and should not be picked up.
- * The output of this comment should be nothing.
- */
-/// @docsEditable
-class InputTestCase4 {
-
-}
-
-/**
- * NO. This multi-line dartdoc comment doesn't have the /// @docsEditable stuff.
- * This comment should not show up in the JSON.
- * Note that the /// @docsEditable in this line and the one above are ignored.
- */
-class InputTestCase5 {
-
-}
-
-/// NO. This is a single line dartdoc comment that is ignored.
-class InputTestCase6 {
-
-}
-
-/// NO. This is a multi-line dartdoc comment that is ignored.
-/// It is made of multiple single line dartdoc comments.
-class InputTestCase7 {
-
- /// @docsEditable
- var InputTestCase8;
-
- /// @docsEditable
- var InputTestCase9;
-
- /// @docsEditable
- var InputTestCase10;
-
- /**
- * NO.This multi-line comment on a member is ignored.
- */
- var InputTestCase11;
-
- /// NO. This single line dartdoc comment on a member is ignored.
- var InputTestCase12;
-}
diff --git a/tools/html_json_doc/test/test_data/json_to_html/test_html_input2.dart b/tools/html_json_doc/test/test_data/json_to_html/test_html_input2.dart
deleted file mode 100644
index a6b286d..0000000
--- a/tools/html_json_doc/test/test_data/json_to_html/test_html_input2.dart
+++ /dev/null
@@ -1,65 +0,0 @@
-/**
- * This is a library level dartdoc comment.
- * This should be ignored.
- */
-library testInput2;
-
-/// @docsEditable
-class InputTestCase1 {
-
-}
-
-/// @docsEditable
-class InputTestCase2 extends InputTestCase1 {
-
-}
-
-/// @docsEditable
-class InputTestCase3 extends InputTestCase2 {
-
-}
-
-/*
- * This is not a dartdoc comment and should not be picked up.
- * The output of this comment should be nothing.
- */
-/// @docsEditable
-class InputTestCase4 {
-
-}
-
-/**
- * This multi-line dartdoc comment doesn't have the /// @docsEditable stuff.
- * This comment should not show up in the JSON.
- * Note that the /// @docsEditable in this line and the one above are ignored.
- */
-class InputTestCase5 {
-
-}
-
-/// This is a single line dartdoc comment that is ignored.
-class InputTestCase6 {
-
-}
-
-/// This is a multi-line dartdoc comment that is ignored.
-/// It is made of multiple single line dartdoc comments.
-class InputTestCase7 {
-
- /// @docsEditable
- var InputTestCase8;
-
- /// @docsEditable
- var InputTestCase9;
-
- /// @docsEditable
- var InputTestCase10;
-
- /**
- * This multi-line comment on a member is ignored.
- */
- var InputTestCase11;
-
- /// This single line dartdoc comment on a member is ignored.
- var InputTestCase12;
-}
diff --git a/tools/html_json_doc/test/test_output/html_to_json_test.json b/tools/html_json_doc/test/test_output/html_to_json_test.json
deleted file mode 100644
index 8495eed..0000000
--- a/tools/html_json_doc/test/test_output/html_to_json_test.json
+++ /dev/null
@@ -1,79 +0,0 @@
-{
-"test_html_input2.dart":
- {
- "class InputTestCase1 {":
- [
- "/**",
- " * This is a multi-line dartdoc comment.",
- " * This is one line.",
- " * And it keeps going to this line, too.",
- " */"
- ],
- "class InputTestCase2 extends InputTestCase1 {":
- [
- "/// This is a single line dartdoc comment."
- ],
- "class InputTestCase3 extends InputTestCase2 {":
- [
- "/// This is a multi-line dartdoc comment.",
- "/// It happens to use multiple single line dartdoc comments."
- ],
- " var InputTestCase8;":
- [
- " /**",
- " * This is a multi-line comment on a member.",
- " */"
- ],
- " var InputTestCase9;":
- [
- " /// This is a single line dartdoc comment on a member."
- ],
- " var InputTestCase10;":
- [
- " /// This is a multi-line dartdoc comment on a member.",
- " /// It is split over two lines."
- ]
- },
-"test_html_input.dart":
- {
- "library testInput;":
- [
- "/**",
- " * YES. This is a library level dartdoc comment.",
- " * This should show up correctly in the JSON.",
- " */"
- ],
- "class InputTestCase1 {":
- [
- "/**",
- " * YES. This is a multi-line dartdoc comment.",
- " * This is one line.",
- " * And it keeps going to this line, too.",
- " */"
- ],
- "class InputTestCase2 extends InputTestCase1 {":
- [
- "/// YES. This is a single line dartdoc comment."
- ],
- "class InputTestCase3 extends InputTestCase2 {":
- [
- "/// YES. This is a multi-line dartdoc comment.",
- "/// It happens to use multiple single line dartdoc comments."
- ],
- " var InputTestCase8;":
- [
- " /**",
- " * YES. This is a multi-line comment on a member.",
- " */"
- ],
- " var InputTestCase9;":
- [
- " /// YES. This is a single line dartdoc comment on a member."
- ],
- " var InputTestCase10;":
- [
- " /// YES. This is a multi-line dartdoc comment on a member.",
- " /// It is split over two lines."
- ]
- }
-}
\ No newline at end of file
diff --git a/tools/html_json_doc/test/test_output/test_html_input.dart b/tools/html_json_doc/test/test_output/test_html_input.dart
deleted file mode 100644
index 291d0dd..0000000
--- a/tools/html_json_doc/test/test_output/test_html_input.dart
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * YES. This is a library level dartdoc comment.
- * This should show up correctly in the JSON.
- */
-/// @docsEditable
-library testInput;
-
-/**
- * YES. This is a multi-line dartdoc comment.
- * This is one line.
- * And it keeps going to this line, too.
- */
-/// @docsEditable
-class InputTestCase1 {
-
-}
-
-/// YES. This is a single line dartdoc comment.
-/// @docsEditable
-class InputTestCase2 extends InputTestCase1 {
-
-}
-
-/// YES. This is a multi-line dartdoc comment.
-/// It happens to use multiple single line dartdoc comments.
-/// @docsEditable
-class InputTestCase3 extends InputTestCase2 {
-
-}
-
-/*
- * NO. This is not a dartdoc comment and should not be picked up.
- * The output of this comment should be nothing.
- */
-/// @docsEditable
-class InputTestCase4 {
-
-}
-
-/**
- * NO. This multi-line dartdoc comment doesn't have the /// @docsEditable stuff.
- * This comment should not show up in the JSON.
- * Note that the /// @docsEditable in this line and the one above are ignored.
- */
-class InputTestCase5 {
-
-}
-
-/// NO. This is a single line dartdoc comment that is ignored.
-class InputTestCase6 {
-
-}
-
-/// NO. This is a multi-line dartdoc comment that is ignored.
-/// It is made of multiple single line dartdoc comments.
-class InputTestCase7 {
-
- /**
- * YES. This is a multi-line comment on a member.
- */
- /// @docsEditable
- var InputTestCase8;
-
- /// YES. This is a single line dartdoc comment on a member.
- /// @docsEditable
- var InputTestCase9;
-
- /// YES. This is a multi-line dartdoc comment on a member.
- /// It is split over two lines.
- /// @docsEditable
- var InputTestCase10;
-
- /**
- * NO.This multi-line comment on a member is ignored.
- */
- var InputTestCase11;
-
- /// NO. This single line dartdoc comment on a member is ignored.
- var InputTestCase12;
-}
diff --git a/tools/html_json_doc/test/test_output/test_html_input2.dart b/tools/html_json_doc/test/test_output/test_html_input2.dart
deleted file mode 100644
index 1f9615b..0000000
--- a/tools/html_json_doc/test/test_output/test_html_input2.dart
+++ /dev/null
@@ -1,79 +0,0 @@
-/**
- * This is a library level dartdoc comment.
- * This should be ignored.
- */
-library testInput2;
-
-/**
- * This is a multi-line dartdoc comment.
- * This is one line.
- * And it keeps going to this line, too.
- */
-/// @docsEditable
-class InputTestCase1 {
-
-}
-
-/// This is a single line dartdoc comment.
-/// @docsEditable
-class InputTestCase2 extends InputTestCase1 {
-
-}
-
-/// This is a multi-line dartdoc comment.
-/// It happens to use multiple single line dartdoc comments.
-/// @docsEditable
-class InputTestCase3 extends InputTestCase2 {
-
-}
-
-/*
- * This is not a dartdoc comment and should not be picked up.
- * The output of this comment should be nothing.
- */
-/// @docsEditable
-class InputTestCase4 {
-
-}
-
-/**
- * This multi-line dartdoc comment doesn't have the /// @docsEditable stuff.
- * This comment should not show up in the JSON.
- * Note that the /// @docsEditable in this line and the one above are ignored.
- */
-class InputTestCase5 {
-
-}
-
-/// This is a single line dartdoc comment that is ignored.
-class InputTestCase6 {
-
-}
-
-/// This is a multi-line dartdoc comment that is ignored.
-/// It is made of multiple single line dartdoc comments.
-class InputTestCase7 {
-
- /**
- * This is a multi-line comment on a member.
- */
- /// @docsEditable
- var InputTestCase8;
-
- /// This is a single line dartdoc comment on a member.
- /// @docsEditable
- var InputTestCase9;
-
- /// This is a multi-line dartdoc comment on a member.
- /// It is split over two lines.
- /// @docsEditable
- var InputTestCase10;
-
- /**
- * This multi-line comment on a member is ignored.
- */
- var InputTestCase11;
-
- /// This single line dartdoc comment on a member is ignored.
- var InputTestCase12;
-}
diff --git a/tools/publish_all_pkgs.py b/tools/publish_all_pkgs.py
index c20ed29..5ddeb20 100644
--- a/tools/publish_all_pkgs.py
+++ b/tools/publish_all_pkgs.py
@@ -4,7 +4,7 @@
# for details. All rights reserved. Use of this source code is governed by a
# BSD-style license that can be found in the LICENSE file.
#
-# Upload all packages in pkg/ (other than a few that should be explicitly
+# Upload all packages in pkg/ (other than a few that should be explicitly
# excluded), plus sdk/lib/_internal/compiler .
#
# Usage: publish_all_pkgs.py
@@ -21,15 +21,14 @@
pkgs_to_publish = []
for name in os.listdir('pkg'):
if os.path.isdir(os.path.join('pkg', name)):
- if (name != '.svn' and name != 'fixnum' and
- not name.endswith('-experimental')):
+ if name != '.svn' and name != 'fixnum':
pkgs_to_publish.append(os.path.join('pkg', name))
# Publish dart2js as an "unsupported" package.
pkgs_to_publish.append(
os.path.join('sdk', 'lib', '_internal', 'compiler'))
- for pkg in pkgs_to_publish:
+ for pkg in pkgs_to_publish:
print "Publishing " + pkg
subprocess.call(['python', 'tools/publish_pkg.py', pkg])
diff --git a/tools/publish_pkg.py b/tools/publish_pkg.py
index 9861a8d..d1629c9 100755
--- a/tools/publish_pkg.py
+++ b/tools/publish_pkg.py
@@ -58,11 +58,12 @@
version = '%d.%d.%d' % (major, minor, build)
tmpDir = tempfile.mkdtemp()
- pkgName = argv[1].split('/').pop()
+ pkgName = os.path.basename(os.path.normpath(argv[1]))
pubspec = os.path.join(tmpDir, pkgName, 'pubspec.yaml')
- replaceInFiles = []
+ replaceInDart = []
+ replaceInPubspec = []
if os.path.exists(os.path.join(HOME, argv[1], 'pubspec.yaml')):
#
@@ -126,7 +127,7 @@
shutil.copy(libpath, os.path.join(tmpDir, pkgName, 'lib/libraries.dart'))
# Replace '../../libraries.dart' with '../libraries.dart'
- replaceInFiles.append(
+ replaceInDart.append(
(r'(import|part)(\s+)(\'|")\.\./(\.\./)*libraries.dart',
r'\1\2\3\4libraries.dart'))
@@ -159,7 +160,13 @@
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
''');
- replaceInFiles.append(
+ # TODO(jmesserly): this is a hack to make analyzer-experimental work.
+ if pkgName.endswith('-experimental'):
+ pkgReplace = (pkgName, pkgName.replace('-', '_'))
+ replaceInDart.append(pkgReplace)
+ replaceInPubspec.append(pkgReplace)
+
+ replaceInDart.append(
(r'(import|part)(\s+)(\'|")(\.\./)+pkg/([^/]+/)lib/', r'\1\2\3package:\5'))
# Replace '../*/pkg' imports and parts.
@@ -169,7 +176,9 @@
shutil.rmtree(os.path.join(root, '.svn'))
for name in files:
if name.endswith('.dart'):
- ReplaceInFiles([os.path.join(root, name)], replaceInFiles)
+ ReplaceInFiles([os.path.join(root, name)], replaceInDart)
+ elif name == 'pubspec.yaml':
+ ReplaceInFiles([os.path.join(root, name)], replaceInPubspec)
print 'publishing version ' + version + ' of ' + argv[1] + ' to pub.\n'
subprocess.call(['pub', 'publish'], cwd=os.path.join(tmpDir, pkgName))
diff --git a/tools/test-runtime.dart b/tools/test-runtime.dart
index 036c861..2077a06 100755
--- a/tools/test-runtime.dart
+++ b/tools/test-runtime.dart
@@ -73,6 +73,8 @@
}
var testSuites = new List<TestSuite>();
+ TestingServerRunner.setBuildDir(firstConf);
+ TestingServerRunner.setPackageRootDir(firstConf);
for (var conf in configurations) {
if (selectors.containsKey('co19')) {
testSuites.add(new Co19TestSuite(conf));
diff --git a/tools/test.dart b/tools/test.dart
index 12cff10..da3a85e 100755
--- a/tools/test.dart
+++ b/tools/test.dart
@@ -126,6 +126,10 @@
}
var testSuites = new List<TestSuite>();
+ // FIXME(kustermann,ricow): This is boken and should be fixed ASAP.
+ // Issue: 8366
+ TestingServerRunner.setBuildDir(firstConf);
+ TestingServerRunner.setPackageRootDir(firstConf);
var maxBrowserProcesses = maxProcesses;
for (var conf in configurations) {
// There should not be more than one InternetExplorerDriver instance
@@ -134,7 +138,6 @@
if (conf['runtime'].startsWith('ie')) {
maxBrowserProcesses = 1;
}
- TestingServerRunner.setPackageRootDir(conf);
for (String key in selectors.keys) {
if (key == 'co19') {
testSuites.add(new Co19TestSuite(conf));
diff --git a/tools/testing/dart/browser_test.dart b/tools/testing/dart/browser_test.dart
index 6bfc93a..ad9f972 100644
--- a/tools/testing/dart/browser_test.dart
+++ b/tools/testing/dart/browser_test.dart
@@ -5,8 +5,6 @@
part of test_suite;
String getHtmlContents(String title,
- Path controllerScript,
- Path dartJsScript,
String scriptType,
Path sourceScript) =>
"""
@@ -24,10 +22,11 @@
</head>
<body>
<h1> Running $title </h1>
- <script type="text/javascript" src="$controllerScript"></script>
+ <script type="text/javascript" src="/pkg/unittest/lib/test_controller.js">
+ </script>
<script type="$scriptType" src="$sourceScript" onerror="externalError(null)">
</script>
- <script type="text/javascript" src="$dartJsScript"></script>
+ <script type="text/javascript" src="/pkg/browser/lib/dart.js"></script>
</body>
</html>
""";
@@ -48,37 +47,27 @@
</html>
""";
-String wrapDartTestInLibrary(Path test, String testPath) =>
+String wrapDartTestInLibrary(Path testRelativeToDart) =>
"""
library libraryWrapper;
-part '${pathLib.relative(test.toNativePath(),
- from: pathLib.dirname(testPath)).replaceAll('\\', '\\\\')}';
+part '/$testRelativeToDart';
""";
-String dartTestWrapper(Path dartHome, String testPath, Path library) {
- var testPathDir = pathLib.dirname(testPath);
- var dartHomePath = dartHome.toNativePath();
- // TODO(efortuna): Unify path libraries used in test.dart.
- var unitTest = pathLib.relative(pathLib.join(dartHomePath,
- 'pkg/unittest/lib'), from: testPathDir).replaceAll('\\', '\\\\');
-
- var libString = library.toNativePath();
- if (!pathLib.isAbsolute(libString)) {
- libString = pathLib.join(dartHome.toNativePath(), libString);
- }
+String dartTestWrapper(bool usePackageImport, String libraryPathComponent) {
// Tests inside "pkg" import unittest using "package:". All others use a
// relative path. The imports need to agree, so use a matching form here.
- if (pathLib.split(pathLib.relative(libString,
- from: dartHome.toNativePath())).contains("pkg")) {
+ var unitTest;
+ if (usePackageImport) {
unitTest = 'package:unittest';
+ } else {
+ unitTest = '/pkg/unittest/lib';
}
return """
library test;
import '$unitTest/unittest.dart' as unittest;
import '$unitTest/html_config.dart' as config;
-import '${pathLib.relative(libString, from: testPathDir).replaceAll(
- '\\', '\\\\')}' as Test;
+import '$libraryPathComponent' as Test;
main() {
config.useHtmlConfiguration();
diff --git a/tools/testing/dart/http_server.dart b/tools/testing/dart/http_server.dart
index 84a5b77..6966ab3 100644
--- a/tools/testing/dart/http_server.dart
+++ b/tools/testing/dart/http_server.dart
@@ -40,7 +40,11 @@
.join(new Path('../../test.dart'))
.canonicalize()
.toNativePath();
+ // Note: args['package-root'] is always the build directory. We have the
+ // implicit assumption that it contains the 'packages' subdirectory.
+ // TODO: We should probably rename 'package-root' to 'build-directory'.
TestingServerRunner._packageRootDir = new Path(args['package-root']);
+ TestingServerRunner._buildDirectory = new Path(args['package-root']);
TestingServerRunner.startHttpServer('127.0.0.1',
port: int.parse(args['port']));
print('Server listening on port '
@@ -59,16 +63,22 @@
class TestingServerRunner {
static List serverList = [];
static Path _packageRootDir = null;
+ static Path _buildDirectory = null;
// Added as a getter so that the function will be called again each time the
// default request handler closure is executed.
static Path get packageRootDir => _packageRootDir;
+ static Path get buildDirectory => _buildDirectory;
static setPackageRootDir(Map configuration) {
_packageRootDir = TestUtils.currentWorkingDirectory.join(
new Path(TestUtils.buildDir(configuration)));
}
+ static setBuildDir(Map configuration) {
+ _buildDirectory = new Path(TestUtils.buildDir(configuration));
+ }
+
static startHttpServer(String host, {int allowedPort:-1, int port: 0}) {
var basePath = TestUtils.dartDir();
var httpServer = new HttpServer();
@@ -78,10 +88,23 @@
print('Test http server error: $e');
};
httpServer.defaultRequestHandler = (request, resp) {
+ // TODO(kustermann,ricow): We could change this to the following scheme:
+ // http://host:port/root_dart/X -> $DartDir/X
+ // http://host:port/root_build/X -> $BuildDir/X
+ // http://host:port/root_packages/X -> $BuildDir/packages/X
+ // Issue: 8368
+
var requestPath = new Path(request.path.substring(1)).canonicalize();
var path = basePath.join(requestPath);
var file = new File(path.toNativePath());
-
+ // Since the build directory may not be located directly beneath the dart
+ // root directory (if we pass it in, e.g., for dartium testing) we serve
+ // files from the build directory explicitly. Please note that if
+ // buildDirectory has the same name as a directory inside the dart repo
+ // we will server files from the buildDirectory.
+ if (requestPath.toString().startsWith(buildDirectory.toString())) {
+ file = new File(requestPath.toNativePath());
+ }
if (requestPath.segments().contains(packagesDirName)) {
// Essentially implement the packages path rewriting, so we don't have
// to pass environment variables to the browsers.
diff --git a/tools/testing/dart/test_suite.dart b/tools/testing/dart/test_suite.dart
index 349a8a6..11b9ef1 100644
--- a/tools/testing/dart/test_suite.dart
+++ b/tools/testing/dart/test_suite.dart
@@ -812,6 +812,77 @@
};
}
+
+ /**
+ * _createUrlPathFromFile takes a [file], which is either located in the dart
+ * or in the build directory, and will return a String representing
+ * the relative path to either the dart or the build directory.
+ * Thus, the returned [String] will be the path component of the URL
+ * corresponding to [file] (the http server serves files relative to the
+ * dart/build directories).
+ */
+ String _createUrlPathFromFile(Path file) {
+ file = TestUtils.absolutePath(file);
+ var fileString = file.toString();
+
+ var relativeBuildDir = new Path(TestUtils.buildDir(configuration));
+ var buildDir = TestUtils.absolutePath(relativeBuildDir);
+ var dartDir = TestUtils.dartDir();
+
+ var pathComponent;
+ if (fileString.startsWith(buildDir.toString())) {
+ var fileRelativeToBuildDir = file.relativeTo(buildDir);
+ pathComponent = "$relativeBuildDir/$fileRelativeToBuildDir";
+ } else if (fileString.startsWith(dartDir.toString())) {
+ pathComponent = file.relativeTo(dartDir);
+ } else {
+ // Unreachable
+ Except.isTrue(false);
+ }
+ return "/$pathComponent";
+ }
+
+ void _getUriForBrowserTest(TestInformation info,
+ String pathComponent,
+ subtestNames,
+ subtestIndex) {
+ // Note: If we run test.py with the "--list" option, no http servers
+ // will be started. Therefore serverList is an empty list in this
+ // case. So we use PORT/CROSS_ORIGIN_PORT instead of real ports.
+ var serverPort = "PORT";
+ var crossOriginPort = "CROSS_ORIGIN_PORT";
+ if (!configuration['list']) {
+ serverPort = serverList[0].port.toString();
+ crossOriginPort = serverList[1].port.toString();
+ }
+
+ var url= 'http://127.0.0.1:$serverPort$pathComponent'
+ '?crossOriginPort=$crossOriginPort';
+ if (info.optionsFromFile['isMultiHtmlTest'] && subtestNames.length > 0) {
+ url= '${url}&group=${subtestNames[subtestIndex]}';
+ }
+ return url;
+ }
+
+ void _createWrapperFile(String dartWrapperFilename, dartLibraryFilename) {
+ File file = new File(dartWrapperFilename);
+ RandomAccessFile dartWrapper = file.openSync(FileMode.WRITE);
+
+ var usePackageImport = dartLibraryFilename.segments().contains("pkg");
+ var libraryPathComponent = _createUrlPathFromFile(dartLibraryFilename);
+ dartWrapper.writeStringSync(dartTestWrapper(usePackageImport,
+ libraryPathComponent));
+ dartWrapper.closeSync();
+ }
+
+ void _createLibraryWrapperFile(Path dartLibraryFilename, filePath) {
+ File file = new File(dartLibraryFilename.toNativePath());
+ RandomAccessFile dartLibrary = file.openSync(FileMode.WRITE);
+ dartLibrary.writeStringSync(
+ wrapDartTestInLibrary(filePath.relativeTo(TestUtils.dartDir())));
+ dartLibrary.closeSync();
+ }
+
/**
* The [StandardTestSuite] has support for tests that
* compile a test from Dart to JavaScript, and then run the resulting
@@ -867,18 +938,9 @@
if (!isLibraryDefinition) {
dartLibraryFilename = new Path(tempDir).append(
'test_as_library.dart');
- File file = new File(dartLibraryFilename.toNativePath());
- RandomAccessFile dartLibrary = file.openSync(FileMode.WRITE);
- dartLibrary.writeStringSync(
- wrapDartTestInLibrary(filePath, file.name));
- dartLibrary.closeSync();
+ _createLibraryWrapperFile(dartLibraryFilename, filePath);
}
-
- File file = new File(dartWrapperFilename);
- RandomAccessFile dartWrapper = file.openSync(FileMode.WRITE);
- dartWrapper.writeStringSync(
- dartTestWrapper(dartDir, file.name, dartLibraryFilename));
- dartWrapper.closeSync();
+ _createWrapperFile(dartWrapperFilename, dartLibraryFilename);
} else {
dartWrapperFilename = filename;
// TODO(whesse): Once test.py is retired, adjust the relative path in
@@ -895,8 +957,10 @@
}
htmlPath = '$tempDir/../$htmlFilename';
}
- final String scriptPath = (compiler == 'none') ?
+ String scriptPath = (compiler == 'none') ?
dartWrapperFilename : compiledDartWrapperFilename;
+ scriptPath = _createUrlPathFromFile(new Path(scriptPath));
+
// Create the HTML file for the test.
RandomAccessFile htmlTest = new File(htmlPath).openSync(FileMode.WRITE);
String content = null;
@@ -907,22 +971,13 @@
Path expectedOutput = null;
if (new File.fromPath(pngPath).existsSync()) {
expectedOutput = pngPath;
- // TODO(efortuna): Unify path libraries in test.dart.
- content = getHtmlLayoutContents(scriptType, pathLib.relative(scriptPath,
- from: pathLib.dirname(htmlPath)));
+ content = getHtmlLayoutContents(scriptType, new Path("$scriptPath"));
} else if (new File.fromPath(txtPath).existsSync()) {
expectedOutput = txtPath;
- content = getHtmlLayoutContents(scriptType, pathLib.relative(scriptPath,
- from: pathLib.dirname(htmlPath)));
+ content = getHtmlLayoutContents(scriptType, new Path("$scriptPath"));
} else {
- final htmlLocation = new Path(htmlPath);
- content = getHtmlContents(
- filename,
- dartDir.append('pkg/unittest/test_controller.js')
- .relativeTo(htmlLocation),
- dartDir.append('pkg/browser/lib/dart.js').relativeTo(htmlLocation),
- scriptType,
- new Path(scriptPath).relativeTo(htmlLocation));
+ content = getHtmlContents(filename, scriptType,
+ new Path("$scriptPath"));
}
htmlTest.writeStringSync(content);
htmlTest.closeSync();
@@ -962,35 +1017,11 @@
commandSet = [];
}
- List<String> args = <String>[];
- var basePath = TestUtils.dartDir().toString();
- if (!htmlPath.startsWith('/') && !htmlPath.startsWith('http')) {
- htmlPath = '/$htmlPath';
- }
- htmlPath = htmlPath.startsWith(basePath) ?
- htmlPath.substring(basePath.length) : htmlPath;
- String fullHtmlPath = htmlPath;
- var searchStr = '?';
- if (!htmlPath.startsWith('http')) {
- // Note: If we run test.py with the "--list" option, no http servers
- // will be started. Therefore serverList is an empty list in this
- // case. So we use PORT/CROSS_ORIGIN_PORT instead of real ports.
- var serverPort = "PORT";
- var crossOriginPort = "CROSS_ORIGIN_PORT";
- if (!configuration['list']) {
- serverPort = serverList[0].port.toString();
- crossOriginPort = serverList[1].port.toString();
- }
- fullHtmlPath = 'http://127.0.0.1:$serverPort$htmlPath${searchStr}'
- 'crossOriginPort=$crossOriginPort';
- searchStr = '&';
- }
- if (info.optionsFromFile['isMultiHtmlTest']
- && subtestNames.length > 0) {
- fullHtmlPath = '${fullHtmlPath}${searchStr}group='
- '${subtestNames[subtestIndex]}';
- }
+ var htmlPath_subtest = _createUrlPathFromFile(new Path(htmlPath));
+ var fullHtmlPath = _getUriForBrowserTest(info, htmlPath_subtest,
+ subtestNames, subtestIndex);
+ List<String> args = <String>[];
if (TestUtils.usesWebDriver(runtime)) {
args = [
dartDir.append('tools/testing/run_selenium.py').toNativePath(),
@@ -1125,8 +1156,7 @@
var minified = configuration['minified'] ? '-minified' : '';
var dirName = "${configuration['compiler']}-${configuration['runtime']}"
"$checked$minified";
- Path generatedTestPath = new Path(dartDir.toNativePath())
- .append(buildDir)
+ Path generatedTestPath = new Path(buildDir)
.append('generated_tests')
.append(dirName)
.append(testUniqueName);
@@ -1816,6 +1846,10 @@
const ['d8', 'jsshell'].contains(runtime);
static String buildDir(Map configuration) {
+ // FIXME(kustermann,ricow): Our code assumes that the returned 'buildDir'
+ // is relative to the current working directory.
+ // Thus, if we pass in an absolute path (e.g. '--build-directory=/tmp/out')
+ // we get into trouble.
if (configuration['build_directory'] != '') {
return configuration['build_directory'];
}
diff --git a/utils/apidoc/apidoc.dart b/utils/apidoc/apidoc.dart
index bf6324f..36ef96b 100644
--- a/utils/apidoc/apidoc.dart
+++ b/utils/apidoc/apidoc.dart
@@ -258,16 +258,6 @@
super.docLibrary(library);
}
- /** Override definition from parent class to strip out annotation tags. */
- doc.DocComment createDocComment(String text,
- [ClassMirror inheritedFrom]) {
- String strippedText =
- text.replaceAll(new RegExp("@([a-zA-Z]+) ([^;]+)(?:;|\$)"),
- '').trim();
- if (strippedText.isEmpty) return null;
- return super.createDocComment(strippedText, inheritedFrom);
- }
-
doc.DocComment getLibraryComment(LibraryMirror library) {
return super.getLibraryComment(library);
}
diff --git a/utils/apidoc/html_diff.dart b/utils/apidoc/html_diff.dart
index c9aaf84..d6a5067 100644
--- a/utils/apidoc/html_diff.dart
+++ b/utils/apidoc/html_diff.dart
@@ -156,8 +156,8 @@
final domNameMetadata = findMetadata(htmlType.metadata, 'DomName');
if (domNameMetadata != null) {
var domNames = <String>[];
- var tags = deprecatedFutureValue(domNameMetadata.getField('name'));
- for (var s in tags.reflectee.split(',')) {
+ var names = deprecatedFutureValue(domNameMetadata.getField('name'));
+ for (var s in names.reflectee.split(',')) {
domNames.add(s.trim());
}
@@ -180,8 +180,8 @@
final domNameMetadata = findMetadata(htmlMember.metadata, 'DomName');
if (domNameMetadata != null) {
var domNames = <String>[];
- var tags = deprecatedFutureValue(domNameMetadata.getField('name'));
- for (var s in tags.reflectee.split(',')) {
+ var names = deprecatedFutureValue(domNameMetadata.getField('name'));
+ for (var s in names.reflectee.split(',')) {
domNames.add(s.trim());
}
diff --git a/utils/pub/entrypoint.dart b/utils/pub/entrypoint.dart
index 843d41d..6d7ffe0 100644
--- a/utils/pub/entrypoint.dart
+++ b/utils/pub/entrypoint.dart
@@ -157,13 +157,19 @@
var id = lockFile.packages[ref.name];
visited.add(ref.name);
- var future = cache.describe(id);
+ var future;
+ if (ref.name == root.name) {
+ future = new Future<Pubspec>.immediate(root.pubspec);
+ } else {
+ future = cache.describe(id);
+ }
group.add(future.then(visitPackage));
}
return pubspec;
}
+ visited.add(root.name);
visitPackage(root.pubspec);
return group.future;
});
diff --git a/utils/pub/hosted_source.dart b/utils/pub/hosted_source.dart
index 2db9cc8..ef56462 100644
--- a/utils/pub/hosted_source.dart
+++ b/utils/pub/hosted_source.dart
@@ -62,31 +62,29 @@
/// Downloads a package from the site and unpacks it.
Future<bool> install(PackageId id, String destPath) {
- var parsedDescription = _parseDescription(id.description);
- var name = parsedDescription.first;
- var url = parsedDescription.last;
+ return defer(() {
+ var parsedDescription = _parseDescription(id.description);
+ var name = parsedDescription.first;
+ var url = parsedDescription.last;
- var fullUrl = "$url/packages/$name/versions/${id.version}.tar.gz";
+ var fullUrl = "$url/packages/$name/versions/${id.version}.tar.gz";
- log.message('Downloading $id...');
+ log.message('Downloading $id...');
- // Download and extract the archive to a temp directory.
- var tempDir;
- return Future.wait([
- httpClient.send(new http.Request("GET", Uri.parse(fullUrl)))
- .then((response) => response.stream),
- systemCache.createTempDir()
- ]).then((args) {
- var stream = args[0];
- tempDir = args[1];
- return timeout(extractTarGz(stream, tempDir), HTTP_TIMEOUT,
- 'fetching URL "$fullUrl"');
- }).then((_) {
- // Now that the install has succeeded, move it to the real location in
- // the cache. This ensures that we don't leave half-busted ghost
- // directories in the user's pub cache if an install fails.
- return renameDir(tempDir, destPath);
- }).then((_) => true);
+ // Download and extract the archive to a temp directory.
+ var tempDir = systemCache.createTempDir();
+ return httpClient.send(new http.Request("GET", Uri.parse(fullUrl)))
+ .then((response) => response.stream)
+ .then((stream) {
+ return timeout(extractTarGz(stream, tempDir), HTTP_TIMEOUT,
+ 'fetching URL "$fullUrl"');
+ }).then((_) {
+ // Now that the install has succeeded, move it to the real location in
+ // the cache. This ensures that we don't leave half-busted ghost
+ // directories in the user's pub cache if an install fails.
+ return renameDir(tempDir, destPath);
+ }).then((_) => true);
+ });
}
/// The system cache directory for the hosted source contains subdirectories
diff --git a/utils/pub/io.dart b/utils/pub/io.dart
index 60f6d77..d3fa00bb 100644
--- a/utils/pub/io.dart
+++ b/utils/pub/io.dart
@@ -157,10 +157,10 @@
/// suffix appended to it. If [dir] is not provided, a temp directory will be
/// created in a platform-dependent temporary location. Returns a [Future] that
/// completes when the directory is created.
-Future<Directory> createTempDir([dir = '']) {
- dir = _getDirectory(dir);
- return log.ioAsync("create temp directory ${dir.path}",
- dir.createTemp());
+Directory createTempDir([dir = '']) {
+ var tempDir = _getDirectory(dir).createTempSync();
+ log.io("Created temp directory ${tempDir.path}");
+ return tempDir;
}
/// Asynchronously recursively deletes [dir], which can be a [String] or a
@@ -425,6 +425,21 @@
.then((line) => new RegExp(r"^[yY]").hasMatch(line));
}
+/// Reads and discards all output from [inputStream]. Returns a [Future] that
+/// completes when the stream is closed.
+Future drainInputStream(InputStream inputStream) {
+ var completer = new Completer();
+ if (inputStream.closed) {
+ completer.complete();
+ return completer.future;
+ }
+
+ inputStream.onClosed = () => completer.complete();
+ inputStream.onData = inputStream.read;
+ inputStream.onError = (error) => completer.completeError(error);
+ return completer.future;
+}
+
/// Wraps [stream] in a single-subscription [Stream] that emits the same data.
ByteStream wrapInputStream(InputStream stream) {
var controller = new StreamController();
@@ -707,14 +722,15 @@
/// Creates a temporary directory and passes its path to [fn]. Once the [Future]
/// returned by [fn] completes, the temporary directory and all its contents
/// will be deleted.
+///
+/// Returns a future that completes to the value that the future returned from
+/// [fn] completes to.
Future withTempDir(Future fn(String path)) {
- var tempDir;
- return createTempDir().then((dir) {
- tempDir = dir;
- return fn(tempDir.path);
- }).whenComplete(() {
- log.fine('Cleaning up temp directory ${tempDir.path}.');
- return deleteDir(tempDir);
+ return defer(() {
+ var tempDir = createTempDir();
+ return fn(tempDir.path).whenComplete(() {
+ return deleteDir(tempDir);
+ });
});
}
@@ -764,51 +780,44 @@
var pathTo7zip = '../../third_party/7zip/7za.exe';
var command = relativeToPub(pathTo7zip);
- var tempDir;
-
- // TODO(rnystrom): Use withTempDir().
- return createTempDir().then((temp) {
+ return withTempDir((tempDir) {
// Write the archive to a temp file.
- tempDir = temp;
- return createFileFromStream(stream, join(tempDir, 'data.tar.gz'));
- }).then((_) {
- // 7zip can't unarchive from gzip -> tar -> destination all in one step
- // first we un-gzip it to a tar file.
- // Note: Setting the working directory instead of passing in a full file
- // path because 7zip says "A full path is not allowed here."
- return runProcess(command, ['e', 'data.tar.gz'], workingDir: tempDir);
- }).then((result) {
- if (result.exitCode != 0) {
- throw 'Could not un-gzip (exit code ${result.exitCode}). Error:\n'
- '${Strings.join(result.stdout, "\n")}\n'
- '${Strings.join(result.stderr, "\n")}';
- }
- // Find the tar file we just created since we don't know its name.
- return listDir(tempDir);
- }).then((files) {
- var tarFile;
- for (var file in files) {
- if (path.extension(file) == '.tar') {
- tarFile = file;
- break;
+ return createFileFromStream(stream, join(tempDir, 'data.tar.gz')).then((_) {
+ // 7zip can't unarchive from gzip -> tar -> destination all in one step
+ // first we un-gzip it to a tar file.
+ // Note: Setting the working directory instead of passing in a full file
+ // path because 7zip says "A full path is not allowed here."
+ return runProcess(command, ['e', 'data.tar.gz'], workingDir: tempDir);
+ }).then((result) {
+ if (result.exitCode != 0) {
+ throw 'Could not un-gzip (exit code ${result.exitCode}). Error:\n'
+ '${Strings.join(result.stdout, "\n")}\n'
+ '${Strings.join(result.stderr, "\n")}';
}
- }
+ // Find the tar file we just created since we don't know its name.
+ return listDir(tempDir);
+ }).then((files) {
+ var tarFile;
+ for (var file in files) {
+ if (path.extension(file) == '.tar') {
+ tarFile = file;
+ break;
+ }
+ }
- if (tarFile == null) throw 'The gzip file did not contain a tar file.';
+ if (tarFile == null) throw 'The gzip file did not contain a tar file.';
- // Untar the archive into the destination directory.
- return runProcess(command, ['x', tarFile], workingDir: destination);
- }).then((result) {
- if (result.exitCode != 0) {
- throw 'Could not un-tar (exit code ${result.exitCode}). Error:\n'
- '${Strings.join(result.stdout, "\n")}\n'
- '${Strings.join(result.stderr, "\n")}';
- }
-
- log.fine('Clean up 7zip temp directory ${tempDir.path}.');
- // TODO(rnystrom): Should also delete this if anything fails.
- return deleteDir(tempDir);
- }).then((_) => true);
+ // Untar the archive into the destination directory.
+ return runProcess(command, ['x', tarFile], workingDir: destination);
+ }).then((result) {
+ if (result.exitCode != 0) {
+ throw 'Could not un-tar (exit code ${result.exitCode}). Error:\n'
+ '${Strings.join(result.stdout, "\n")}\n'
+ '${Strings.join(result.stderr, "\n")}';
+ }
+ return true;
+ });
+ });
}
/// Create a .tar.gz archive from a list of entries. Each entry can be a
diff --git a/utils/pub/log.dart b/utils/pub/log.dart
index 43499ef..06a4748 100644
--- a/utils/pub/log.dart
+++ b/utils/pub/log.dart
@@ -208,7 +208,7 @@
_logToStream(stderrSink, entry, showLabel: true);
}
-void _logToStream(Sink<List<int>> sink, Entry entry, {bool showLabel}) {
+void _logToStream(StreamSink<List<int>> sink, Entry entry, {bool showLabel}) {
bool firstLine = true;
for (var line in entry.lines) {
if (showLabel) {
diff --git a/utils/pub/pub.dart b/utils/pub/pub.dart
index db628d0..302420f 100644
--- a/utils/pub/pub.dart
+++ b/utils/pub/pub.dart
@@ -121,20 +121,37 @@
cacheDir = '${Platform.environment['HOME']}/.pub-cache';
}
- var cache = new SystemCache.withSources(cacheDir);
+ validatePlatform().then((_) {
+ var cache = new SystemCache.withSources(cacheDir);
- // Select the command.
- var command = pubCommands[globalOptions.rest[0]];
- if (command == null) {
- log.error('Could not find a command named "${globalOptions.rest[0]}".');
- log.error('Run "pub help" to see available commands.');
- exit(exit_codes.USAGE);
- return;
- }
+ // Select the command.
+ var command = pubCommands[globalOptions.rest[0]];
+ if (command == null) {
+ log.error('Could not find a command named "${globalOptions.rest[0]}".');
+ log.error('Run "pub help" to see available commands.');
+ exit(exit_codes.USAGE);
+ return;
+ }
- var commandArgs =
- globalOptions.rest.getRange(1, globalOptions.rest.length - 1);
- command.run(cache, globalOptions, commandArgs);
+ var commandArgs =
+ globalOptions.rest.getRange(1, globalOptions.rest.length - 1);
+ command.run(cache, globalOptions, commandArgs);
+ });
+}
+
+/// Checks that pub is running on a supported platform. If it isn't, it prints
+/// an error message and exits. Completes when the validation is done.
+Future validatePlatform() {
+ return defer(() {
+ if (Platform.operatingSystem != 'windows') return;
+
+ return runProcess('ver', []).then((result) {
+ if (result.stdout.join('\n').contains('XP')) {
+ log.error('Sorry, but pub is not supported on Windows XP.');
+ exit(exit_codes.USAGE);
+ }
+ });
+ });
}
/// Displays usage information for the app.
diff --git a/utils/pub/system_cache.dart b/utils/pub/system_cache.dart
index 4041e40..13e6b8d 100644
--- a/utils/pub/system_cache.dart
+++ b/utils/pub/system_cache.dart
@@ -63,6 +63,8 @@
/// Gets the package identified by [id]. If the package is already cached,
/// reads it from the cache. Otherwise, requests it from the source.
Future<Pubspec> describe(PackageId id) {
+ if (id.isRoot) throw new ArgumentError("Cannot describe the root package.");
+
// Try to get it from the system cache first.
if (id.source.shouldCache) {
return id.systemCacheDirectory.then((packageDir) {
@@ -99,11 +101,9 @@
/// packages into while installing. It uses this instead of the OS's system
/// temp directory to ensure that it's on the same volume as the pub system
/// cache so that it can move the directory from it.
- Future<Directory> createTempDir() {
- return defer(() {
- var temp = ensureDir(tempDir);
- return io.createTempDir(join(temp, 'dir'));
- });
+ Directory createTempDir() {
+ var temp = ensureDir(tempDir);
+ return io.createTempDir(join(temp, 'dir'));
}
/// Delete's the system cache's internal temp directory.
diff --git a/utils/tests/pub/pub_lish_test.dart b/utils/tests/pub/pub_lish_test.dart
index 7101d91..482b616 100644
--- a/utils/tests/pub/pub_lish_test.dart
+++ b/utils/tests/pub/pub_lish_test.dart
@@ -38,7 +38,9 @@
server.handle('POST', '/upload', (request, response) {
// TODO(nweiz): Once a multipart/form-data parser in Dart exists, validate
// that the request body is correctly formatted. See issue 6952.
- return server.url.then((url) {
+ return drainInputStream(request.inputStream).then((_) {
+ return server.url;
+ }).then((url) {
response.statusCode = 302;
response.headers.set('location', url.resolve('/create').toString());
response.outputStream.close();
@@ -260,11 +262,13 @@
handleUploadForm(server);
server.handle('POST', '/upload', (request, response) {
- response.statusCode = 400;
- response.headers.contentType = new ContentType('application', 'xml');
- response.outputStream.writeString('<Error><Message>Your request sucked.'
- '</Message></Error>');
- response.outputStream.close();
+ return drainInputStream(request.inputStream).then((_) {
+ response.statusCode = 400;
+ response.headers.contentType = new ContentType('application', 'xml');
+ response.outputStream.writeString('<Error><Message>Your request sucked.'
+ '</Message></Error>');
+ response.outputStream.close();
+ });
});
// TODO(nweiz): This should use the server's error message once the client
@@ -282,8 +286,10 @@
handleUploadForm(server);
server.handle('POST', '/upload', (request, response) {
- // don't set the location header
- response.outputStream.close();
+ return drainInputStream(request.inputStream).then((_) {
+ // Don't set the location header.
+ response.outputStream.close();
+ });
});
expectLater(pub.nextErrLine(), equals('Failed to upload the package.'));
diff --git a/utils/tests/pub/pub_test.dart b/utils/tests/pub/pub_test.dart
index bbc8e40..3a9db1fd 100644
--- a/utils/tests/pub/pub_test.dart
+++ b/utils/tests/pub/pub_test.dart
@@ -42,6 +42,8 @@
''';
main() {
+ initConfig();
+
integration('running pub with no command displays usage', () {
schedulePub(args: [], output: USAGE_STRING);
});
diff --git a/utils/tests/pub/sdk_constraint_test.dart b/utils/tests/pub/sdk_constraint_test.dart
index 3f934b9..33d4686 100644
--- a/utils/tests/pub/sdk_constraint_test.dart
+++ b/utils/tests/pub/sdk_constraint_test.dart
@@ -117,5 +117,40 @@
or adding a version constraint to use an older version of a package.
""");
});
+
+ integration("handles a circular dependency on the root package", () {
+ // Using an SDK source, but this should be true of all sources.
+ dir(sdkPath, [
+ dir("pkg", [
+ dir("foo", [
+ libPubspec("foo", "0.0.1", sdk: ">3.0.0", deps: [
+ {"sdk": "myapp"}
+ ]),
+ libDir("foo")
+ ])
+ ])
+ ]).scheduleCreate();
+
+ dir(appPath, [
+ pubspec({
+ "name": "myapp",
+ "dependencies": {
+ "foo": { "sdk": "foo" }
+ },
+ "environment": {"sdk": ">2.0.0"}
+ })
+ ]).scheduleCreate();
+
+ schedulePub(args: [command],
+ error:
+ """
+ Some packages are not compatible with your SDK version 0.1.2+3:
+ - 'myapp' requires >2.0.0
+ - 'foo' requires >3.0.0
+
+ You may be able to resolve this by upgrading to the latest Dart SDK
+ or adding a version constraint to use an older version of a package.
+ """);
+ });
}
}
diff --git a/utils/tests/pub/test_pub.dart b/utils/tests/pub/test_pub.dart
index c799ce7..63301f4 100644
--- a/utils/tests/pub/test_pub.dart
+++ b/utils/tests/pub/test_pub.dart
@@ -494,24 +494,21 @@
// Run all of the scheduled tasks. If an error occurs, it will propagate
// through the futures back up to here where we can hand it off to unittest.
var asyncDone = expectAsync0(() {});
- var createdSandboxDir;
- _setUpSandbox().then((sandboxDir) {
- createdSandboxDir = sandboxDir;
- return timeout(_runScheduled(sandboxDir, _scheduled),
- _TIMEOUT, 'waiting for a test to complete');
- }).catchError((e) {
- return _runScheduled(createdSandboxDir, _scheduledOnException).then((_) {
+ var sandboxDir = createTempDir();
+ return timeout(_runScheduled(sandboxDir, _scheduled),
+ _TIMEOUT, 'waiting for a test to complete').catchError((e) {
+ return _runScheduled(sandboxDir, _scheduledOnException).then((_) {
// Rethrow the original error so it keeps propagating.
throw e;
});
}).whenComplete(() {
// Clean up after ourselves. Do this first before reporting back to
// unittest because it will advance to the next test immediately.
- return _runScheduled(createdSandboxDir, _scheduledCleanup).then((_) {
+ return _runScheduled(sandboxDir, _scheduledCleanup).then((_) {
_scheduled = null;
_scheduledCleanup = null;
_scheduledOnException = null;
- if (createdSandboxDir != null) return deleteDir(createdSandboxDir);
+ if (sandboxDir != null) return deleteDir(sandboxDir);
});
}).then((_) {
// If we got here, the test completed successfully so tell unittest so.
@@ -680,8 +677,6 @@
});
}
-Future<Directory> _setUpSandbox() => createTempDir();
-
Future _runScheduled(Directory parentDir, List<_ScheduledEvent> scheduled) {
if (scheduled == null) return new Future.immediate(null);
var iterator = scheduled.iterator;
@@ -1104,17 +1099,13 @@
/// Creates the files and directories within this tar file, then archives
/// them, compresses them, and saves the result to [parentDir].
Future<File> create(parentDir) {
- // TODO(rnystrom): Use withTempDir().
- var tempDir;
- return createTempDir().then((_tempDir) {
- tempDir = _tempDir;
- return Future.wait(contents.map((child) => child.create(tempDir)));
- }).then((createdContents) {
- return createTarGz(createdContents, baseDir: tempDir).toBytes();
- }).then((bytes) {
- return new File(join(parentDir, _stringName)).writeAsBytes(bytes);
- }).then((file) {
- return deleteDir(tempDir).then((_) => file);
+ return withTempDir((tempDir) {
+ return Future.wait(contents.map((child) => child.create(tempDir)))
+ .then((createdContents) {
+ return createTarGz(createdContents, baseDir: tempDir).toBytes();
+ }).then((bytes) {
+ return new File(join(parentDir, _stringName)).writeAsBytes(bytes);
+ });
});
}
@@ -1136,16 +1127,11 @@
}
var controller = new StreamController<List<int>>();
- var tempDir;
- // TODO(rnystrom): Use withTempDir() here.
// TODO(nweiz): propagate any errors to the return value. See issue 3657.
- createTempDir().then((_tempDir) {
- tempDir = _tempDir;
- return create(tempDir);
- }).then((tar) {
- var sourceStream = tar.openInputStream();
- return store(wrapInputStream(sourceStream), controller).then((_) {
- tempDir.delete(recursive: true);
+ withTempDir((tempDir) {
+ return create(tempDir).then((tar) {
+ var sourceStream = tar.openInputStream();
+ return store(wrapInputStream(sourceStream), controller);
});
});
return new ByteStream(controller.stream);