Version 0.3.6.2 .
svn merge -r 18445:18527 https://dart.googlecode.com/svn/branches/bleeding_edge trunk
git-svn-id: http://dart.googlecode.com/svn/trunk@18539 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/dart.gyp b/dart.gyp
index d206fcc..c988d74 100644
--- a/dart.gyp
+++ b/dart.gyp
@@ -95,6 +95,17 @@
],
},
{
+ # This is the target that is built on the dartc bots.
+ # It must depend on anything that is required by dartc
+ # tests.
+ 'target_name': 'dartc_bot',
+ 'type': 'none',
+ 'dependencies': [
+ 'create_sdk',
+ 'packages',
+ ],
+ },
+ {
# This is the target that is built on the dart2js build bots.
# It must depend on anything that is required by the dart2js
# test suites.
diff --git a/pkg/intl/lib/bidi_utils.dart b/pkg/intl/lib/bidi_utils.dart
index b6bb007..35d62b7 100644
--- a/pkg/intl/lib/bidi_utils.dart
+++ b/pkg/intl/lib/bidi_utils.dart
@@ -353,22 +353,6 @@
}
/**
- * Find the first index in [str] of the first closing parenthesis that does
- * not match an opening parenthesis.
- */
- static int _unmatchedParenIndex(String str) {
- int sum = 0;
- int index = 0;
- while (sum >= 0 || index > str.length) {
- int char = str.charCodeAt(index);
- if (char == '('.charCodeAt(0)) sum++;
- else if (char == ')'.charCodeAt(0)) sum--;
- index++;
- }
- return index;
- }
-
- /**
* Replace the double and single quote directly after a Hebrew character in
* [str] with GERESH and GERSHAYIM. This is most likely the user's intention.
*/
diff --git a/pkg/intl/lib/number_format.dart b/pkg/intl/lib/number_format.dart
index 4f75d63..76f8afa 100644
--- a/pkg/intl/lib/number_format.dart
+++ b/pkg/intl/lib/number_format.dart
@@ -258,10 +258,14 @@
}
/** Returns the code point for the character '0'. */
- int get _zero => '0'.charCodes[0];
+ int get _zero => '0'.codeUnits.first;
/** Returns the code point for the locale's zero digit. */
- int get _localeZero => symbols.ZERO_DIGIT.charCodeAt(0);
+ // Note that there is a slight risk of a locale's zero digit not fitting
+ // into a single code unit, but it seems very unlikely, and if it did,
+ // there's a pretty good chance that our assumptions about being able to do
+ // arithmetic on it would also be invalid.
+ int get _localeZero => symbols.ZERO_DIGIT.codeUnits.first;
/**
* Returns the prefix for [x] based on whether it's positive or negative.
diff --git a/pkg/oauth2/lib/src/utils.dart b/pkg/oauth2/lib/src/utils.dart
index bcff589..83fe2b7 100644
--- a/pkg/oauth2/lib/src/utils.dart
+++ b/pkg/oauth2/lib/src/utils.dart
@@ -113,4 +113,5 @@
}
/// Returns a [Future] that asynchronously completes to `null`.
-Future get async => new Future.delayed(0, () => null);
+Future get async => new Future.delayed(const Duration(milliseconds: 0),
+ () => null);
diff --git a/pkg/pkg.status b/pkg/pkg.status
index a241322..69fbaee 100644
--- a/pkg/pkg.status
+++ b/pkg/pkg.status
@@ -49,7 +49,6 @@
[ $runtime == vm ]
intl/test/find_default_locale_browser_test: Skip
intl/test/date_time_format_http_request_test: Skip
-serialization/test/serialization_test: Pass, Fail # Temporary workaround for flakiness
[ $runtime == vm && $system == windows ]
intl/test/find_default_locale_standalone_test: Fail # Issue 8110
diff --git a/pkg/serialization/lib/src/format.dart b/pkg/serialization/lib/src/format.dart
index ab602c9..a1726f0 100644
--- a/pkg/serialization/lib/src/format.dart
+++ b/pkg/serialization/lib/src/format.dart
@@ -154,9 +154,15 @@
* to turn References into a nested List/Map.
*/
jsonifyEntry(map, Writer w) {
+ // Note, if this is a Map, and the key might be a reference, we need to
+ // bend over backwards to avoid concurrent modifications. Non-string keys
+ // won't actually work if we try to write this to json, but might happen
+ // if e.g. sending between isolates.
+ var updates = new Map();
keysAndValues(map).forEach((key, value) {
- if (value is Reference) map[key] = w.stateForReference(value);
+ if (value is Reference) updates[key] = w.stateForReference(value);
});
+ updates.forEach((k, v) => map[k] = v);
}
/**
diff --git a/pkg/serialization/test/serialization_test.dart b/pkg/serialization/test/serialization_test.dart
index d45f562..5a9cc49 100644
--- a/pkg/serialization/test/serialization_test.dart
+++ b/pkg/serialization/test/serialization_test.dart
@@ -386,6 +386,20 @@
expect(a2.city, "Seattle");
});
+ test("Straight JSON format, non-string key", () {
+ // This tests what happens if we have a key that's not a string. That's
+ // not allowed by json, so we don't actually turn it into a json string,
+ // but someone might reasonably convert to a json-able structure without
+ // going through the string representation.
+ var p1 = new Person()..name = 'Alice'..address = a1;
+ var s = new Serialization()
+ ..addRule(new PersonRuleReturningMapWithNonStringKey());
+ var p2 = writeAndReadBack(s,
+ new SimpleJsonFormat(storeRoundTripInfo: true), p1);
+ expect(p2.name, "Alice");
+ expect(p2.address.street, "N 34th");
+ });
+
test("Root is a Map", () {
// Note that we can't use the usual round-trip test because it has cycles.
var p1 = new Person()..name = 'Alice'..address = a1;
@@ -704,3 +718,31 @@
node.children = state[2];
}
}
+
+/**
+ * This is a rather silly rule which stores the address data in a map,
+ * but inverts the keys and values, so we look up values and find the
+ * corresponding key. This will lead to maps that aren't allowed in JSON,
+ * and which have keys that need to be dereferenced.
+ */
+class PersonRuleReturningMapWithNonStringKey extends CustomRule {
+ appliesTo(instance, _) => instance is Person;
+ getState(instance) {
+ return new Map()
+ ..[instance.name] = "name"
+ ..[instance.address] = "address";
+ }
+ create(state) => new Person();
+ setState(Person a, state) {
+ a.name = findValue("name", state);
+ a.address = findValue("address", state);
+ }
+ findValue(String key, Map state) {
+ var answer;
+ for (var each in state.keys) {
+ var value = state[each];
+ if (value == key) return each;
+ }
+ return null;
+ }
+}
diff --git a/runtime/bin/directory_win.cc b/runtime/bin/directory_win.cc
index 9d8f6f3..84242c6 100644
--- a/runtime/bin/directory_win.cc
+++ b/runtime/bin/directory_win.cc
@@ -9,51 +9,75 @@
#include "bin/log.h"
-// Forward declaration.
+class PathBuffer {
+ public:
+ PathBuffer() : length(0) { }
+
+ wchar_t data[MAX_PATH + 1];
+ int length;
+
+ bool Add(const wchar_t* name) {
+ size_t written = _snwprintf(data + length,
+ MAX_PATH - length,
+ L"%s",
+ name);
+ data[MAX_PATH] = L'\0';
+ if (written == wcsnlen(name, MAX_PATH + 1)) {
+ length += written;
+ return true;
+ } else {
+ SetLastError(ERROR_BUFFER_OVERFLOW);
+ return false;
+ }
+ }
+
+ void Reset(int new_length) {
+ length = new_length;
+ data[length] = L'\0';
+ }
+};
+
+
+// Forward declarations.
static bool ListRecursively(const wchar_t* dir_name,
bool recursive,
DirectoryListing* listing);
static bool DeleteRecursively(const wchar_t* dir_name);
+static void PostError(DirectoryListing* listing,
+ const wchar_t* dir_name) {
+ const char* utf8_path = StringUtils::WideToUtf8(dir_name);
+ listing->HandleError(utf8_path);
+ free(const_cast<char*>(utf8_path));
+}
+
+
static bool HandleDir(wchar_t* dir_name,
- wchar_t* path,
- int path_length,
+ PathBuffer* path,
bool recursive,
DirectoryListing* listing) {
- if (wcscmp(dir_name, L".") != 0 &&
- wcscmp(dir_name, L"..") != 0) {
- size_t written = _snwprintf(path + path_length,
- MAX_PATH - path_length,
- L"%s",
- dir_name);
- if (written != wcslen(dir_name)) {
- return false;
- }
- char* utf8_path = StringUtils::WideToUtf8(path);
- bool ok = listing->HandleDirectory(utf8_path);
- free(utf8_path);
- if (!ok) return ok;
- if (recursive) {
- return ListRecursively(path, recursive, listing);
- }
+ if (wcscmp(dir_name, L".") == 0) return true;
+ if (wcscmp(dir_name, L"..") == 0) return true;
+ if (!path->Add(dir_name)) {
+ PostError(listing, path->data);
+ return false;
}
- return true;
+ char* utf8_path = StringUtils::WideToUtf8(path->data);
+ bool ok = listing->HandleDirectory(utf8_path);
+ free(utf8_path);
+ return ok && (!recursive || ListRecursively(path->data, recursive, listing));
}
static bool HandleFile(wchar_t* file_name,
- wchar_t* path,
- int path_length,
+ PathBuffer* path,
DirectoryListing* listing) {
- size_t written = _snwprintf(path + path_length,
- MAX_PATH - path_length,
- L"%s",
- file_name);
- if (written != wcslen(file_name)) {
+ if (!path->Add(file_name)) {
+ PostError(listing, path->data);
return false;
- };
- char* utf8_path = StringUtils::WideToUtf8(path);
+ }
+ char* utf8_path = StringUtils::WideToUtf8(path->data);
bool ok = listing->HandleFile(utf8_path);
free(utf8_path);
return ok;
@@ -61,55 +85,42 @@
static bool HandleEntry(LPWIN32_FIND_DATAW find_file_data,
- wchar_t* path,
- int path_length,
+ PathBuffer* path,
bool recursive,
DirectoryListing* listing) {
DWORD attributes = find_file_data->dwFileAttributes;
if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
return HandleDir(find_file_data->cFileName,
path,
- path_length,
recursive,
listing);
} else {
- return HandleFile(find_file_data->cFileName, path, path_length, listing);
+ return HandleFile(find_file_data->cFileName, path, listing);
}
}
-// ComputeFullSearchPath must be called with a path array of size at
-// least MAX_PATH.
-static bool ComputeFullSearchPath(const wchar_t* dir_name,
- wchar_t* path,
- int* path_length) {
+static PathBuffer* ComputeFullSearchPath(const wchar_t* dir_name) {
// GetFullPathName only works in a multi-threaded environment if
// SetCurrentDirectory is not used. We currently have no plan for
// exposing SetCurrentDirectory.
- size_t written = GetFullPathNameW(dir_name, MAX_PATH, path, NULL);
+ PathBuffer* path = new PathBuffer();
+
+ size_t written = GetFullPathNameW(dir_name, MAX_PATH + 1, path->data, NULL);
// GetFullPathName only accepts input strings of size less than
// MAX_PATH and returns 0 to indicate failure for paths longer than
// that. Therefore the path buffer is always big enough.
if (written == 0 || written > MAX_PATH) {
- return false;
+ delete path;
+ return NULL;
}
- *path_length = written;
- written = _snwprintf(path + *path_length,
- MAX_PATH - *path_length,
- L"%s",
- L"\\*");
- if (written != 2) {
- return false;
+ path->length = written;
+ if (path->Add(L"\\*")) {
+ return path;
+ } else {
+ delete path;
+ return NULL;
}
- *path_length += written;
- return true;
-}
-
-static void PostError(DirectoryListing* listing,
- const wchar_t* dir_name) {
- const char* utf8_path = StringUtils::WideToUtf8(dir_name);
- listing->HandleError(utf8_path);
- free(const_cast<char*>(utf8_path));
}
@@ -121,38 +132,35 @@
// 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.
- wchar_t* path = static_cast<wchar_t*>(malloc(MAX_PATH * sizeof(wchar_t)));
- int path_length = 0;
- bool valid = ComputeFullSearchPath(dir_name, path, &path_length);
- if (!valid) {
+ PathBuffer* path = ComputeFullSearchPath(dir_name);
+ if (path == NULL) {
PostError(listing, dir_name);
- free(path);
+ delete path;
return false;
}
WIN32_FIND_DATAW find_file_data;
- HANDLE find_handle = FindFirstFileW(path, &find_file_data);
+ HANDLE find_handle = FindFirstFileW(path->data, &find_file_data);
// Adjust the path by removing the '*' used for the search.
- path_length -= 1;
- path[path_length] = '\0';
+ path->Reset(path->length - 1);
if (find_handle == INVALID_HANDLE_VALUE) {
- PostError(listing, path);
- free(path);
+ PostError(listing, path->data);
+ delete path;
return false;
}
+ int path_length = path->length;
bool success = HandleEntry(&find_file_data,
path,
- path_length,
recursive,
listing);
while ((FindNextFileW(find_handle, &find_file_data) != 0)) {
+ path->Reset(path_length); // HandleEntry adds the entry name to path.
success = HandleEntry(&find_file_data,
path,
- path_length,
recursive,
listing) && success;
}
@@ -166,24 +174,16 @@
success = false;
PostError(listing, dir_name);
}
- free(path);
+ delete path;
return success;
}
-static bool DeleteFile(wchar_t* file_name,
- wchar_t* path,
- int path_length) {
- size_t written = _snwprintf(path + path_length,
- MAX_PATH - path_length,
- L"%s",
- file_name);
- if (written != wcslen(file_name)) {
- return false;
- }
+static bool DeleteFile(wchar_t* file_name, PathBuffer* path) {
+ if (!path->Add(file_name)) return false;
- if (DeleteFileW(path) != 0) {
+ if (DeleteFileW(path->data) != 0) {
return true;
}
@@ -191,7 +191,7 @@
// again. This mirrors Linux/Mac where a directory containing read-only files
// can still be recursively deleted.
if (GetLastError() == ERROR_ACCESS_DENIED) {
- DWORD attributes = GetFileAttributesW(path);
+ DWORD attributes = GetFileAttributesW(path->data);
if (attributes == INVALID_FILE_ATTRIBUTES) {
return false;
}
@@ -199,11 +199,11 @@
if ((attributes & FILE_ATTRIBUTE_READONLY) == FILE_ATTRIBUTE_READONLY) {
attributes &= ~FILE_ATTRIBUTE_READONLY;
- if (SetFileAttributesW(path, attributes) == 0) {
+ if (SetFileAttributesW(path->data, attributes) == 0) {
return false;
}
- return DeleteFileW(path) != 0;
+ return DeleteFileW(path->data) != 0;
}
}
@@ -211,33 +211,20 @@
}
-static bool DeleteDir(wchar_t* dir_name,
- wchar_t* path,
- int path_length) {
- if (wcscmp(dir_name, L".") != 0 &&
- wcscmp(dir_name, L"..") != 0) {
- size_t written = _snwprintf(path + path_length,
- MAX_PATH - path_length,
- L"%s",
- dir_name);
- if (written != wcslen(dir_name)) {
- return false;
- }
- return DeleteRecursively(path);
- }
- return true;
+static bool DeleteDir(wchar_t* dir_name, PathBuffer* path) {
+ if (wcscmp(dir_name, L".") == 0) return true;
+ if (wcscmp(dir_name, L"..") == 0) return true;
+ return path->Add(dir_name) && DeleteRecursively(path->data);
}
-static bool DeleteEntry(LPWIN32_FIND_DATAW find_file_data,
- wchar_t* path,
- int path_length) {
+static bool DeleteEntry(LPWIN32_FIND_DATAW find_file_data, PathBuffer* path) {
DWORD attributes = find_file_data->dwFileAttributes;
if ((attributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
- return DeleteDir(find_file_data->cFileName, path, path_length);
+ return DeleteDir(find_file_data->cFileName, path);
} else {
- return DeleteFile(find_file_data->cFileName, path, path_length);
+ return DeleteFile(find_file_data->cFileName, path);
}
}
@@ -257,33 +244,29 @@
// 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.
- wchar_t* path = static_cast<wchar_t*>(malloc(MAX_PATH * sizeof(wchar_t)));
- int path_length = 0;
- bool valid = ComputeFullSearchPath(dir_name, path, &path_length);
- if (!valid) {
- free(path);
- return false;
- }
+ PathBuffer* path = ComputeFullSearchPath(dir_name);
+ if (path == NULL) return false;
WIN32_FIND_DATAW find_file_data;
- HANDLE find_handle = FindFirstFileW(path, &find_file_data);
+ HANDLE find_handle = FindFirstFileW(path->data, &find_file_data);
// Adjust the path by removing the '*' used for the search.
- path_length -= 1;
- path[path_length] = '\0';
+ int path_length = path->length - 1;
+ path->Reset(path_length);
if (find_handle == INVALID_HANDLE_VALUE) {
- free(path);
+ delete path;
return false;
}
- bool success = DeleteEntry(&find_file_data, path, path_length);
+ bool success = DeleteEntry(&find_file_data, path);
while ((FindNextFileW(find_handle, &find_file_data) != 0) && success) {
- success = success && DeleteEntry(&find_file_data, path, path_length);
+ path->Reset(path_length); // DeleteEntry adds to the path.
+ success = success && DeleteEntry(&find_file_data, path);
}
- free(path);
+ delete path;
if ((GetLastError() != ERROR_NO_MORE_FILES) ||
(FindClose(find_handle) == 0) ||
@@ -362,52 +345,51 @@
// dir_template. Creates this directory, with a default security
// descriptor inherited from its parent directory.
// The return value must be freed by the caller.
- wchar_t* path = static_cast<wchar_t*>(malloc(MAX_PATH * sizeof(wchar_t)));
- int path_length;
+ PathBuffer* path = new PathBuffer();
if (0 == strncmp(const_template, "", 1)) {
- path_length = GetTempPathW(MAX_PATH, path);
- if (path_length == 0) {
- free(path);
+ path->length = GetTempPathW(MAX_PATH, path->data);
+ if (path->length == 0) {
+ delete path;
return NULL;
}
} else {
const wchar_t* system_template = StringUtils::Utf8ToWide(const_template);
- _snwprintf(path, MAX_PATH, L"%s", system_template);
+ path->Add(system_template);
free(const_cast<wchar_t*>(system_template));
- path_length = wcslen(path);
}
// Length of tempdir-xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx is 44.
- if (path_length > MAX_PATH - 44) {
- free(path);
+ if (path->length > MAX_PATH - 44) {
+ delete path;
return NULL;
}
- if ((path)[path_length - 1] == L'\\') {
+ if ((path->data)[path->length - 1] == L'\\') {
// No base name for the directory - use "tempdir".
- _snwprintf(path + path_length, MAX_PATH - path_length, L"tempdir");
- path_length = wcslen(path);
+ path->Add(L"tempdir");
}
UUID uuid;
RPC_STATUS status = UuidCreateSequential(&uuid);
if (status != RPC_S_OK && status != RPC_S_UUID_LOCAL_ONLY) {
- free(path);
+ delete path;
return NULL;
}
RPC_WSTR uuid_string;
status = UuidToStringW(&uuid, &uuid_string);
if (status != RPC_S_OK) {
- free(path);
+ delete path;
return NULL;
}
- _snwprintf(path + path_length, MAX_PATH - path_length, L"-%s", uuid_string);
+ path->Add(L"-");
+ // RPC_WSTR is an unsigned short*, so we cast to wchar_t*.
+ path->Add(reinterpret_cast<wchar_t*>(uuid_string));
RpcStringFreeW(&uuid_string);
- if (!CreateDirectoryW(path, NULL)) {
- free(path);
+ if (!CreateDirectoryW(path->data, NULL)) {
+ delete path;
return NULL;
}
- char* result = StringUtils::WideToUtf8(path);
- free(path);
+ char* result = StringUtils::WideToUtf8(path->data);
+ delete path;
return result;
}
diff --git a/runtime/lib/string_base.dart b/runtime/lib/string_base.dart
index 2a777c2..8b28aae 100644
--- a/runtime/lib/string_base.dart
+++ b/runtime/lib/string_base.dart
@@ -433,9 +433,7 @@
return result;
}
- Iterable<int> get codeUnits {
- throw new UnimplementedError("String.codeUnits");
- }
+ Iterable<int> get codeUnits => new CodeUnits(this);
Runes get runes => new Runes(this);
diff --git a/runtime/platform/globals.h b/runtime/platform/globals.h
index 0e352c6..176246e 100644
--- a/runtime/platform/globals.h
+++ b/runtime/platform/globals.h
@@ -79,15 +79,47 @@
#if defined(_M_X64) || defined(__x86_64__)
#define HOST_ARCH_X64 1
#define ARCH_IS_64_BIT 1
+#include <xmmintrin.h> // NOLINT
+#define kFpuRegisterSize 16
+typedef __m128 fpu_register_t;
+typedef __m128 simd_value_t;
+// Unaligned load.
+#define simd_value_safe_load(addr) \
+ _mm_loadu_ps(reinterpret_cast<const float*>(addr))
+// Unaligned store.
+#define simd_value_safe_store(addr, value) \
+ _mm_storeu_ps(reinterpret_cast<float*>(addr), value)
#elif defined(_M_IX86) || defined(__i386__)
#define HOST_ARCH_IA32 1
#define ARCH_IS_32_BIT 1
+#include <xmmintrin.h> // NOLINT
+#define kFpuRegisterSize 16
+typedef __m128 fpu_register_t;
+typedef __m128 simd_value_t;
+// Unaligned load.
+#define simd_value_safe_load(addr) \
+ _mm_loadu_ps(reinterpret_cast<const float*>(addr))
+// Unaligned store.
+#define simd_value_safe_store(addr, value) \
+ _mm_storeu_ps(reinterpret_cast<float*>(addr), value)
#elif defined(__ARMEL__)
#define HOST_ARCH_ARM 1
#define ARCH_IS_32_BIT 1
+#define kFpuRegisterSize 8
+typedef double fpu_register_t;
+// TODO(johnmccutchan): ARM simd type.
+typedef struct {
+ uint32_t data_[4];
+} simd_value_t;
#elif defined(__MIPSEL__)
#define HOST_ARCH_MIPS 1
#define ARCH_IS_32_BIT 1
+#define kFpuRegisterSize 8
+typedef double fpu_register_t;
+// TODO(johnmccutchan): MIPS simd type.
+typedef struct {
+ uint32_t data_[4];
+} simd_value_t;
#else
#error Architecture was not detected as supported by Dart.
#endif
@@ -169,7 +201,8 @@
// Byte sizes.
const int kWordSize = sizeof(word);
const int kDoubleSize = sizeof(double); // NOLINT
-const int kFloatSize = sizeof(float); // NOLINT
+const int kFloatSize = sizeof(float); // NOLINT
+const int kSimd128Size = 16;
#ifdef ARCH_IS_32_BIT
const int kWordSizeLog2 = 2;
const uword kUwordMax = kMaxUint32;
diff --git a/runtime/vm/assembler_ia32.cc b/runtime/vm/assembler_ia32.cc
index 1e23316..bef0afb 100644
--- a/runtime/vm/assembler_ia32.cc
+++ b/runtime/vm/assembler_ia32.cc
@@ -505,6 +505,22 @@
}
+void Assembler::movups(XmmRegister dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0x10);
+ EmitOperand(dst, src);
+}
+
+
+void Assembler::movups(const Address& dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0x11);
+ EmitOperand(src, dst);
+}
+
+
void Assembler::addsd(XmmRegister dst, XmmRegister src) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF2);
@@ -523,6 +539,227 @@
}
+void Assembler::addps(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0x58);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::subps(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0x5C);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::divps(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0x5E);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::mulps(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0x59);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::minps(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0x5D);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::maxps(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0x5F);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::andps(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0x54);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::andps(XmmRegister dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0x54);
+ EmitOperand(dst, src);
+}
+
+
+void Assembler::orps(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0x56);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
+void Assembler::notps(XmmRegister dst) {
+ static const struct ALIGN16 {
+ uint32_t a;
+ uint32_t b;
+ uint32_t c;
+ uint32_t d;
+ } float_not_constant =
+ { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ xorps(dst,
+ Address::Absolute(reinterpret_cast<uword>(&float_not_constant)));
+}
+
+
+void Assembler::negateps(XmmRegister dst) {
+ static const struct ALIGN16 {
+ uint32_t a;
+ uint32_t b;
+ uint32_t c;
+ uint32_t d;
+ } float_negate_constant =
+ { 0x80000000, 0x80000000, 0x80000000, 0x80000000 };
+ xorps(dst,
+ Address::Absolute(reinterpret_cast<uword>(&float_negate_constant)));
+}
+
+
+void Assembler::absps(XmmRegister dst) {
+ static const struct ALIGN16 {
+ uint32_t a;
+ uint32_t b;
+ uint32_t c;
+ uint32_t d;
+ } float_absolute_constant =
+ { 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF };
+ andps(dst,
+ Address::Absolute(reinterpret_cast<uword>(&float_absolute_constant)));
+}
+
+
+void Assembler::zerowps(XmmRegister dst) {
+ static const struct ALIGN16 {
+ uint32_t a;
+ uint32_t b;
+ uint32_t c;
+ uint32_t d;
+ } float_zerow_constant =
+ { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 };
+ andps(dst, Address::Absolute(reinterpret_cast<uword>(&float_zerow_constant)));
+}
+
+
+void Assembler::cmppseq(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0xC2);
+ EmitXmmRegisterOperand(dst, src);
+ EmitUint8(0x0);
+}
+
+
+void Assembler::cmppsneq(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0xC2);
+ EmitXmmRegisterOperand(dst, src);
+ EmitUint8(0x4);
+}
+
+
+void Assembler::cmppslt(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0xC2);
+ EmitXmmRegisterOperand(dst, src);
+ EmitUint8(0x1);
+}
+
+
+void Assembler::cmppsle(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0xC2);
+ EmitXmmRegisterOperand(dst, src);
+ EmitUint8(0x2);
+}
+
+
+void Assembler::cmppsnlt(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0xC2);
+ EmitXmmRegisterOperand(dst, src);
+ EmitUint8(0x5);
+}
+
+
+void Assembler::cmppsnle(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0xC2);
+ EmitXmmRegisterOperand(dst, src);
+ EmitUint8(0x6);
+}
+
+
+void Assembler::sqrtps(XmmRegister dst) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0x51);
+ EmitXmmRegisterOperand(dst, dst);
+}
+
+
+void Assembler::rsqrtps(XmmRegister dst) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0x52);
+ EmitXmmRegisterOperand(dst, dst);
+}
+
+
+void Assembler::reciprocalps(XmmRegister dst) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0x53);
+ EmitXmmRegisterOperand(dst, dst);
+}
+
+
+void Assembler::set1ps(XmmRegister dst, Register tmp1, const Immediate& imm) {
+ // Load 32-bit immediate value into tmp1.
+ movl(tmp1, imm);
+ // Move value from tmp1 into dst.
+ movd(dst, tmp1);
+ // Broadcast low lane into other three lanes.
+ shufps(dst, dst, Immediate(0x0));
+}
+
+
+void Assembler::shufps(XmmRegister dst, XmmRegister src, const Immediate& imm) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0xC6);
+ EmitXmmRegisterOperand(dst, src);
+ ASSERT(imm.is_uint8());
+ EmitUint8(imm.value());
+}
+
+
void Assembler::subsd(XmmRegister dst, XmmRegister src) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF2);
@@ -684,6 +921,14 @@
}
+void Assembler::movmskps(Register dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitUint8(0x0F);
+ EmitUint8(0x50);
+ EmitXmmRegisterOperand(dst, src);
+}
+
+
void Assembler::sqrtsd(XmmRegister dst, XmmRegister src) {
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
EmitUint8(0xF2);
@@ -1625,7 +1870,7 @@
void Assembler::StoreIntoObject(Register object,
- const FieldAddress& dest,
+ const Address& dest,
Register value) {
ASSERT(object != value);
TraceStoreIntoObject(object, dest, value);
@@ -1642,7 +1887,7 @@
void Assembler::StoreIntoObjectNoBarrier(Register object,
- const FieldAddress& dest,
+ const Address& dest,
Register value) {
TraceStoreIntoObject(object, dest, value);
movl(dest, value);
@@ -1659,7 +1904,7 @@
void Assembler::StoreIntoObjectNoBarrier(Register object,
- const FieldAddress& dest,
+ const Address& dest,
const Object& value) {
if (value.IsSmi() || value.InVMHeap()) {
movl(dest, Immediate(reinterpret_cast<int32_t>(value.raw())));
@@ -1676,7 +1921,7 @@
void Assembler::TraceStoreIntoObject(Register object,
- const FieldAddress& dest,
+ const Address& dest,
Register value) {
if (HeapTrace::is_enabled()) {
pushal();
@@ -1816,14 +2061,14 @@
}
// Preserve all XMM registers except XMM0
- subl(ESP, Immediate((kNumberOfXmmRegisters - 1) * kDoubleSize));
+ subl(ESP, Immediate((kNumberOfXmmRegisters - 1) * kFpuRegisterSize));
// Store XMM registers with the lowest register number at the lowest
// address.
intptr_t offset = 0;
for (intptr_t reg_idx = 1; reg_idx < kNumberOfXmmRegisters; ++reg_idx) {
XmmRegister xmm_reg = static_cast<XmmRegister>(reg_idx);
- movsd(Address(ESP, offset), xmm_reg);
- offset += kDoubleSize;
+ movups(Address(ESP, offset), xmm_reg);
+ offset += kFpuRegisterSize;
}
ReserveAlignedFrameSpace(frame_space);
@@ -1836,7 +2081,7 @@
// We need to restore it before restoring registers.
const intptr_t kPushedRegistersSize =
kNumberOfVolatileCpuRegisters * kWordSize +
- kNumberOfVolatileXmmRegisters * kDoubleSize;
+ kNumberOfVolatileXmmRegisters * kFpuRegisterSize;
leal(ESP, Address(EBP, -kPushedRegistersSize));
// Restore all XMM registers except XMM0
@@ -1844,8 +2089,8 @@
intptr_t offset = 0;
for (intptr_t reg_idx = 1; reg_idx < kNumberOfXmmRegisters; ++reg_idx) {
XmmRegister xmm_reg = static_cast<XmmRegister>(reg_idx);
- movsd(xmm_reg, Address(ESP, offset));
- offset += kDoubleSize;
+ movups(xmm_reg, Address(ESP, offset));
+ offset += kFpuRegisterSize;
}
addl(ESP, Immediate(offset));
diff --git a/runtime/vm/assembler_ia32.h b/runtime/vm/assembler_ia32.h
index 5c0c1cb..9fb8106 100644
--- a/runtime/vm/assembler_ia32.h
+++ b/runtime/vm/assembler_ia32.h
@@ -377,6 +377,9 @@
void movaps(XmmRegister dst, XmmRegister src);
+ void movups(XmmRegister dst, const Address& src);
+ void movups(const Address& dst, XmmRegister src);
+
void addsd(XmmRegister dst, XmmRegister src);
void addsd(XmmRegister dst, const Address& src);
void subsd(XmmRegister dst, XmmRegister src);
@@ -386,6 +389,33 @@
void divsd(XmmRegister dst, XmmRegister src);
void divsd(XmmRegister dst, const Address& src);
+
+ void addps(XmmRegister dst, XmmRegister src);
+ void subps(XmmRegister dst, XmmRegister src);
+ void divps(XmmRegister dst, XmmRegister src);
+ void mulps(XmmRegister dst, XmmRegister src);
+ void minps(XmmRegister dst, XmmRegister src);
+ void maxps(XmmRegister dst, XmmRegister src);
+ void andps(XmmRegister dst, XmmRegister src);
+ void andps(XmmRegister dst, const Address& src);
+ void orps(XmmRegister dst, XmmRegister src);
+ void notps(XmmRegister dst);
+ void negateps(XmmRegister dst);
+ void absps(XmmRegister dst);
+ void zerowps(XmmRegister dst);
+ void cmppseq(XmmRegister dst, XmmRegister src);
+ void cmppsneq(XmmRegister dst, XmmRegister src);
+ void cmppslt(XmmRegister dst, XmmRegister src);
+ void cmppsle(XmmRegister dst, XmmRegister src);
+ void cmppsnlt(XmmRegister dst, XmmRegister src);
+ void cmppsnle(XmmRegister dst, XmmRegister src);
+ void sqrtps(XmmRegister dst);
+ void rsqrtps(XmmRegister dst);
+ void reciprocalps(XmmRegister dst);
+
+ void set1ps(XmmRegister dst, Register tmp, const Immediate& imm);
+ void shufps(XmmRegister dst, XmmRegister src, const Immediate& mask);
+
void cvtsi2ss(XmmRegister dst, Register src);
void cvtsi2sd(XmmRegister dst, Register src);
@@ -404,6 +434,7 @@
void comisd(XmmRegister a, XmmRegister b);
void movmskpd(Register dst, XmmRegister src);
+ void movmskps(Register dst, XmmRegister src);
void sqrtsd(XmmRegister dst, XmmRegister src);
void sqrtss(XmmRegister dst, XmmRegister src);
@@ -575,18 +606,18 @@
void LoadDoubleConstant(XmmRegister dst, double value);
void StoreIntoObject(Register object, // Object we are storing into.
- const FieldAddress& dest, // Where we are storing into.
+ const Address& dest, // Where we are storing into.
Register value); // Value we are storing.
void StoreIntoObjectNoBarrier(Register object,
- const FieldAddress& dest,
+ const Address& dest,
Register value);
void StoreIntoObjectNoBarrier(Register object,
- const FieldAddress& dest,
+ const Address& dest,
const Object& value);
void TraceStoreIntoObject(Register object,
- const FieldAddress& dest,
+ const Address& dest,
Register value);
void DoubleNegate(XmmRegister d);
diff --git a/runtime/vm/assembler_ia32_test.cc b/runtime/vm/assembler_ia32_test.cc
index 476ebd8..2a2c33d 100644
--- a/runtime/vm/assembler_ia32_test.cc
+++ b/runtime/vm/assembler_ia32_test.cc
@@ -834,6 +834,378 @@
}
+ASSEMBLER_TEST_GENERATE(PackedFPOperations, assembler) {
+ __ movl(EAX, Immediate(bit_cast<int32_t, float>(12.3f)));
+ __ movd(XMM0, EAX);
+ __ shufps(XMM0, XMM0, Immediate(0x0));
+ __ movl(EAX, Immediate(bit_cast<int32_t, float>(3.4f)));
+ __ movd(XMM1, EAX);
+ __ shufps(XMM1, XMM1, Immediate(0x0));
+ __ addps(XMM0, XMM1); // 15.7f
+ __ mulps(XMM0, XMM1); // 53.38f
+ __ subps(XMM0, XMM1); // 49.98f
+ __ divps(XMM0, XMM1); // 14.7f
+ __ shufps(XMM0, XMM0, Immediate(0x55)); // Copy second lane into all 4 lanes.
+ __ pushl(EAX);
+ // Copy the low lane at ESP.
+ __ movss(Address(ESP, 0), XMM0);
+ __ flds(Address(ESP, 0));
+ __ popl(EAX);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedFPOperations, entry) {
+ typedef float (*PackedFPOperationsCode)();
+ float res = reinterpret_cast<PackedFPOperationsCode>(entry)();
+ EXPECT_FLOAT_EQ(14.7f, res, 0.001f);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedFPOperations2, assembler) {
+ __ movl(EAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+ __ movd(XMM0, EAX);
+ __ shufps(XMM0, XMM0, Immediate(0x0));
+
+ __ movaps(XMM1, XMM0); // Copy XMM0
+ __ reciprocalps(XMM1); // 0.25
+ __ sqrtps(XMM1); // 0.5
+ __ rsqrtps(XMM0); // ~0.5
+ __ subps(XMM0, XMM1); // ~0.0
+ __ shufps(XMM0, XMM0, Immediate(0x00)); // Copy second lane into all 4 lanes.
+ __ pushl(EAX);
+ // Copy the low lane at ESP.
+ __ movss(Address(ESP, 0), XMM0);
+ __ flds(Address(ESP, 0));
+ __ popl(EAX);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedFPOperations2, entry) {
+ typedef float (*PackedFPOperations2Code)();
+ float res = reinterpret_cast<PackedFPOperations2Code>(entry)();
+ EXPECT_FLOAT_EQ(0.0f, res, 0.001f);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedCompareEQ, assembler) {
+ __ set1ps(XMM0, EAX, Immediate(bit_cast<int32_t, float>(2.0f)));
+ __ set1ps(XMM1, EAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+ __ cmppseq(XMM0, XMM1);
+ // Copy the low lane at ESP.
+ __ pushl(EAX);
+ __ movss(Address(ESP, 0), XMM0);
+ __ flds(Address(ESP, 0));
+ __ popl(EAX);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedCompareEQ, entry) {
+ typedef uint32_t (*PackedCompareEQCode)();
+ uint32_t res = reinterpret_cast<PackedCompareEQCode>(entry)();
+ EXPECT_EQ(static_cast<uword>(0x0), res);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedCompareNEQ, assembler) {
+ __ set1ps(XMM0, EAX, Immediate(bit_cast<int32_t, float>(2.0f)));
+ __ set1ps(XMM1, EAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+ __ cmppsneq(XMM0, XMM1);
+ // Copy the low lane at ESP.
+ __ pushl(EAX);
+ __ movss(Address(ESP, 0), XMM0);
+ __ flds(Address(ESP, 0));
+ __ popl(EAX);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedCompareNEQ, entry) {
+ typedef uint32_t (*PackedCompareNEQCode)();
+ uint32_t res = reinterpret_cast<PackedCompareNEQCode>(entry)();
+ EXPECT_EQ(static_cast<uword>(0xFFFFFFFF), res);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedCompareLT, assembler) {
+ __ set1ps(XMM0, EAX, Immediate(bit_cast<int32_t, float>(2.0f)));
+ __ set1ps(XMM1, EAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+ __ cmppslt(XMM0, XMM1);
+ // Copy the low lane at ESP.
+ __ pushl(EAX);
+ __ movss(Address(ESP, 0), XMM0);
+ __ flds(Address(ESP, 0));
+ __ popl(EAX);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedCompareLT, entry) {
+ typedef uint32_t (*PackedCompareLTCode)();
+ uint32_t res = reinterpret_cast<PackedCompareLTCode>(entry)();
+ EXPECT_EQ(static_cast<uword>(0xFFFFFFFF), res);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedCompareLE, assembler) {
+ __ set1ps(XMM0, EAX, Immediate(bit_cast<int32_t, float>(2.0f)));
+ __ set1ps(XMM1, EAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+ __ cmppsle(XMM0, XMM1);
+ // Copy the low lane at ESP.
+ __ pushl(EAX);
+ __ movss(Address(ESP, 0), XMM0);
+ __ flds(Address(ESP, 0));
+ __ popl(EAX);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedCompareLE, entry) {
+ typedef uint32_t (*PackedCompareLECode)();
+ uint32_t res = reinterpret_cast<PackedCompareLECode>(entry)();
+ EXPECT_EQ(static_cast<uword>(0xFFFFFFFF), res);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedCompareNLT, assembler) {
+ __ set1ps(XMM0, EAX, Immediate(bit_cast<int32_t, float>(2.0f)));
+ __ set1ps(XMM1, EAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+ __ cmppsnlt(XMM0, XMM1);
+ // Copy the low lane at ESP.
+ __ pushl(EAX);
+ __ movss(Address(ESP, 0), XMM0);
+ __ flds(Address(ESP, 0));
+ __ popl(EAX);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedCompareNLT, entry) {
+ typedef uint32_t (*PackedCompareNLTCode)();
+ uint32_t res = reinterpret_cast<PackedCompareNLTCode>(entry)();
+ EXPECT_EQ(static_cast<uword>(0x0), res);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedCompareNLE, assembler) {
+ __ set1ps(XMM0, EAX, Immediate(bit_cast<int32_t, float>(2.0f)));
+ __ set1ps(XMM1, EAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+ __ cmppsnle(XMM0, XMM1);
+ // Copy the low lane at ESP.
+ __ pushl(EAX);
+ __ movss(Address(ESP, 0), XMM0);
+ __ flds(Address(ESP, 0));
+ __ popl(EAX);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedCompareNLE, entry) {
+ typedef uint32_t (*PackedCompareNLECode)();
+ uint32_t res = reinterpret_cast<PackedCompareNLECode>(entry)();
+ EXPECT_EQ(static_cast<uword>(0x0), res);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedNegate, assembler) {
+ __ movl(EAX, Immediate(bit_cast<int32_t, float>(12.3f)));
+ __ movd(XMM0, EAX);
+ __ shufps(XMM0, XMM0, Immediate(0x0));
+ __ negateps(XMM0);
+ __ shufps(XMM0, XMM0, Immediate(0xAA)); // Copy third lane into all 4 lanes.
+ __ pushl(EAX);
+ // Copy the low lane at ESP.
+ __ movss(Address(ESP, 0), XMM0);
+ __ flds(Address(ESP, 0));
+ __ popl(EAX);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedNegate, entry) {
+ typedef float (*PackedNegateCode)();
+ float res = reinterpret_cast<PackedNegateCode>(entry)();
+ EXPECT_FLOAT_EQ(-12.3f, res, 0.001f);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedAbsolute, assembler) {
+ __ movl(EAX, Immediate(bit_cast<int32_t, float>(-15.3f)));
+ __ movd(XMM0, EAX);
+ __ shufps(XMM0, XMM0, Immediate(0x0));
+ __ absps(XMM0);
+ __ shufps(XMM0, XMM0, Immediate(0xAA)); // Copy third lane into all 4 lanes.
+ // Copy the low lane at ESP.
+ __ pushl(EAX);
+ __ movss(Address(ESP, 0), XMM0);
+ __ flds(Address(ESP, 0));
+ __ popl(EAX);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedAbsolute, entry) {
+ typedef float (*PackedAbsoluteCode)();
+ float res = reinterpret_cast<PackedAbsoluteCode>(entry)();
+ EXPECT_FLOAT_EQ(15.3f, res, 0.001f);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedSetWZero, assembler) {
+ __ set1ps(XMM0, EAX, Immediate(bit_cast<int32_t, float>(12.3f)));
+ __ zerowps(XMM0);
+ __ shufps(XMM0, XMM0, Immediate(0xFF)); // Copy the W lane which is now 0.0.
+ // Copy the low lane at ESP.
+ __ pushl(EAX);
+ __ movss(Address(ESP, 0), XMM0);
+ __ flds(Address(ESP, 0));
+ __ popl(EAX);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedSetWZero, entry) {
+ typedef float (*PackedSetWZeroCode)();
+ float res = reinterpret_cast<PackedSetWZeroCode>(entry)();
+ EXPECT_FLOAT_EQ(0.0f, res, 0.001f);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedMin, assembler) {
+ __ set1ps(XMM0, EAX, Immediate(bit_cast<int32_t, float>(2.0f)));
+ __ set1ps(XMM1, EAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+ __ minps(XMM0, XMM1);
+ // Copy the low lane at ESP.
+ __ pushl(EAX);
+ __ movss(Address(ESP, 0), XMM0);
+ __ flds(Address(ESP, 0));
+ __ popl(EAX);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedMin, entry) {
+ typedef float (*PackedMinCode)();
+ float res = reinterpret_cast<PackedMinCode>(entry)();
+ EXPECT_FLOAT_EQ(2.0f, res, 0.001f);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedMax, assembler) {
+ __ set1ps(XMM0, EAX, Immediate(bit_cast<int32_t, float>(2.0f)));
+ __ set1ps(XMM1, EAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+ __ maxps(XMM0, XMM1);
+ // Copy the low lane at ESP.
+ __ pushl(EAX);
+ __ movss(Address(ESP, 0), XMM0);
+ __ flds(Address(ESP, 0));
+ __ popl(EAX);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedMax, entry) {
+ typedef float (*PackedMaxCode)();
+ float res = reinterpret_cast<PackedMaxCode>(entry)();
+ EXPECT_FLOAT_EQ(4.0f, res, 0.001f);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedLogicalOr, assembler) {
+ static const struct ALIGN16 {
+ uint32_t a;
+ uint32_t b;
+ uint32_t c;
+ uint32_t d;
+ } constant1 =
+ { 0xF0F0F0F0, 0xF0F0F0F0, 0xF0F0F0F0, 0xF0F0F0F0 };
+ static const struct ALIGN16 {
+ uint32_t a;
+ uint32_t b;
+ uint32_t c;
+ uint32_t d;
+ } constant2 =
+ { 0x0F0F0F0F, 0x0F0F0F0F, 0x0F0F0F0F, 0x0F0F0F0F };
+ __ movups(XMM0, Address::Absolute(reinterpret_cast<uword>(&constant1)));
+ __ movups(XMM1, Address::Absolute(reinterpret_cast<uword>(&constant2)));
+ __ orps(XMM0, XMM1);
+ // Copy the low lane at ESP.
+ __ pushl(EAX);
+ __ movss(Address(ESP, 0), XMM0);
+ __ flds(Address(ESP, 0));
+ __ popl(EAX);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedLogicalOr, entry) {
+ typedef uint32_t (*PackedLogicalOrCode)();
+ uint32_t res = reinterpret_cast<PackedLogicalOrCode>(entry)();
+ EXPECT_EQ(0xFFFFFFFF, res);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedLogicalAnd, assembler) {
+ static const struct ALIGN16 {
+ uint32_t a;
+ uint32_t b;
+ uint32_t c;
+ uint32_t d;
+ } constant1 =
+ { 0xF0F0F0F0, 0xF0F0F0F0, 0xF0F0F0F0, 0xF0F0F0F0 };
+ static const struct ALIGN16 {
+ uint32_t a;
+ uint32_t b;
+ uint32_t c;
+ uint32_t d;
+ } constant2 =
+ { 0x0F0FFF0F, 0x0F0F0F0F, 0x0F0F0F0F, 0x0F0F0F0F };
+ __ movups(XMM0, Address::Absolute(reinterpret_cast<uword>(&constant1)));
+ __ andps(XMM0, Address::Absolute(reinterpret_cast<uword>(&constant2)));
+ // Copy the low lane at ESP.
+ __ pushl(EAX);
+ __ movss(Address(ESP, 0), XMM0);
+ __ flds(Address(ESP, 0));
+ __ popl(EAX);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedLogicalAnd, entry) {
+ typedef uint32_t (*PackedLogicalAndCode)();
+ uint32_t res = reinterpret_cast<PackedLogicalAndCode>(entry)();
+ EXPECT_EQ(static_cast<uword>(0x0000F000), res);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedLogicalNot, assembler) {
+ static const struct ALIGN16 {
+ uint32_t a;
+ uint32_t b;
+ uint32_t c;
+ uint32_t d;
+ } constant1 =
+ { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ __ movups(XMM0, Address::Absolute(reinterpret_cast<uword>(&constant1)));
+ __ notps(XMM0);
+ // Copy the low lane at ESP.
+ __ pushl(EAX);
+ __ movss(Address(ESP, 0), XMM0);
+ __ flds(Address(ESP, 0));
+ __ popl(EAX);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedLogicalNot, entry) {
+ typedef uint32_t (*PackedLogicalNotCode)();
+ uint32_t res = reinterpret_cast<PackedLogicalNotCode>(entry)();
+ EXPECT_EQ(static_cast<uword>(0x0), res);
+}
+
+
ASSEMBLER_TEST_GENERATE(SingleFPOperationsStack, assembler) {
__ movl(EAX, Immediate(bit_cast<int32_t, float>(12.3f)));
__ movd(XMM0, EAX);
diff --git a/runtime/vm/assembler_x64.cc b/runtime/vm/assembler_x64.cc
index 1b270aa..8afb003 100644
--- a/runtime/vm/assembler_x64.cc
+++ b/runtime/vm/assembler_x64.cc
@@ -529,6 +529,24 @@
}
+void Assembler::movups(XmmRegister dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitREX_RB(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x10);
+ EmitOperand(dst & 7, src);
+}
+
+
+void Assembler::movups(const Address& dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitREX_RB(src, dst);
+ EmitUint8(0x0F);
+ EmitUint8(0x11);
+ EmitOperand(src & 7, dst);
+}
+
+
void Assembler::addsd(XmmRegister dst, XmmRegister src) {
ASSERT(src <= XMM15);
ASSERT(dst <= XMM15);
@@ -576,6 +594,245 @@
EmitXmmRegisterOperand(dst & 7, src);
}
+void Assembler::addps(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitREX_RB(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x58);
+ EmitXmmRegisterOperand(dst & 7, src);
+}
+
+
+void Assembler::subps(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitREX_RB(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x5C);
+ EmitXmmRegisterOperand(dst & 7, src);
+}
+
+
+void Assembler::divps(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitREX_RB(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x5E);
+ EmitXmmRegisterOperand(dst & 7, src);
+}
+
+
+void Assembler::mulps(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitREX_RB(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x59);
+ EmitXmmRegisterOperand(dst & 7, src);
+}
+
+
+void Assembler::minps(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitREX_RB(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x5D);
+ EmitXmmRegisterOperand(dst & 7, src);
+}
+
+
+void Assembler::maxps(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitREX_RB(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x5F);
+ EmitXmmRegisterOperand(dst & 7, src);
+}
+
+
+void Assembler::andps(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitREX_RB(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x54);
+ EmitXmmRegisterOperand(dst & 7, src);
+}
+
+
+void Assembler::andps(XmmRegister dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitREX_RB(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x54);
+ EmitOperand(dst & 7, src);
+}
+
+
+void Assembler::orps(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitREX_RB(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x56);
+ EmitXmmRegisterOperand(dst & 7, src);
+}
+
+void Assembler::notps(XmmRegister dst) {
+ static const struct ALIGN16 {
+ uint32_t a;
+ uint32_t b;
+ uint32_t c;
+ uint32_t d;
+ } float_not_constant =
+ { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ movq(TMP, Immediate(reinterpret_cast<intptr_t>(&float_not_constant)));
+ xorps(dst, Address(TMP, 0));
+}
+
+
+void Assembler::negateps(XmmRegister dst) {
+ static const struct ALIGN16 {
+ uint32_t a;
+ uint32_t b;
+ uint32_t c;
+ uint32_t d;
+ } float_negate_constant =
+ { 0x80000000, 0x80000000, 0x80000000, 0x80000000 };
+ movq(TMP, Immediate(reinterpret_cast<intptr_t>(&float_negate_constant)));
+ xorps(dst, Address(TMP, 0));
+}
+
+
+void Assembler::absps(XmmRegister dst) {
+ static const struct ALIGN16 {
+ uint32_t a;
+ uint32_t b;
+ uint32_t c;
+ uint32_t d;
+ } float_absolute_constant =
+ { 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF };
+ movq(TMP, Immediate(reinterpret_cast<intptr_t>(&float_absolute_constant)));
+ andps(dst, Address(TMP, 0));
+}
+
+
+void Assembler::zerowps(XmmRegister dst) {
+ static const struct ALIGN16 {
+ uint32_t a;
+ uint32_t b;
+ uint32_t c;
+ uint32_t d;
+ } float_zerow_constant =
+ { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x00000000 };
+ movq(TMP, Immediate(reinterpret_cast<intptr_t>(&float_zerow_constant)));
+ andps(dst, Address(TMP, 0));
+}
+
+
+void Assembler::cmppseq(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitREX_RB(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0xC2);
+ EmitXmmRegisterOperand(dst & 7, src);
+ EmitUint8(0x0);
+}
+
+
+void Assembler::cmppsneq(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitREX_RB(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0xC2);
+ EmitXmmRegisterOperand(dst & 7, src);
+ EmitUint8(0x4);
+}
+
+
+void Assembler::cmppslt(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitREX_RB(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0xC2);
+ EmitXmmRegisterOperand(dst & 7, src);
+ EmitUint8(0x1);
+}
+
+
+void Assembler::cmppsle(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitREX_RB(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0xC2);
+ EmitXmmRegisterOperand(dst & 7, src);
+ EmitUint8(0x2);
+}
+
+
+void Assembler::cmppsnlt(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitREX_RB(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0xC2);
+ EmitXmmRegisterOperand(dst & 7, src);
+ EmitUint8(0x5);
+}
+
+
+void Assembler::cmppsnle(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitREX_RB(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0xC2);
+ EmitXmmRegisterOperand(dst & 7, src);
+ EmitUint8(0x6);
+}
+
+
+void Assembler::sqrtps(XmmRegister dst) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitREX_RB(dst, dst);
+ EmitUint8(0x0F);
+ EmitUint8(0x51);
+ EmitXmmRegisterOperand(dst & 7, dst);
+}
+
+
+void Assembler::rsqrtps(XmmRegister dst) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitREX_RB(dst, dst);
+ EmitUint8(0x0F);
+ EmitUint8(0x52);
+ EmitXmmRegisterOperand(dst & 7, dst);
+}
+
+
+void Assembler::reciprocalps(XmmRegister dst) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitREX_RB(dst, dst);
+ EmitUint8(0x0F);
+ EmitUint8(0x53);
+ EmitXmmRegisterOperand(dst & 7, dst);
+}
+
+
+void Assembler::set1ps(XmmRegister dst, Register tmp1, const Immediate& imm) {
+ // Load 32-bit immediate value into tmp1.
+ movl(tmp1, imm);
+ // Move value from tmp1 into dst.
+ movd(dst, tmp1);
+ // Broadcast low lane into other three lanes.
+ shufps(dst, dst, Immediate(0x0));
+}
+
+
+void Assembler::shufps(XmmRegister dst, XmmRegister src, const Immediate& imm) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitREX_RB(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0xC6);
+ EmitXmmRegisterOperand(dst & 7, src);
+ ASSERT(imm.is_uint8());
+ EmitUint8(imm.value());
+}
+
void Assembler::comisd(XmmRegister a, XmmRegister b) {
ASSERT(a <= XMM15);
@@ -600,6 +857,16 @@
}
+void Assembler::movmskps(Register dst, XmmRegister src) {
+ ASSERT(src <= XMM15);
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitREX_RB(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x50);
+ EmitXmmRegisterOperand(dst & 7, src);
+}
+
+
void Assembler::sqrtsd(XmmRegister dst, XmmRegister src) {
ASSERT(dst <= XMM15);
ASSERT(src <= XMM15);
@@ -635,6 +902,23 @@
}
+void Assembler::xorps(XmmRegister dst, const Address& src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitREX_RB(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x57);
+ EmitOperand(dst & 7, src);
+}
+
+
+void Assembler::xorps(XmmRegister dst, XmmRegister src) {
+ AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+ EmitREX_RB(dst, src);
+ EmitUint8(0x0F);
+ EmitUint8(0x57);
+ EmitXmmRegisterOperand(dst & 7, src);
+}
+
void Assembler::andpd(XmmRegister dst, const Address& src) {
ASSERT(dst <= XMM15);
AssemblerBuffer::EnsureCapacity ensured(&buffer_);
@@ -1744,7 +2028,7 @@
void Assembler::StoreIntoObject(Register object,
- const FieldAddress& dest,
+ const Address& dest,
Register value) {
ASSERT(object != value);
movq(dest, value);
@@ -1760,7 +2044,7 @@
void Assembler::StoreIntoObjectNoBarrier(Register object,
- const FieldAddress& dest,
+ const Address& dest,
Register value) {
movq(dest, value);
#if defined(DEBUG)
@@ -1923,14 +2207,14 @@
}
// Preserve all XMM registers except XMM0
- subq(RSP, Immediate((kNumberOfXmmRegisters - 1) * kDoubleSize));
+ subq(RSP, Immediate((kNumberOfXmmRegisters - 1) * kFpuRegisterSize));
// Store XMM registers with the lowest register number at the lowest
// address.
intptr_t offset = 0;
for (intptr_t reg_idx = 1; reg_idx < kNumberOfXmmRegisters; ++reg_idx) {
XmmRegister xmm_reg = static_cast<XmmRegister>(reg_idx);
- movsd(Address(RSP, offset), xmm_reg);
- offset += kDoubleSize;
+ movups(Address(RSP, offset), xmm_reg);
+ offset += kFpuRegisterSize;
}
ReserveAlignedFrameSpace(frame_space);
@@ -1943,7 +2227,7 @@
// We need to restore it before restoring registers.
const intptr_t kPushedRegistersSize =
kNumberOfVolatileCpuRegisters * kWordSize +
- kNumberOfVolatileXmmRegisters * kDoubleSize;
+ kNumberOfVolatileXmmRegisters * kFpuRegisterSize;
leaq(RSP, Address(RBP, -kPushedRegistersSize));
// Restore all XMM registers except XMM0
@@ -1951,8 +2235,8 @@
intptr_t offset = 0;
for (intptr_t reg_idx = 1; reg_idx < kNumberOfXmmRegisters; ++reg_idx) {
XmmRegister xmm_reg = static_cast<XmmRegister>(reg_idx);
- movsd(xmm_reg, Address(RSP, offset));
- offset += kDoubleSize;
+ movups(xmm_reg, Address(RSP, offset));
+ offset += kFpuRegisterSize;
}
addq(RSP, Immediate(offset));
diff --git a/runtime/vm/assembler_x64.h b/runtime/vm/assembler_x64.h
index 8c18c6c..1bfabf2 100644
--- a/runtime/vm/assembler_x64.h
+++ b/runtime/vm/assembler_x64.h
@@ -383,11 +383,40 @@
void movaps(XmmRegister dst, XmmRegister src);
+ void movups(const Address& dst, XmmRegister src);
+ void movups(XmmRegister dst, const Address& src);
+
void addsd(XmmRegister dst, XmmRegister src);
void subsd(XmmRegister dst, XmmRegister src);
void mulsd(XmmRegister dst, XmmRegister src);
void divsd(XmmRegister dst, XmmRegister src);
+ void addps(XmmRegister dst, XmmRegister src);
+ void subps(XmmRegister dst, XmmRegister src);
+ void divps(XmmRegister dst, XmmRegister src);
+ void mulps(XmmRegister dst, XmmRegister src);
+ void minps(XmmRegister dst, XmmRegister src);
+ void maxps(XmmRegister dst, XmmRegister src);
+ void andps(XmmRegister dst, XmmRegister src);
+ void andps(XmmRegister dst, const Address& src);
+ void orps(XmmRegister dst, XmmRegister src);
+ void notps(XmmRegister dst);
+ void negateps(XmmRegister dst);
+ void absps(XmmRegister dst);
+ void zerowps(XmmRegister dst);
+ void cmppseq(XmmRegister dst, XmmRegister src);
+ void cmppsneq(XmmRegister dst, XmmRegister src);
+ void cmppslt(XmmRegister dst, XmmRegister src);
+ void cmppsle(XmmRegister dst, XmmRegister src);
+ void cmppsnlt(XmmRegister dst, XmmRegister src);
+ void cmppsnle(XmmRegister dst, XmmRegister src);
+ void sqrtps(XmmRegister dst);
+ void rsqrtps(XmmRegister dst);
+ void reciprocalps(XmmRegister dst);
+
+ void set1ps(XmmRegister dst, Register tmp, const Immediate& imm);
+ void shufps(XmmRegister dst, XmmRegister src, const Immediate& mask);
+
void comisd(XmmRegister a, XmmRegister b);
void cvtsi2sd(XmmRegister a, Register b);
void cvttsd2siq(Register dst, XmmRegister src);
@@ -507,12 +536,16 @@
void ret();
void movmskpd(Register dst, XmmRegister src);
+ void movmskps(Register dst, XmmRegister src);
void sqrtsd(XmmRegister dst, XmmRegister src);
void xorpd(XmmRegister dst, const Address& src);
void xorpd(XmmRegister dst, XmmRegister src);
+ void xorps(XmmRegister dst, const Address& src);
+ void xorps(XmmRegister dst, XmmRegister src);
+
void andpd(XmmRegister dst, const Address& src);
void fldl(const Address& src);
@@ -594,15 +627,12 @@
// Destroys value.
void StoreIntoObject(Register object, // Object we are storing into.
- const FieldAddress& dest, // Where we are storing into.
+ const Address& dest, // Where we are storing into.
Register value); // Value we are storing.
void StoreIntoObjectNoBarrier(Register object,
- const FieldAddress& dest,
+ const Address& dest,
Register value);
- void StoreIntoObjectNoBarrier(Register object,
- const FieldAddress& dest,
- const Object& value);
void DoubleNegate(XmmRegister d);
void FloatNegate(XmmRegister f);
diff --git a/runtime/vm/assembler_x64_test.cc b/runtime/vm/assembler_x64_test.cc
index e6e3940..8e3f62a 100644
--- a/runtime/vm/assembler_x64_test.cc
+++ b/runtime/vm/assembler_x64_test.cc
@@ -1388,6 +1388,330 @@
EXPECT_FLOAT_EQ(0.0f, res, 0.001f);
}
+ASSEMBLER_TEST_GENERATE(PackedFPOperations, assembler) {
+ __ movq(RAX, Immediate(bit_cast<int32_t, float>(12.3f)));
+ __ movd(XMM10, RAX);
+ __ shufps(XMM10, XMM10, Immediate(0x0));
+ __ movq(RAX, Immediate(bit_cast<int32_t, float>(3.4f)));
+ __ movd(XMM9, RAX);
+ __ shufps(XMM9, XMM9, Immediate(0x0));
+ __ addps(XMM10, XMM9); // 15.7f
+ __ mulps(XMM10, XMM9); // 53.38f
+ __ subps(XMM10, XMM9); // 49.98f
+ __ divps(XMM10, XMM9); // 14.7f
+ __ movaps(XMM0, XMM10);
+ __ shufps(XMM0, XMM0, Immediate(0x55)); // Copy second lane into all 4 lanes.
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedFPOperations, entry) {
+ typedef float (*PackedFPOperationsCode)();
+ float res = reinterpret_cast<PackedFPOperationsCode>(entry)();
+ EXPECT_FLOAT_EQ(14.7f, res, 0.001f);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedFPOperations2, assembler) {
+ __ movq(RAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+ __ movd(XMM0, RAX);
+ __ shufps(XMM0, XMM0, Immediate(0x0));
+
+ __ movaps(XMM11, XMM0); // Copy XMM0
+ __ reciprocalps(XMM11); // 0.25
+ __ sqrtps(XMM11); // 0.5
+ __ rsqrtps(XMM0); // ~0.5
+ __ subps(XMM0, XMM11); // ~0.0
+ __ shufps(XMM0, XMM0, Immediate(0x00)); // Copy second lane into all 4 lanes.
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedFPOperations2, entry) {
+ typedef float (*PackedFPOperations2Code)();
+ float res = reinterpret_cast<PackedFPOperations2Code>(entry)();
+ EXPECT_FLOAT_EQ(0.0f, res, 0.001f);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedCompareEQ, assembler) {
+ __ set1ps(XMM0, RAX, Immediate(bit_cast<int32_t, float>(2.0f)));
+ __ set1ps(XMM1, RAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+ __ cmppseq(XMM0, XMM1);
+ __ pushq(RAX);
+ __ movss(Address(RSP, 0), XMM0);
+ __ popq(RAX);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedCompareEQ, entry) {
+ typedef uint32_t (*PackedCompareEQCode)();
+ uint32_t res = reinterpret_cast<PackedCompareEQCode>(entry)();
+ EXPECT_EQ(static_cast<uword>(0x0), res);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedCompareNEQ, assembler) {
+ __ set1ps(XMM0, RAX, Immediate(bit_cast<int32_t, float>(2.0f)));
+ __ set1ps(XMM1, RAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+ __ cmppsneq(XMM0, XMM1);
+ __ pushq(RAX);
+ __ movss(Address(RSP, 0), XMM0);
+ __ popq(RAX);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedCompareNEQ, entry) {
+ typedef uint32_t (*PackedCompareNEQCode)();
+ uint32_t res = reinterpret_cast<PackedCompareNEQCode>(entry)();
+ EXPECT_EQ(static_cast<uword>(0xFFFFFFFF), res);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedCompareLT, assembler) {
+ __ set1ps(XMM0, RAX, Immediate(bit_cast<int32_t, float>(2.0f)));
+ __ set1ps(XMM1, RAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+ __ cmppslt(XMM0, XMM1);
+ __ pushq(RAX);
+ __ movss(Address(RSP, 0), XMM0);
+ __ popq(RAX);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedCompareLT, entry) {
+ typedef uint32_t (*PackedCompareLTCode)();
+ uint32_t res = reinterpret_cast<PackedCompareLTCode>(entry)();
+ EXPECT_EQ(static_cast<uword>(0xFFFFFFFF), res);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedCompareLE, assembler) {
+ __ set1ps(XMM0, RAX, Immediate(bit_cast<int32_t, float>(2.0f)));
+ __ set1ps(XMM1, RAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+ __ cmppsle(XMM0, XMM1);
+ __ pushq(RAX);
+ __ movss(Address(RSP, 0), XMM0);
+ __ popq(RAX);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedCompareLE, entry) {
+ typedef uint32_t (*PackedCompareLECode)();
+ uint32_t res = reinterpret_cast<PackedCompareLECode>(entry)();
+ EXPECT_EQ(static_cast<uword>(0xFFFFFFFF), res);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedCompareNLT, assembler) {
+ __ set1ps(XMM0, RAX, Immediate(bit_cast<int32_t, float>(2.0f)));
+ __ set1ps(XMM1, RAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+ __ cmppsnlt(XMM0, XMM1);
+ __ pushq(RAX);
+ __ movss(Address(RSP, 0), XMM0);
+ __ popq(RAX);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedCompareNLT, entry) {
+ typedef uint32_t (*PackedCompareNLTCode)();
+ uint32_t res = reinterpret_cast<PackedCompareNLTCode>(entry)();
+ EXPECT_EQ(static_cast<uword>(0x0), res);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedCompareNLE, assembler) {
+ __ set1ps(XMM0, RAX, Immediate(bit_cast<int32_t, float>(2.0f)));
+ __ set1ps(XMM1, RAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+ __ cmppsnle(XMM0, XMM1);
+ __ pushq(RAX);
+ __ movss(Address(RSP, 0), XMM0);
+ __ popq(RAX);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedCompareNLE, entry) {
+ typedef uint32_t (*PackedCompareNLECode)();
+ uint32_t res = reinterpret_cast<PackedCompareNLECode>(entry)();
+ EXPECT_EQ(static_cast<uword>(0x0), res);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedNegate, assembler) {
+ __ movl(RAX, Immediate(bit_cast<int32_t, float>(12.3f)));
+ __ movd(XMM0, RAX);
+ __ shufps(XMM0, XMM0, Immediate(0x0));
+ __ negateps(XMM0);
+ __ shufps(XMM0, XMM0, Immediate(0xAA)); // Copy third lane into all 4 lanes.
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedNegate, entry) {
+ typedef float (*PackedNegateCode)();
+ float res = reinterpret_cast<PackedNegateCode>(entry)();
+ EXPECT_FLOAT_EQ(-12.3f, res, 0.001f);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedAbsolute, assembler) {
+ __ movl(RAX, Immediate(bit_cast<int32_t, float>(-15.3f)));
+ __ movd(XMM0, RAX);
+ __ shufps(XMM0, XMM0, Immediate(0x0));
+ __ absps(XMM0);
+ __ shufps(XMM0, XMM0, Immediate(0xAA)); // Copy third lane into all 4 lanes.
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedAbsolute, entry) {
+ typedef float (*PackedAbsoluteCode)();
+ float res = reinterpret_cast<PackedAbsoluteCode>(entry)();
+ EXPECT_FLOAT_EQ(15.3f, res, 0.001f);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedSetWZero, assembler) {
+ __ set1ps(XMM0, RAX, Immediate(bit_cast<int32_t, float>(12.3f)));
+ __ zerowps(XMM0);
+ __ shufps(XMM0, XMM0, Immediate(0xFF)); // Copy the W lane which is now 0.0.
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedSetWZero, entry) {
+ typedef float (*PackedSetWZeroCode)();
+ float res = reinterpret_cast<PackedSetWZeroCode>(entry)();
+ EXPECT_FLOAT_EQ(0.0f, res, 0.001f);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedMin, assembler) {
+ __ set1ps(XMM0, RAX, Immediate(bit_cast<int32_t, float>(2.0f)));
+ __ set1ps(XMM1, RAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+ __ minps(XMM0, XMM1);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedMin, entry) {
+ typedef float (*PackedMinCode)();
+ float res = reinterpret_cast<PackedMinCode>(entry)();
+ EXPECT_FLOAT_EQ(2.0f, res, 0.001f);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedMax, assembler) {
+ __ set1ps(XMM0, RAX, Immediate(bit_cast<int32_t, float>(2.0f)));
+ __ set1ps(XMM1, RAX, Immediate(bit_cast<int32_t, float>(4.0f)));
+ __ maxps(XMM0, XMM1);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedMax, entry) {
+ typedef float (*PackedMaxCode)();
+ float res = reinterpret_cast<PackedMaxCode>(entry)();
+ EXPECT_FLOAT_EQ(4.0f, res, 0.001f);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedLogicalOr, assembler) {
+ static const struct ALIGN16 {
+ uint32_t a;
+ uint32_t b;
+ uint32_t c;
+ uint32_t d;
+ } constant1 =
+ { 0xF0F0F0F0, 0xF0F0F0F0, 0xF0F0F0F0, 0xF0F0F0F0 };
+ static const struct ALIGN16 {
+ uint32_t a;
+ uint32_t b;
+ uint32_t c;
+ uint32_t d;
+ } constant2 =
+ { 0x0F0F0F0F, 0x0F0F0F0F, 0x0F0F0F0F, 0x0F0F0F0F };
+ __ movq(RAX, Immediate(reinterpret_cast<intptr_t>(&constant1)));
+ __ movups(XMM0, Address(RAX, 0));
+ __ movq(RAX, Immediate(reinterpret_cast<intptr_t>(&constant2)));
+ __ movups(XMM1, Address(RAX, 0));
+ __ orps(XMM0, XMM1);
+ __ pushq(RAX);
+ __ movss(Address(RSP, 0), XMM0);
+ __ popq(RAX);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedLogicalOr, entry) {
+ typedef uint32_t (*PackedLogicalOrCode)();
+ uint32_t res = reinterpret_cast<PackedLogicalOrCode>(entry)();
+ EXPECT_EQ(0xFFFFFFFF, res);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedLogicalAnd, assembler) {
+ static const struct ALIGN16 {
+ uint32_t a;
+ uint32_t b;
+ uint32_t c;
+ uint32_t d;
+ } constant1 =
+ { 0xF0F0F0F0, 0xF0F0F0F0, 0xF0F0F0F0, 0xF0F0F0F0 };
+ static const struct ALIGN16 {
+ uint32_t a;
+ uint32_t b;
+ uint32_t c;
+ uint32_t d;
+ } constant2 =
+ { 0x0F0FFF0F, 0x0F0F0F0F, 0x0F0F0F0F, 0x0F0F0F0F };
+ __ movq(RAX, Immediate(reinterpret_cast<intptr_t>(&constant1)));
+ __ movups(XMM0, Address(RAX, 0));
+ __ movq(RAX, Immediate(reinterpret_cast<intptr_t>(&constant2)));
+ __ andps(XMM0, Address(RAX, 0));
+ __ pushq(RAX);
+ __ movss(Address(RSP, 0), XMM0);
+ __ popq(RAX);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedLogicalAnd, entry) {
+ typedef uint32_t (*PackedLogicalAndCode)();
+ uint32_t res = reinterpret_cast<PackedLogicalAndCode>(entry)();
+ EXPECT_EQ(static_cast<uword>(0x0000F000), res);
+}
+
+
+ASSEMBLER_TEST_GENERATE(PackedLogicalNot, assembler) {
+ static const struct ALIGN16 {
+ uint32_t a;
+ uint32_t b;
+ uint32_t c;
+ uint32_t d;
+ } constant1 =
+ { 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF };
+ __ movq(RAX, Immediate(reinterpret_cast<intptr_t>(&constant1)));
+ __ movups(XMM9, Address(RAX, 0));
+ __ notps(XMM9);
+ __ movaps(XMM0, XMM9);
+ __ pushq(RAX);
+ __ movss(Address(RSP, 0), XMM0);
+ __ popq(RAX);
+ __ ret();
+}
+
+
+ASSEMBLER_TEST_RUN(PackedLogicalNot, entry) {
+ typedef uint32_t (*PackedLogicalNotCode)();
+ uint32_t res = reinterpret_cast<PackedLogicalNotCode>(entry)();
+ EXPECT_EQ(static_cast<uword>(0x0), res);
+}
ASSEMBLER_TEST_GENERATE(DoubleFPMoves, assembler) {
__ movq(RAX, Immediate(bit_cast<int64_t, double>(1024.67)));
diff --git a/runtime/vm/ast.h b/runtime/vm/ast.h
index 721de07..07e2314 100644
--- a/runtime/vm/ast.h
+++ b/runtime/vm/ast.h
@@ -265,17 +265,22 @@
class ArrayNode : public AstNode {
public:
- ArrayNode(intptr_t token_pos, const AbstractType& type)
+ ArrayNode(intptr_t token_pos,
+ const AbstractType& type,
+ const LocalVariable& temp)
: AstNode(token_pos),
type_(type),
+ temp_local_(temp),
elements_() {
CheckFields();
}
ArrayNode(intptr_t token_pos,
const AbstractType& type,
+ const LocalVariable& temp,
const GrowableArray<AstNode*>& elements)
: AstNode(token_pos),
type_(type),
+ temp_local_(temp),
elements_(elements.length()) {
CheckFields();
for (intptr_t i = 0; i < elements.length(); i++) {
@@ -295,10 +300,13 @@
const AbstractType& type() const { return type_; }
+ const LocalVariable& temp_local() const { return temp_local_; }
+
DECLARE_COMMON_NODE_FUNCTIONS(ArrayNode);
private:
const AbstractType& type_;
+ const LocalVariable& temp_local_; // Store allocated array while filling it.
GrowableArray<AstNode*> elements_;
void CheckFields() {
diff --git a/runtime/vm/class_finalizer.cc b/runtime/vm/class_finalizer.cc
index d6e85f3..b2253ee 100644
--- a/runtime/vm/class_finalizer.cc
+++ b/runtime/vm/class_finalizer.cc
@@ -1098,6 +1098,83 @@
}
+void ClassFinalizer::ApplyMixin(const Class& cls) {
+ const Type& mixin_type = Type::Handle(cls.mixin());
+ ASSERT(!mixin_type.IsNull());
+ ASSERT(mixin_type.HasResolvedTypeClass());
+ const Class& mixin_cls = Class::Handle(mixin_type.type_class());
+
+ if (FLAG_trace_class_finalization) {
+ OS::Print("Applying mixin '%s' to '%s'\n",
+ String::Handle(mixin_cls.Name()).ToCString(),
+ cls.ToCString());
+ }
+
+ // Check that the super class of the mixin class is extending
+ // class Object.
+ const Type& mixin_super_type = Type::Handle(mixin_cls.super_type());
+ if (!mixin_super_type.IsObjectType()) {
+ const Script& script = Script::Handle(cls.script());
+ const String& class_name = String::Handle(mixin_cls.Name());
+ ReportError(script, cls.token_pos(),
+ "mixin class %s must extend class Object",
+ class_name.ToCString());
+ }
+
+ const GrowableObjectArray& cloned_funcs =
+ GrowableObjectArray::Handle(GrowableObjectArray::New());
+ Array& functions = Array::Handle();
+ Function& func = Function::Handle();
+ // The parser creates the mixin application class and adds just
+ // one function, the implicit constructor.
+ functions = cls.functions();
+ ASSERT(functions.Length() == 1);
+ func ^= functions.At(0);
+ ASSERT(func.IsImplicitConstructor());
+ cloned_funcs.Add(func);
+ // Now clone the functions from the mixin class.
+ functions = mixin_cls.functions();
+ const intptr_t num_functions = functions.Length();
+ for (int i = 0; i < num_functions; i++) {
+ func ^= functions.At(i);
+ if (func.IsConstructor()) {
+ // A mixin class must not have explicit constructors.
+ if (!func.IsImplicitConstructor()) {
+ const Script& script = Script::Handle(cls.script());
+ ReportError(script, cls.token_pos(),
+ "mixin class %s must not have constructors\n",
+ String::Handle(mixin_cls.Name()).ToCString());
+ }
+ continue; // Skip the implicit constructor.
+ }
+ if (!func.is_static()) {
+ func = func.Clone(cls);
+ cloned_funcs.Add(func);
+ }
+ }
+ functions = Array::MakeArray(cloned_funcs);
+ cls.SetFunctions(functions);
+
+ // Now clone the fields from the mixin class. There should be no
+ // existing fields in the mixin application class.
+ ASSERT(Array::Handle(cls.fields()).Length() == 0);
+ Array& fields = Array::Handle(mixin_cls.fields());
+ Field& field = Field::Handle();
+ const GrowableObjectArray& cloned_fields =
+ GrowableObjectArray::Handle(GrowableObjectArray::New());
+ const intptr_t num_fields = fields.Length();
+ for (int i = 0; i < num_fields; i++) {
+ field ^= fields.At(i);
+ if (!field.is_static()) {
+ field = field.Clone(cls);
+ cloned_fields.Add(field);
+ }
+ }
+ fields = Array::MakeArray(cloned_fields);
+ cls.SetFields(fields);
+}
+
+
void ClassFinalizer::FinalizeClass(const Class& cls) {
if (cls.is_finalized()) {
return;
@@ -1150,6 +1227,12 @@
FinalizeType(cls, sig_type, kCanonicalizeWellFormed);
return;
}
+ if (cls.mixin() != Type::null()) {
+ // Copy instance methods and fields from the mixin class.
+ // This has to happen before the check whether the methods of
+ // the class conflict with inherited methods.
+ ApplyMixin(cls);
+ }
// Finalize interface types (but not necessarily interface classes).
Array& interface_types = Array::Handle(cls.interfaces());
AbstractType& interface_type = AbstractType::Handle();
@@ -1267,16 +1350,23 @@
}
}
- // If the class/interface has no explicit super class/interfaces, we are done.
+ // If the class/interface has no explicit super class/interfaces
+ // and is not a mixin application, we are done.
Type& super_type = Type::Handle(cls.super_type());
+ Type& mixin_type = Type::Handle(cls.mixin());
Array& super_interfaces = Array::Handle(cls.interfaces());
if ((super_type.IsNull() || super_type.IsObjectType()) &&
- (super_interfaces.Length() == 0)) {
+ (super_interfaces.Length() == 0) &&
+ (mixin_type.IsNull())) {
return;
}
- // If cls belongs to core lib or to core lib's implementation, restrictions
- // about allowed interfaces are lifted.
+ if (!mixin_type.IsNull()) {
+ ResolveType(cls, mixin_type, kCanonicalizeWellFormed);
+ }
+
+ // If cls belongs to core lib, restrictions about allowed interfaces
+ // are lifted.
const bool cls_belongs_to_core_lib = cls.library() == Library::CoreLibrary();
// Resolve and check the super type and interfaces of cls.
@@ -1287,7 +1377,6 @@
// Resolve super type. Failures lead to a longjmp.
ResolveType(cls, super_type, kCanonicalizeWellFormed);
- // If cls belongs to core lib or to core lib's implementation, restrictions
interface_class = super_type.type_class();
// If cls belongs to core lib or to core lib's implementation, restrictions
// about allowed interfaces are lifted.
diff --git a/runtime/vm/class_finalizer.h b/runtime/vm/class_finalizer.h
index c272379..237c40d 100644
--- a/runtime/vm/class_finalizer.h
+++ b/runtime/vm/class_finalizer.h
@@ -99,6 +99,7 @@
const Class& cls,
const Function& factory,
const GrowableObjectArray& visited_factories);
+ static void ApplyMixin(const Class& cls);
static void ResolveSuperTypeAndInterfaces(const Class& cls,
GrowableArray<intptr_t>* visited);
static void FinalizeTypeParameters(const Class& cls);
diff --git a/runtime/vm/compiler.cc b/runtime/vm/compiler.cc
index babed80..2efb71d 100644
--- a/runtime/vm/compiler.cc
+++ b/runtime/vm/compiler.cc
@@ -21,6 +21,7 @@
#include "vm/flow_graph_compiler.h"
#include "vm/flow_graph_inliner.h"
#include "vm/flow_graph_optimizer.h"
+#include "vm/flow_graph_type_propagator.h"
#include "vm/il_printer.h"
#include "vm/longjump.h"
#include "vm/object.h"
@@ -53,7 +54,7 @@
DECLARE_FLAG(bool, print_flow_graph);
DECLARE_FLAG(bool, print_flow_graph_optimized);
DECLARE_FLAG(bool, trace_failed_optimization_attempts);
-
+DECLARE_FLAG(bool, trace_type_propagation);
// Compile a function. Should call only if the function has not been compiled.
// Arg0: function object.
@@ -190,15 +191,25 @@
// Use lists are maintained and validated by the inliner.
}
+ if (FLAG_trace_type_propagation) {
+ OS::Print("Before type propagation:\n");
+ FlowGraphPrinter printer(*flow_graph);
+ printer.PrintBlocks();
+ }
+
// Propagate types and eliminate more type tests.
if (FLAG_propagate_types) {
FlowGraphTypePropagator propagator(flow_graph);
- propagator.PropagateTypes();
+ propagator.Propagate();
}
- // Propagate sminess from CheckSmi to phis.
+ if (FLAG_trace_type_propagation) {
+ OS::Print("After type propagation:\n");
+ FlowGraphPrinter printer(*flow_graph);
+ printer.PrintBlocks();
+ }
+
flow_graph->ComputeUseLists();
- optimizer.PropagateSminess();
// Use propagated class-ids to optimize further.
optimizer.ApplyClassIds();
@@ -465,10 +476,11 @@
ParsedFunction* parsed_function = new ParsedFunction(
Function::ZoneHandle(function.raw()));
if (FLAG_trace_compiler) {
- OS::Print("Compiling %sfunction: '%s' @ token %"Pd"\n",
+ OS::Print("Compiling %sfunction: '%s' @ token %"Pd", size %"Pd"\n",
(optimized ? "optimized " : ""),
function.ToFullyQualifiedCString(),
- function.token_pos());
+ function.token_pos(),
+ (function.end_token_pos() - function.token_pos()));
}
{
HANDLESCOPE(isolate);
@@ -495,9 +507,10 @@
per_compile_timer.Stop();
if (FLAG_trace_compiler) {
- OS::Print("--> '%s' entry: %#"Px" time: %"Pd64" us\n",
+ OS::Print("--> '%s' entry: %#"Px" size: %"Pd" time: %"Pd64" us\n",
function.ToFullyQualifiedCString(),
Code::Handle(function.CurrentCode()).EntryPoint(),
+ Code::Handle(function.CurrentCode()).Size(),
per_compile_timer.TotalElapsedTime());
}
@@ -625,6 +638,9 @@
parsed_function->set_expression_temp_var(
ParsedFunction::CreateExpressionTempVar(0));
fragment->scope()->AddVariable(parsed_function->expression_temp_var());
+ parsed_function->set_array_literal_var(
+ ParsedFunction::CreateArrayLiteralVar(0));
+ fragment->scope()->AddVariable(parsed_function->array_literal_var());
parsed_function->AllocateVariables();
// Non-optimized code generator.
diff --git a/runtime/vm/disassembler_ia32.cc b/runtime/vm/disassembler_ia32.cc
index cc08f94..5610b5f 100644
--- a/runtime/vm/disassembler_ia32.cc
+++ b/runtime/vm/disassembler_ia32.cc
@@ -237,8 +237,22 @@
case 0xAD: return "shrd";
case 0xAB: return "bts";
case 0xB1: return "cmpxchg";
+ case 0x50: return "movmskps";
+ case 0x51: return "sqrtps";
+ case 0x52: return "rqstps";
+ case 0x53: return "rcpps";
+ case 0x54: return "andps";
+ case 0x56: return "orps";
case 0x57: return "xorps";
+ case 0x58: return "addps";
+ case 0x59: return "mulps";
+ case 0x5C: return "subps";
+ case 0x5D: return "minps";
+ case 0x5E: return "divps";
+ case 0x5F: return "maxps";
case 0x28: return "movaps";
+ case 0x10: return "movups";
+ case 0x11: return "movups";
default: return NULL;
}
}
@@ -286,6 +300,7 @@
void PrintCPURegister(int reg);
void PrintCPUByteRegister(int reg);
void PrintXmmRegister(int reg);
+ void PrintXmmComparison(int comparison);
void PrintAddress(uword addr);
typedef void (X86Decoder::*RegisterNamePrinter)(int reg);
@@ -395,6 +410,15 @@
Print(xmm_regs[reg]);
}
+void X86Decoder::PrintXmmComparison(int comparison) {
+ ASSERT(0 <= comparison);
+ ASSERT(comparison < 8);
+ static const char* comparisons[8] = {
+ "eq", "lt", "le", "unordered", "not eq", "not lt", "not le", "ordered"
+ };
+ Print(comparisons[comparison]);
+}
+
static const char* ObjectToCStringNoGC(const Object& obj) {
if (obj.IsSmi() ||
@@ -1337,6 +1361,54 @@
PrintXmmRegister(regop);
Print(",");
data += PrintRightXmmOperand(data);
+ } else if (f0byte == 0x11) {
+ Print("movups ");
+ int mod, regop, rm;
+ GetModRm(*data, &mod, ®op, &rm);
+ data += PrintRightXmmOperand(data);
+ Print(",");
+ PrintXmmRegister(regop);
+ } else if (f0byte == 0x10) {
+ int mod, regop, rm;
+ GetModRm(*data, &mod, ®op, &rm);
+ Print("movups ");
+ PrintXmmRegister(regop);
+ Print(",");
+ data += PrintRightOperand(data);
+ } else if (f0byte == 0x51 || f0byte == 0x52 || f0byte == 0x53 ||
+ f0byte == 0x54 || f0byte == 0x56 || f0byte == 0x58 ||
+ f0byte == 0x59 || f0byte == 0x5C || f0byte == 0x5D ||
+ f0byte == 0x5E || f0byte == 0x5F) {
+ int mod, regop, rm;
+ GetModRm(*data, &mod, ®op, &rm);
+ Print(f0mnem);
+ Print(" ");
+ PrintXmmRegister(regop);
+ Print(",");
+ data += PrintRightXmmOperand(data);
+ } else if (f0byte == 0x50) {
+ Print("movmskpd ");
+ int mod, regop, rm;
+ GetModRm(*data, &mod, ®op, &rm);
+ PrintCPURegister(regop);
+ Print(",");
+ data += PrintRightXmmOperand(data);
+ } else if (f0byte == 0xC2 || f0byte == 0xC6) {
+ if (f0byte == 0xC2)
+ Print("cmpps ");
+ else
+ Print("shufps ");
+ int mod, regop, rm;
+ GetModRm(*data, &mod, ®op, &rm);
+ Print(" ");
+ PrintXmmRegister(regop);
+ Print(",");
+ data += PrintRightXmmOperand(data);
+ int comparison = *data;
+ Print(" [");
+ PrintHex(comparison);
+ Print("]");
+ data++;
} else {
UNIMPLEMENTED();
}
diff --git a/runtime/vm/disassembler_x64.cc b/runtime/vm/disassembler_x64.cc
index 4d15072..958c2b7 100644
--- a/runtime/vm/disassembler_x64.cc
+++ b/runtime/vm/disassembler_x64.cc
@@ -1394,7 +1394,6 @@
get_modrm(*current, &mod, ®op, &rm);
AppendToBuffer("movaps %s, ", NameOfXMMRegister(regop));
current += PrintRightXMMOperand(current);
-
} else if (opcode == 0x29) {
// movaps xmm/m128, xmm
int mod, regop, rm;
@@ -1402,7 +1401,19 @@
AppendToBuffer("movaps ");
current += PrintRightXMMOperand(current);
AppendToBuffer(", %s", NameOfXMMRegister(regop));
-
+ } else if (opcode == 0x11) {
+ // movups xmm/m128, xmm
+ int mod, regop, rm;
+ get_modrm(*current, &mod, ®op, &rm);
+ AppendToBuffer("movups ");
+ current += PrintRightXMMOperand(current);
+ AppendToBuffer(", %s", NameOfXMMRegister(regop));
+ } else if (opcode == 0x10) {
+ // movups xmm, xmm/m128
+ int mod, regop, rm;
+ get_modrm(*current, &mod, ®op, &rm);
+ AppendToBuffer("movups %s, ", NameOfXMMRegister(regop));
+ current += PrintRightXMMOperand(current);
} else if (opcode == 0xA2 || opcode == 0x31) {
// RDTSC or CPUID
AppendToBuffer("%s", mnemonic);
@@ -1414,13 +1425,42 @@
byte_size_operand_ = idesc.byte_size_operation;
current += PrintOperands(idesc.mnem, idesc.op_order_, current);
- } else if (opcode == 0x57) {
- // xorps xmm, xmm/m128
+ } else if (opcode == 0x51 || opcode == 0x52 || opcode == 0x53 ||
+ opcode == 0x54 || opcode == 0x56 || opcode == 0x57 ||
+ opcode == 0x58 || opcode == 0x59 || opcode == 0x5C ||
+ opcode == 0x5D || opcode == 0x5E || opcode == 0x5F) {
+ const char* mnemonic = NULL;
+ switch (opcode) {
+ case 0x51: mnemonic = "sqrtps"; break;
+ case 0x52: mnemonic = "rsqrtps"; break;
+ case 0x53: mnemonic = "rcpps"; break;
+ case 0x54: mnemonic = "andps"; break;
+ case 0x56: mnemonic = "orps"; break;
+ case 0x57: mnemonic = "xorps"; break;
+ case 0x58: mnemonic = "addps"; break;
+ case 0x59: mnemonic = "mulps"; break;
+ case 0x5C: mnemonic = "subps"; break;
+ case 0x5D: mnemonic = "minps"; break;
+ case 0x5E: mnemonic = "divps"; break;
+ case 0x5F: mnemonic = "maxps"; break;
+ default: UNREACHABLE();
+ }
int mod, regop, rm;
get_modrm(*current, &mod, ®op, &rm);
- AppendToBuffer("xorps %s, ", NameOfXMMRegister(regop));
+ AppendToBuffer("%s %s, ", mnemonic, NameOfXMMRegister(regop));
current += PrintRightXMMOperand(current);
-
+ } else if (opcode == 0xC2 || opcode == 0xC6) {
+ int mod, regop, rm;
+ get_modrm(*current, &mod, ®op, &rm);
+ if (opcode == 0xC2) {
+ AppendToBuffer("cmpps %s, ", NameOfXMMRegister(regop));
+ } else {
+ ASSERT(opcode == 0xC6);
+ AppendToBuffer("shufps %s, ", NameOfXMMRegister(regop));
+ }
+ current += PrintRightXMMOperand(current);
+ AppendToBuffer(" [%x]", *current);
+ current++;
} else if ((opcode & 0xF0) == 0x80) {
// Jcc: Conditional jump (branch).
current = data + JumpConditional(data);
diff --git a/runtime/vm/flow_graph_builder.cc b/runtime/vm/flow_graph_builder.cc
index 236c4d9..909d937 100644
--- a/runtime/vm/flow_graph_builder.cc
+++ b/runtime/vm/flow_graph_builder.cc
@@ -762,12 +762,7 @@
return false;
}
- // Propagated types are not set yet.
- // More checks will possibly be eliminated during type propagation.
- bool is_null, is_instance;
- const bool eliminated =
- (value->CanComputeIsNull(&is_null) && is_null) ||
- (value->CanComputeIsInstanceOf(dst_type, &is_instance) && is_instance);
+ const bool eliminated = value->Type()->IsAssignableTo(dst_type);
if (FLAG_trace_type_check_elimination) {
FlowGraphPrinter::PrintTypeCheck(owner()->parsed_function(),
token_pos,
@@ -1661,24 +1656,37 @@
void EffectGraphVisitor::VisitArrayNode(ArrayNode* node) {
- // Translate the array elements and collect their values.
- ZoneGrowableArray<PushArgumentInstr*>* arguments =
- new ZoneGrowableArray<PushArgumentInstr*>(node->length());
- for (int i = 0; i < node->length(); ++i) {
- ValueGraphVisitor for_value(owner(), temp_index());
- node->ElementAt(i)->Visit(&for_value);
- Append(for_value);
- arguments->Add(PushArgument(for_value.value()));
- }
const AbstractTypeArguments& type_args =
AbstractTypeArguments::ZoneHandle(node->type().arguments());
Value* element_type = BuildInstantiatedTypeArguments(node->token_pos(),
type_args);
CreateArrayInstr* create = new CreateArrayInstr(node->token_pos(),
- arguments,
+ node->length(),
node->type(),
element_type);
- ReturnDefinition(create);
+ Value* array_val = Bind(create);
+ Definition* store = BuildStoreTemp(node->temp_local(), array_val);
+ Do(store);
+
+ const intptr_t class_id = create->Type()->ToCid();
+ const intptr_t deopt_id = Isolate::kNoDeoptId;
+ for (int i = 0; i < node->length(); ++i) {
+ Value* array = Bind(
+ new LoadLocalInstr(node->temp_local(), owner()->context_level()));
+ Value* index = Bind(new ConstantInstr(Smi::ZoneHandle(Smi::New(i))));
+ ValueGraphVisitor for_value(owner(), temp_index());
+ node->ElementAt(i)->Visit(&for_value);
+ Append(for_value);
+ // No store barrier needed for constants.
+ const bool emit_store_barrier = !for_value.value()->BindsToConstant();
+ StoreIndexedInstr* store = new StoreIndexedInstr(
+ array, index, for_value.value(),
+ emit_store_barrier, class_id, deopt_id);
+ Do(store);
+ }
+
+ ReturnDefinition(
+ new LoadLocalInstr(node->temp_local(), owner()->context_level()));
}
@@ -3046,8 +3054,10 @@
arguments->Add(new LiteralNode(args_pos, args_descriptor));
// The third argument is an array containing the original method arguments,
// including the receiver.
- ArrayNode* args_array =
- new ArrayNode(args_pos, Type::ZoneHandle(Type::ArrayType()));
+ ArrayNode* args_array = new ArrayNode(
+ args_pos,
+ Type::ZoneHandle(Type::ArrayType()),
+ *owner()->parsed_function().array_literal_var());
for (intptr_t i = 0; i < method_arguments->length(); i++) {
args_array->AddElement(method_arguments->NodeAt(i));
}
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index 880b3eb..8319dd5 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -939,6 +939,10 @@
return OneByteString::data_offset();
case kTwoByteStringCid:
return TwoByteString::data_offset();
+ case kExternalUint8ArrayCid:
+ case kExternalUint8ClampedArrayCid:
+ // Elements start at offset 0 of the external data.
+ return 0;
default:
UNIMPLEMENTED();
return Array::data_offset();
diff --git a/runtime/vm/flow_graph_compiler.h b/runtime/vm/flow_graph_compiler.h
index f7d3f34..d0ff1f7 100644
--- a/runtime/vm/flow_graph_compiler.h
+++ b/runtime/vm/flow_graph_compiler.h
@@ -210,11 +210,6 @@
// Bail out of the flow graph compiler. Does not return to the caller.
void Bailout(const char* reason);
- void LoadDoubleOrSmiToFpu(FpuRegister result,
- Register reg,
- Register temp,
- Label* not_double_or_smi);
-
// Returns 'true' if code generation for this function is complete, i.e.,
// no fall-through to regular code is needed.
bool TryIntrinsify();
diff --git a/runtime/vm/flow_graph_compiler_ia32.cc b/runtime/vm/flow_graph_compiler_ia32.cc
index efb9b7b..72e7d35 100644
--- a/runtime/vm/flow_graph_compiler_ia32.cc
+++ b/runtime/vm/flow_graph_compiler_ia32.cc
@@ -24,6 +24,7 @@
DECLARE_FLAG(int, optimization_counter_threshold);
DECLARE_FLAG(bool, print_ast);
DECLARE_FLAG(bool, print_scopes);
+DECLARE_FLAG(bool, eliminate_type_checks);
FlowGraphCompiler::~FlowGraphCompiler() {
@@ -561,6 +562,16 @@
__ cmpl(EAX, raw_null);
__ j(EQUAL, &is_assignable);
+ if (!FLAG_eliminate_type_checks) {
+ // If type checks are not eliminated during the graph building then
+ // a transition sentinel can be seen here.
+ const Immediate& raw_transition_sentinel =
+ Immediate(reinterpret_cast<intptr_t>(
+ Object::transition_sentinel().raw()));
+ __ cmpl(EAX, raw_transition_sentinel);
+ __ j(EQUAL, &is_assignable);
+ }
+
// Generate throw new TypeError() if the type is malformed.
if (dst_type.IsMalformed()) {
const Error& error = Error::Handle(dst_type.malformed_error());
@@ -1318,25 +1329,6 @@
}
-void FlowGraphCompiler::LoadDoubleOrSmiToFpu(FpuRegister result,
- Register reg,
- Register temp,
- Label* not_double_or_smi) {
- Label is_smi, done;
- __ testl(reg, Immediate(kSmiTagMask));
- __ j(ZERO, &is_smi);
- __ CompareClassId(reg, kDoubleCid, temp);
- __ j(NOT_EQUAL, not_double_or_smi);
- __ movsd(result, FieldAddress(reg, Double::value_offset()));
- __ jmp(&done);
- __ Bind(&is_smi);
- __ movl(temp, reg);
- __ SmiUntag(temp);
- __ cvtsi2sd(result, temp);
- __ Bind(&done);
-}
-
-
void FlowGraphCompiler::SaveLiveRegisters(LocationSummary* locs) {
// TODO(vegorov): consider saving only caller save (volatile) registers.
const intptr_t xmm_regs_count = locs->live_registers()->fpu_regs_count();
diff --git a/runtime/vm/flow_graph_compiler_x64.cc b/runtime/vm/flow_graph_compiler_x64.cc
index 76e976e..f92c613 100644
--- a/runtime/vm/flow_graph_compiler_x64.cc
+++ b/runtime/vm/flow_graph_compiler_x64.cc
@@ -23,7 +23,7 @@
DECLARE_FLAG(int, optimization_counter_threshold);
DECLARE_FLAG(bool, print_ast);
DECLARE_FLAG(bool, print_scopes);
-DECLARE_FLAG(bool, use_sse41);
+DECLARE_FLAG(bool, eliminate_type_checks);
FlowGraphCompiler::~FlowGraphCompiler() {
@@ -561,6 +561,13 @@
__ cmpq(RAX, raw_null);
__ j(EQUAL, &is_assignable);
+ if (!FLAG_eliminate_type_checks) {
+ // If type checks are not eliminated during the graph building then
+ // a transition sentinel can be seen here.
+ __ CompareObject(RAX, Object::transition_sentinel());
+ __ j(EQUAL, &is_assignable);
+ }
+
// Generate throw new TypeError() if the type is malformed.
if (dst_type.IsMalformed()) {
const Error& error = Error::Handle(dst_type.malformed_error());
@@ -1322,25 +1329,6 @@
}
-void FlowGraphCompiler::LoadDoubleOrSmiToFpu(FpuRegister result,
- Register reg,
- Register temp,
- Label* not_double_or_smi) {
- Label is_smi, done;
- __ testq(reg, Immediate(kSmiTagMask));
- __ j(ZERO, &is_smi);
- __ CompareClassId(reg, kDoubleCid);
- __ j(NOT_EQUAL, not_double_or_smi);
- __ movsd(result, FieldAddress(reg, Double::value_offset()));
- __ jmp(&done);
- __ Bind(&is_smi);
- __ movq(temp, reg);
- __ SmiUntag(temp);
- __ cvtsi2sd(result, temp);
- __ Bind(&done);
-}
-
-
void FlowGraphCompiler::SaveLiveRegisters(LocationSummary* locs) {
// TODO(vegorov): consider saving only caller save (volatile) registers.
const intptr_t xmm_regs_count = locs->live_registers()->fpu_regs_count();
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index b1a10b8..c72acf8 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -84,7 +84,7 @@
GrowableArray<intptr_t> class_ids(call->ic_data()->num_args_tested());
ASSERT(call->ic_data()->num_args_tested() <= call->ArgumentCount());
for (intptr_t i = 0; i < call->ic_data()->num_args_tested(); i++) {
- intptr_t cid = call->ArgumentAt(i)->value()->ResultCid();
+ intptr_t cid = call->ArgumentAt(i)->value()->Type()->ToCid();
class_ids.Add(cid);
}
// TODO(srdjan): Test for other class_ids > 1.
@@ -150,7 +150,7 @@
return; // Already specialized.
}
- const intptr_t receiver_cid = call->ArgumentAt(0)->value()->ResultCid();
+ const intptr_t receiver_cid = call->ArgumentAt(0)->value()->Type()->ToCid();
if (receiver_cid == kDynamicCid) {
return; // No information about receiver was infered.
}
@@ -231,7 +231,7 @@
Definition* converted = NULL;
if ((from == kTagged) && (to == kUnboxedMint)) {
ASSERT((deopt_target != NULL) ||
- (use->definition()->GetPropagatedCid() == kDoubleCid));
+ (use->Type()->ToCid() == kDoubleCid));
const intptr_t deopt_id = (deopt_target != NULL) ?
deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId;
converted = new UnboxIntegerInstr(new Value(use->definition()), deopt_id);
@@ -251,7 +251,7 @@
const intptr_t deopt_id = (deopt_target != NULL) ?
deopt_target->DeoptimizationTarget() : Isolate::kNoDeoptId;
ASSERT((deopt_target != NULL) ||
- (use->definition()->GetPropagatedCid() == kDoubleCid));
+ (use->Type()->ToCid() == kDoubleCid));
ConstantInstr* constant = use->definition()->AsConstant();
if ((constant != NULL) && constant->value().IsSmi()) {
const double dbl_val = Smi::Cast(constant->value()).AsDoubleValue();
@@ -313,7 +313,7 @@
for (intptr_t i = 0; i < join_entry->phis()->length(); ++i) {
PhiInstr* phi = (*join_entry->phis())[i];
if (phi == NULL) continue;
- if (phi->GetPropagatedCid() == kDoubleCid) {
+ if (phi->Type()->ToCid() == kDoubleCid) {
phi->set_representation(kUnboxedDouble);
}
}
@@ -603,6 +603,8 @@
case kInt8ArrayCid:
case kUint8ArrayCid:
case kUint8ClampedArrayCid:
+ case kExternalUint8ArrayCid:
+ case kExternalUint8ClampedArrayCid:
case kInt16ArrayCid:
case kUint16ArrayCid:
// Check that value is always smi.
@@ -679,6 +681,8 @@
case kInt8ArrayCid:
case kUint8ArrayCid:
case kUint8ClampedArrayCid:
+ case kExternalUint8ArrayCid:
+ case kExternalUint8ClampedArrayCid:
case kInt16ArrayCid:
case kUint16ArrayCid:
case kInt32ArrayCid:
@@ -1171,13 +1175,17 @@
static LoadFieldInstr* BuildLoadStringLength(Value* str) {
- const bool is_immutable = true; // String length is immutable.
+ // Treat length loads as mutable (i.e. affected by side effects) to avoid
+ // hoisting them since we can't hoist the preceding class-check. This
+ // is because of externalization of strings that affects their class-id.
+ const bool is_immutable = false;
LoadFieldInstr* load = new LoadFieldInstr(
str,
String::length_offset(),
Type::ZoneHandle(Type::SmiType()),
is_immutable);
load->set_result_cid(kSmiCid);
+ load->set_recognized_kind(MethodRecognizer::kStringBaseLength);
return load;
}
@@ -1187,7 +1195,6 @@
AddCheckClass(call, call->ArgumentAt(0)->value()->Copy());
LoadFieldInstr* load = BuildLoadStringLength(call->ArgumentAt(0)->value());
- load->set_recognized_kind(MethodRecognizer::kStringBaseLength);
call->ReplaceWith(load, current_iterator());
RemovePushArguments(call);
}
@@ -1321,14 +1328,7 @@
}
if (!skip_check) {
// Insert bounds check.
- const bool is_immutable = true;
- LoadFieldInstr* length = new LoadFieldInstr(
- str->Copy(),
- CheckArrayBoundInstr::LengthOffsetFor(cid),
- Type::ZoneHandle(Type::SmiType()),
- is_immutable);
- length->set_result_cid(kSmiCid);
- length->set_recognized_kind(MethodRecognizer::kStringBaseLength);
+ LoadFieldInstr* length = BuildLoadStringLength(str->Copy());
InsertBefore(call, length, NULL, Definition::kValue);
InsertBefore(call,
new CheckArrayBoundInstr(new Value(length),
@@ -1367,6 +1367,8 @@
case kInt8ArrayCid:
case kUint8ArrayCid:
case kUint8ClampedArrayCid:
+ case kExternalUint8ArrayCid:
+ case kExternalUint8ClampedArrayCid:
case kInt16ArrayCid:
case kUint16ArrayCid:
case kInt32ArrayCid:
@@ -1965,192 +1967,13 @@
// If one of the input is not a boxable number (Mint, Double, Bigint), no
// need for number checks.
- if (!MayBeBoxableNumber(instr->left()->ResultCid()) ||
- !MayBeBoxableNumber(instr->right()->ResultCid())) {
+ if (!MayBeBoxableNumber(instr->left()->Type()->ToCid()) ||
+ !MayBeBoxableNumber(instr->right()->Type()->ToCid())) {
instr->set_needs_number_check(false);
}
}
-// SminessPropagator ensures that CheckSmis are eliminated across phis.
-class SminessPropagator : public ValueObject {
- public:
- explicit SminessPropagator(FlowGraph* flow_graph)
- : flow_graph_(flow_graph),
- known_smis_(new BitVector(flow_graph_->current_ssa_temp_index())),
- rollback_checks_(10),
- in_worklist_(NULL),
- worklist_(0) { }
-
- void Propagate();
-
- private:
- void PropagateSminessRecursive(BlockEntryInstr* block);
- void AddToWorklist(PhiInstr* phi);
- PhiInstr* RemoveLastFromWorklist();
- void ProcessPhis();
-
- FlowGraph* flow_graph_;
-
- BitVector* known_smis_;
- GrowableArray<intptr_t> rollback_checks_;
-
- BitVector* in_worklist_;
- GrowableArray<PhiInstr*> worklist_;
-
- DISALLOW_COPY_AND_ASSIGN(SminessPropagator);
-};
-
-
-void SminessPropagator::AddToWorklist(PhiInstr* phi) {
- if (in_worklist_ == NULL) {
- in_worklist_ = new BitVector(flow_graph_->current_ssa_temp_index());
- }
- if (!in_worklist_->Contains(phi->ssa_temp_index())) {
- in_worklist_->Add(phi->ssa_temp_index());
- worklist_.Add(phi);
- }
-}
-
-
-PhiInstr* SminessPropagator::RemoveLastFromWorklist() {
- PhiInstr* phi = worklist_.RemoveLast();
- ASSERT(in_worklist_->Contains(phi->ssa_temp_index()));
- in_worklist_->Remove(phi->ssa_temp_index());
- return phi;
-}
-
-
-static bool IsDefinitelySmiPhi(PhiInstr* phi) {
- for (intptr_t i = 0; i < phi->InputCount(); i++) {
- const intptr_t cid = phi->InputAt(i)->ResultCid();
- if (cid != kSmiCid) {
- return false;
- }
- }
- return true;
-}
-
-
-static bool IsPossiblySmiPhi(PhiInstr* phi) {
- for (intptr_t i = 0; i < phi->InputCount(); i++) {
- const intptr_t cid = phi->InputAt(i)->ResultCid();
- if ((cid != kSmiCid) && (cid != kDynamicCid)) {
- return false;
- }
- }
- return true;
-}
-
-
-void SminessPropagator::ProcessPhis() {
- // First optimistically mark all possible smi-phis: phi is possibly a smi if
- // its operands are either smis or phis in the worklist.
- for (intptr_t i = 0; i < worklist_.length(); i++) {
- PhiInstr* phi = worklist_[i];
- ASSERT(phi->GetPropagatedCid() == kDynamicCid);
- phi->SetPropagatedCid(kSmiCid);
-
- // Append all phis that use this phi and can potentially be smi to the
- // end of worklist.
- for (Value* use = phi->input_use_list();
- use != NULL;
- use = use->next_use()) {
- PhiInstr* phi_use = use->instruction()->AsPhi();
- if ((phi_use != NULL) &&
- (phi_use->GetPropagatedCid() == kDynamicCid) &&
- IsPossiblySmiPhi(phi_use)) {
- AddToWorklist(phi_use);
- }
- }
- }
-
- // Now unmark phis that are not definitely smi: that is have only
- // smi operands.
- while (!worklist_.is_empty()) {
- PhiInstr* phi = RemoveLastFromWorklist();
- if (!IsDefinitelySmiPhi(phi)) {
- // Phi result is not a smi. Propagate this fact to phis that depend on it.
- phi->SetPropagatedCid(kDynamicCid);
- for (Value* use = phi->input_use_list();
- use != NULL;
- use = use->next_use()) {
- PhiInstr* phi_use = use->instruction()->AsPhi();
- if ((phi_use != NULL) && (phi_use->GetPropagatedCid() == kSmiCid)) {
- AddToWorklist(phi_use);
- }
- }
- }
- }
-}
-
-
-void SminessPropagator::PropagateSminessRecursive(BlockEntryInstr* block) {
- const intptr_t rollback_point = rollback_checks_.length();
-
- for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
- Instruction* instr = it.Current();
- if (instr->IsCheckSmi()) {
- const intptr_t value_ssa_index =
- instr->InputAt(0)->definition()->ssa_temp_index();
- if (!known_smis_->Contains(value_ssa_index)) {
- known_smis_->Add(value_ssa_index);
- rollback_checks_.Add(value_ssa_index);
- }
- } else if (instr->IsBranch()) {
- for (intptr_t i = 0; i < instr->InputCount(); i++) {
- Value* use = instr->InputAt(i);
- if (known_smis_->Contains(use->definition()->ssa_temp_index())) {
- use->set_reaching_cid(kSmiCid);
- }
- }
- }
- }
-
- for (intptr_t i = 0; i < block->dominated_blocks().length(); ++i) {
- PropagateSminessRecursive(block->dominated_blocks()[i]);
- }
-
- if (block->last_instruction()->SuccessorCount() == 1 &&
- block->last_instruction()->SuccessorAt(0)->IsJoinEntry()) {
- JoinEntryInstr* join =
- block->last_instruction()->SuccessorAt(0)->AsJoinEntry();
- intptr_t pred_index = join->IndexOfPredecessor(block);
- ASSERT(pred_index >= 0);
- if (join->phis() != NULL) {
- for (intptr_t i = 0; i < join->phis()->length(); ++i) {
- PhiInstr* phi = (*join->phis())[i];
- if (phi == NULL) continue;
- Value* use = phi->InputAt(pred_index);
- const intptr_t value_ssa_index = use->definition()->ssa_temp_index();
- if (known_smis_->Contains(value_ssa_index) &&
- (phi->GetPropagatedCid() != kSmiCid)) {
- use->set_reaching_cid(kSmiCid);
- AddToWorklist(phi);
- }
- }
- }
- }
-
- for (intptr_t i = rollback_point; i < rollback_checks_.length(); i++) {
- known_smis_->Remove(rollback_checks_[i]);
- }
- rollback_checks_.TruncateTo(rollback_point);
-}
-
-
-void SminessPropagator::Propagate() {
- PropagateSminessRecursive(flow_graph_->graph_entry());
- ProcessPhis();
-}
-
-
-void FlowGraphOptimizer::PropagateSminess() {
- SminessPropagator propagator(flow_graph_);
- propagator.Propagate();
-}
-
-
// Range analysis for smi values.
class RangeAnalysis : public ValueObject {
public:
@@ -2268,7 +2091,7 @@
Instruction* current = instr_it.Current();
Definition* defn = current->AsDefinition();
if (defn != NULL) {
- if ((defn->GetPropagatedCid() == kSmiCid) &&
+ if ((defn->Type()->ToCid() == kSmiCid) &&
(defn->ssa_temp_index() != -1)) {
smi_values_.Add(defn);
}
@@ -2281,7 +2104,7 @@
if (join != NULL) {
for (PhiIterator phi_it(join); !phi_it.Done(); phi_it.Advance()) {
PhiInstr* current = phi_it.Current();
- if (current->GetPropagatedCid() == kSmiCid) {
+ if ((current->Type()->ToCid() == kSmiCid)) {
smi_values_.Add(current);
}
}
@@ -2736,261 +2559,6 @@
}
-void FlowGraphTypePropagator::VisitBlocks() {
- ASSERT(current_iterator_ == NULL);
- for (intptr_t i = 0; i < block_order_.length(); ++i) {
- BlockEntryInstr* entry = block_order_[i];
- entry->Accept(this);
- ForwardInstructionIterator it(entry);
- current_iterator_ = ⁢
- for (; !it.Done(); it.Advance()) {
- Instruction* current = it.Current();
- // No need to propagate the input types of the instruction, as long as
- // PhiInstr's are handled as part of JoinEntryInstr.
-
- // Visit the instruction and possibly eliminate type checks.
- current->Accept(this);
- // The instruction may have been removed from the graph.
- Definition* defn = current->AsDefinition();
- if ((defn != NULL) &&
- !defn->IsPushArgument() &&
- (defn->previous() != NULL)) {
- // Cache the propagated computation type.
- AbstractType& type = AbstractType::Handle(defn->CompileType());
- still_changing_ = defn->SetPropagatedType(type) || still_changing_;
-
- // Propagate class ids.
- const intptr_t cid = defn->ResultCid();
- still_changing_ = defn->SetPropagatedCid(cid) || still_changing_;
- }
- }
- current_iterator_ = NULL;
- }
-}
-
-
-void FlowGraphTypePropagator::VisitAssertAssignable(
- AssertAssignableInstr* instr) {
- bool is_null, is_instance;
- if (FLAG_eliminate_type_checks &&
- !instr->is_eliminated() &&
- ((instr->value()->CanComputeIsNull(&is_null) && is_null) ||
- (instr->value()->CanComputeIsInstanceOf(instr->dst_type(), &is_instance)
- && is_instance))) {
- // TODO(regis): Remove is_eliminated_ field and support.
- instr->eliminate();
-
- Value* use = instr->value();
- ASSERT(use != NULL);
- Definition* result = use->definition();
- ASSERT(result != NULL);
- // Replace uses and remove the current instruction via the iterator.
- instr->ReplaceUsesWith(result);
- ASSERT(current_iterator()->Current() == instr);
- current_iterator()->RemoveCurrentFromGraph();
- if (FLAG_trace_optimization) {
- OS::Print("Replacing v%"Pd" with v%"Pd"\n",
- instr->ssa_temp_index(),
- result->ssa_temp_index());
- }
-
- if (FLAG_trace_type_check_elimination) {
- FlowGraphPrinter::PrintTypeCheck(parsed_function(),
- instr->token_pos(),
- instr->value(),
- instr->dst_type(),
- instr->dst_name(),
- instr->is_eliminated());
- }
- }
-}
-
-
-void FlowGraphTypePropagator::VisitAssertBoolean(AssertBooleanInstr* instr) {
- bool is_null, is_bool;
- if (FLAG_eliminate_type_checks &&
- !instr->is_eliminated() &&
- instr->value()->CanComputeIsNull(&is_null) &&
- !is_null &&
- instr->value()->CanComputeIsInstanceOf(Type::Handle(Type::BoolType()),
- &is_bool) &&
- is_bool) {
- // TODO(regis): Remove is_eliminated_ field and support.
- instr->eliminate();
- Value* use = instr->value();
- Definition* result = use->definition();
- ASSERT(result != NULL);
- // Replace uses and remove the current instruction via the iterator.
- instr->ReplaceUsesWith(result);
- ASSERT(current_iterator()->Current() == instr);
- current_iterator()->RemoveCurrentFromGraph();
- if (FLAG_trace_optimization) {
- OS::Print("Replacing v%"Pd" with v%"Pd"\n",
- instr->ssa_temp_index(),
- result->ssa_temp_index());
- }
-
- if (FLAG_trace_type_check_elimination) {
- FlowGraphPrinter::PrintTypeCheck(parsed_function(),
- instr->token_pos(),
- instr->value(),
- Type::Handle(Type::BoolType()),
- Symbols::BooleanExpression(),
- instr->is_eliminated());
- }
- }
-}
-
-
-void FlowGraphTypePropagator::VisitInstanceOf(InstanceOfInstr* instr) {
- bool is_null;
- bool is_instance = false;
- if (FLAG_eliminate_type_checks &&
- instr->value()->CanComputeIsNull(&is_null) &&
- (is_null ||
- instr->value()->CanComputeIsInstanceOf(instr->type(), &is_instance))) {
- bool val = instr->negate_result() ? !is_instance : is_instance;
- Definition* result = new ConstantInstr(val ? Bool::True() : Bool::False());
- result->set_ssa_temp_index(flow_graph_->alloc_ssa_temp_index());
- result->InsertBefore(instr);
- // Replace uses and remove the current instruction via the iterator.
- instr->ReplaceUsesWith(result);
- ASSERT(current_iterator()->Current() == instr);
- current_iterator()->RemoveCurrentFromGraph();
- if (FLAG_trace_optimization) {
- OS::Print("Replacing v%"Pd" with v%"Pd"\n",
- instr->ssa_temp_index(),
- result->ssa_temp_index());
- }
-
- if (FLAG_trace_type_check_elimination) {
- FlowGraphPrinter::PrintTypeCheck(parsed_function(),
- instr->token_pos(),
- instr->value(),
- instr->type(),
- Symbols::InstanceOf(),
- /* eliminated = */ true);
- }
- }
-}
-
-
-void FlowGraphTypePropagator::VisitGraphEntry(GraphEntryInstr* graph_entry) {
- // Visit incoming parameters.
- for (intptr_t i = 0; i < graph_entry->initial_definitions()->length(); i++) {
- ParameterInstr* param =
- (*graph_entry->initial_definitions())[i]->AsParameter();
- if (param != NULL) VisitParameter(param);
- }
-}
-
-
-void FlowGraphTypePropagator::VisitJoinEntry(JoinEntryInstr* join_entry) {
- if (join_entry->phis() != NULL) {
- for (intptr_t i = 0; i < join_entry->phis()->length(); ++i) {
- PhiInstr* phi = (*join_entry->phis())[i];
- if (phi != NULL) {
- VisitPhi(phi);
- }
- }
- }
-}
-
-
-// TODO(srdjan): Investigate if the propagated cid should be more specific.
-void FlowGraphTypePropagator::VisitPushArgument(PushArgumentInstr* push) {
- if (!push->has_propagated_cid()) push->SetPropagatedCid(kDynamicCid);
-}
-
-
-void FlowGraphTypePropagator::VisitPhi(PhiInstr* phi) {
- // We could set the propagated type of the phi to the least upper bound of its
- // input propagated types. However, keeping all propagated types allows us to
- // optimize method dispatch.
- // TODO(regis): Support a set of propagated types. For now, we compute the
- // least specific of the input propagated types.
- AbstractType& type = AbstractType::Handle(phi->LeastSpecificInputType());
- bool changed = phi->SetPropagatedType(type);
- if (changed) {
- still_changing_ = true;
- }
-
- // Merge class ids: if any two inputs have different class ids then result
- // is kDynamicCid.
- intptr_t merged_cid = kIllegalCid;
- for (intptr_t i = 0; i < phi->InputCount(); i++) {
- // Result cid of UseVal can be kIllegalCid if the referred definition
- // has not been visited yet.
- intptr_t cid = phi->InputAt(i)->ResultCid();
- if (cid == kIllegalCid) {
- still_changing_ = true;
- continue;
- }
- if (merged_cid == kIllegalCid) {
- // First time set.
- merged_cid = cid;
- } else if (merged_cid != cid) {
- merged_cid = kDynamicCid;
- }
- }
- if (merged_cid == kIllegalCid) {
- merged_cid = kDynamicCid;
- }
- changed = phi->SetPropagatedCid(merged_cid);
- if (changed) {
- still_changing_ = true;
- }
-}
-
-
-void FlowGraphTypePropagator::VisitParameter(ParameterInstr* param) {
- // TODO(regis): Once we inline functions, the propagated type of the formal
- // parameter will reflect the compile type of the passed-in argument.
- // For now, we do not know anything about the argument type and therefore set
- // it to the DynamicType, unless the argument is a compiler generated value,
- // i.e. the receiver argument or the constructor phase argument.
- AbstractType& param_type = AbstractType::Handle(Type::DynamicType());
- param->SetPropagatedCid(kDynamicCid);
- bool param_type_is_known = false;
- if (param->index() == 0) {
- const Function& function = parsed_function().function();
- if ((function.IsDynamicFunction() || function.IsConstructor())) {
- // Parameter is the receiver .
- param_type_is_known = true;
- }
- } else if ((param->index() == 1) &&
- parsed_function().function().IsConstructor()) {
- // Parameter is the constructor phase.
- param_type_is_known = true;
- }
- if (param_type_is_known) {
- LocalScope* scope = parsed_function().node_sequence()->scope();
- param_type = scope->VariableAt(param->index())->type().raw();
- if (FLAG_use_cha) {
- const intptr_t cid = Class::Handle(param_type.type_class()).id();
- if (!CHA::HasSubclasses(cid)) {
- // Receiver's class has no subclasses.
- param->SetPropagatedCid(cid);
- }
- }
- }
- bool changed = param->SetPropagatedType(param_type);
- if (changed) {
- still_changing_ = true;
- }
-}
-
-
-void FlowGraphTypePropagator::PropagateTypes() {
- // TODO(regis): Is there a way to make this more efficient, e.g. by visiting
- // only blocks depending on blocks that have changed and not the whole graph.
- do {
- still_changing_ = false;
- VisitBlocks();
- } while (still_changing_);
-}
-
-
static BlockEntryInstr* FindPreHeader(BlockEntryInstr* header) {
for (intptr_t j = 0; j < header->PredecessorCount(); ++j) {
BlockEntryInstr* candidate = header->PredecessorAt(j);
@@ -3035,7 +2603,7 @@
return;
}
- if (phi->GetPropagatedCid() == kSmiCid) {
+ if (phi->Type()->ToCid() == kSmiCid) {
current->UnuseAllInputs();
it->RemoveCurrentFromGraph();
return;
@@ -3047,8 +2615,9 @@
intptr_t non_smi_input = kNotFound;
for (intptr_t i = 0; i < phi->InputCount(); ++i) {
Value* input = phi->InputAt(i);
- if (input->ResultCid() != kSmiCid) {
- if ((non_smi_input != kNotFound) || (input->ResultCid() != kDynamicCid)) {
+ if (input->Type()->ToCid() != kSmiCid) {
+ if ((non_smi_input != kNotFound) ||
+ (input->Type()->ToCid() != kDynamicCid)) {
// There are multiple kDynamicCid inputs or there is an input that is
// known to be non-smi.
return;
@@ -3072,7 +2641,7 @@
current->value()->set_definition(non_smi_input_defn);
non_smi_input_defn->AddInputUse(current->value());
- phi->SetPropagatedCid(kSmiCid);
+ phi->Type()->ReplaceWith(CompileType::FromCid(kSmiCid));
}
@@ -4118,10 +3687,10 @@
if (IsNonConstant(left) || IsNonConstant(right)) {
// TODO(vegorov): incorporate nullability information into the lattice.
- if ((left.IsNull() && (instr->right()->ResultCid() != kDynamicCid)) ||
- (right.IsNull() && (instr->left()->ResultCid() != kDynamicCid))) {
- bool result = left.IsNull() ? (instr->right()->ResultCid() == kNullCid)
- : (instr->left()->ResultCid() == kNullCid);
+ if ((left.IsNull() && instr->right()->Type()->HasDecidableNullability()) ||
+ (right.IsNull() && instr->left()->Type()->HasDecidableNullability())) {
+ bool result = left.IsNull() ? instr->right()->Type()->IsNull()
+ : instr->left()->Type()->IsNull();
if (instr->kind() == Token::kNE_STRICT) result = !result;
SetValue(instr, result ? Bool::True() : Bool::False());
} else {
@@ -4274,7 +3843,7 @@
if ((instr->recognized_kind() == MethodRecognizer::kObjectArrayLength) &&
(instr->value()->definition()->IsCreateArray())) {
const intptr_t length =
- instr->value()->definition()->AsCreateArray()->ArgumentCount();
+ instr->value()->definition()->AsCreateArray()->num_elements();
const Object& result = Smi::ZoneHandle(Smi::New(length));
SetValue(instr, result);
return;
diff --git a/runtime/vm/flow_graph_optimizer.h b/runtime/vm/flow_graph_optimizer.h
index b53054e..a0922ef 100644
--- a/runtime/vm/flow_graph_optimizer.h
+++ b/runtime/vm/flow_graph_optimizer.h
@@ -121,39 +121,6 @@
class ParsedFunction;
-class FlowGraphTypePropagator : public FlowGraphVisitor {
- public:
- explicit FlowGraphTypePropagator(FlowGraph* flow_graph)
- : FlowGraphVisitor(flow_graph->reverse_postorder()),
- parsed_function_(flow_graph->parsed_function()),
- flow_graph_(flow_graph),
- still_changing_(false) { }
- virtual ~FlowGraphTypePropagator() { }
-
- const ParsedFunction& parsed_function() const { return parsed_function_; }
-
- void PropagateTypes();
-
- private:
- virtual void VisitBlocks();
-
- virtual void VisitAssertAssignable(AssertAssignableInstr* instr);
- virtual void VisitAssertBoolean(AssertBooleanInstr* instr);
- virtual void VisitInstanceOf(InstanceOfInstr* instr);
-
- virtual void VisitGraphEntry(GraphEntryInstr* graph_entry);
- virtual void VisitJoinEntry(JoinEntryInstr* join_entry);
- virtual void VisitPhi(PhiInstr* phi);
- virtual void VisitParameter(ParameterInstr* param);
- virtual void VisitPushArgument(PushArgumentInstr* bind);
-
- const ParsedFunction& parsed_function_;
- FlowGraph* flow_graph_;
- bool still_changing_;
- DISALLOW_COPY_AND_ASSIGN(FlowGraphTypePropagator);
-};
-
-
// Loop invariant code motion.
class LICM : public AllStatic {
public:
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
new file mode 100644
index 0000000..020172c
--- /dev/null
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -0,0 +1,734 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#include "vm/flow_graph_type_propagator.h"
+
+#include "vm/cha.h"
+#include "vm/bit_vector.h"
+
+namespace dart {
+
+DEFINE_FLAG(bool, trace_type_propagation, false,
+ "Trace flow graph type propagation");
+
+DECLARE_FLAG(bool, enable_type_checks);
+DECLARE_FLAG(bool, use_cha);
+
+
+FlowGraphTypePropagator::FlowGraphTypePropagator(FlowGraph* flow_graph)
+ : FlowGraphVisitor(flow_graph->reverse_postorder()),
+ flow_graph_(flow_graph),
+ types_(flow_graph->current_ssa_temp_index()),
+ in_worklist_(new BitVector(flow_graph->current_ssa_temp_index())) {
+ for (intptr_t i = 0; i < flow_graph->current_ssa_temp_index(); i++) {
+ types_.Add(NULL);
+ }
+}
+
+
+void FlowGraphTypePropagator::Propagate() {
+ // Walk dominator tree and propagate reaching types to all Values.
+ // Collect all phis for a fix point iteration.
+ PropagateRecursive(flow_graph_->graph_entry());
+
+#ifdef DEBUG
+ // Initially work-list contains only phis.
+ for (intptr_t i = 0; i < worklist_.length(); i++) {
+ ASSERT(worklist_[i]->IsPhi());
+ ASSERT(worklist_[i]->Type()->IsNone());
+ }
+#endif
+
+ // Iterate until fix point is reached updating types of definitions.
+ while (!worklist_.is_empty()) {
+ Definition* def = RemoveLastFromWorklist();
+ if (FLAG_trace_type_propagation) {
+ OS::Print("recomputing type of v%"Pd": %s\n",
+ def->ssa_temp_index(),
+ def->Type()->ToCString());
+ }
+ if (def->RecomputeType()) {
+ if (FLAG_trace_type_propagation) {
+ OS::Print(" ... new type %s\n", def->Type()->ToCString());
+ }
+ for (Value::Iterator it(def->input_use_list());
+ !it.Done();
+ it.Advance()) {
+ Definition* use_defn = it.Current()->instruction()->AsDefinition();
+ if (use_defn != NULL) {
+ AddToWorklist(use_defn);
+ }
+ }
+ }
+ }
+}
+
+
+void FlowGraphTypePropagator::PropagateRecursive(BlockEntryInstr* block) {
+ const intptr_t rollback_point = rollback_.length();
+
+ block->Accept(this);
+
+ for (ForwardInstructionIterator it(block); !it.Done(); it.Advance()) {
+ Instruction* instr = it.Current();
+
+ for (intptr_t i = 0; i < instr->InputCount(); i++) {
+ VisitValue(instr->InputAt(i));
+ }
+ instr->Accept(this);
+ }
+
+ GotoInstr* goto_instr = block->last_instruction()->AsGoto();
+ if (goto_instr != NULL) {
+ JoinEntryInstr* join = goto_instr->successor();
+ intptr_t pred_index = join->IndexOfPredecessor(block);
+ ASSERT(pred_index >= 0);
+ for (PhiIterator it(join); !it.Done(); it.Advance()) {
+ VisitValue(it.Current()->InputAt(pred_index));
+ }
+ }
+
+ for (intptr_t i = 0; i < block->dominated_blocks().length(); ++i) {
+ PropagateRecursive(block->dominated_blocks()[i]);
+ }
+
+ for (intptr_t i = rollback_.length() - 1; i >= rollback_point; i--) {
+ types_[rollback_[i].index()] = rollback_[i].type();
+ }
+ rollback_.TruncateTo(rollback_point);
+}
+
+
+CompileType* FlowGraphTypePropagator::TypeOf(Definition* def) {
+ const intptr_t index = def->ssa_temp_index();
+
+ CompileType* type = types_[index];
+ if (type == NULL) {
+ type = types_[index] = def->Type();
+ ASSERT(type != NULL);
+ }
+ return type;
+}
+
+
+void FlowGraphTypePropagator::SetTypeOf(Definition* def, CompileType* type) {
+ const intptr_t index = def->ssa_temp_index();
+ rollback_.Add(RollbackEntry(index, types_[index]));
+ types_[index] = type;
+}
+
+
+void FlowGraphTypePropagator::SetCid(Definition* def, intptr_t cid) {
+ CompileType* current = TypeOf(def);
+ if (current->ToCid() == cid) return;
+
+ SetTypeOf(def, CompileType::FromCid(cid));
+}
+
+
+void FlowGraphTypePropagator::VisitValue(Value* value) {
+ CompileType* type = TypeOf(value->definition());
+ value->SetReachingType(type);
+
+ if (FLAG_trace_type_propagation) {
+ OS::Print("reaching type to v%"Pd" for v%"Pd" is %s\n",
+ value->instruction()->IsDefinition() ?
+ value->instruction()->AsDefinition()->ssa_temp_index() : -1,
+ value->definition()->ssa_temp_index(),
+ type->ToCString());
+ }
+}
+
+
+void FlowGraphTypePropagator::VisitJoinEntry(JoinEntryInstr* join) {
+ for (PhiIterator it(join); !it.Done(); it.Advance()) {
+ if (it.Current()->is_alive()) {
+ worklist_.Add(it.Current());
+ }
+ }
+}
+
+
+void FlowGraphTypePropagator::VisitCheckSmi(CheckSmiInstr* check) {
+ SetCid(check->value()->definition(), kSmiCid);
+}
+
+
+void FlowGraphTypePropagator::VisitCheckClass(CheckClassInstr* check) {
+ if ((check->unary_checks().NumberOfChecks() != 1) ||
+ check->AffectedBySideEffect()) {
+ // TODO(vegorov): If check is affected by side-effect we can still propagate
+ // the type further but not the cid.
+ return;
+ }
+
+ SetCid(check->value()->definition(),
+ check->unary_checks().GetReceiverClassIdAt(0));
+}
+
+
+void FlowGraphTypePropagator::AddToWorklist(Definition* defn) {
+ if (defn->ssa_temp_index() == -1) {
+ return;
+ }
+
+ const intptr_t index = defn->ssa_temp_index();
+ if (!in_worklist_->Contains(index)) {
+ worklist_.Add(defn);
+ in_worklist_->Add(index);
+ }
+}
+
+
+Definition* FlowGraphTypePropagator::RemoveLastFromWorklist() {
+ Definition* defn = worklist_.RemoveLast();
+ ASSERT(defn->ssa_temp_index() != -1);
+ in_worklist_->Remove(defn->ssa_temp_index());
+ return defn;
+}
+
+
+void CompileType::Union(CompileType* other) {
+ if (other->IsNone()) {
+ return;
+ }
+
+ if (IsNone()) {
+ ReplaceWith(other);
+ return;
+ }
+
+ is_nullable_ = is_nullable_ || other->is_nullable_;
+
+ if (ToNullableCid() == kNullCid) {
+ cid_ = other->cid_;
+ type_ = other->type_;
+ return;
+ }
+
+ if (other->ToNullableCid() == kNullCid) {
+ return;
+ }
+
+ if (ToNullableCid() != other->ToNullableCid()) {
+ ASSERT(cid_ != kNullCid);
+ cid_ = kDynamicCid;
+ }
+
+ if (ToAbstractType()->IsMoreSpecificThan(*other->ToAbstractType(), NULL)) {
+ type_ = other->ToAbstractType();
+ } else if (ToAbstractType()->IsMoreSpecificThan(*ToAbstractType(), NULL)) {
+ // Nothing to do.
+ } else {
+ // Can't unify.
+ type_ = &Type::ZoneHandle(Type::DynamicType());
+ }
+}
+
+
+static bool IsNullableCid(intptr_t cid) {
+ ASSERT(cid != kIllegalCid);
+ return cid == kNullCid || cid == kDynamicCid;
+}
+
+
+CompileType* CompileType::New(intptr_t cid, const AbstractType& type) {
+ return new CompileType(IsNullableCid(cid), cid, &type);
+}
+
+
+CompileType* CompileType::FromAbstractType(const AbstractType& type,
+ bool is_nullable) {
+ return new CompileType(is_nullable, kIllegalCid, &type);
+}
+
+
+CompileType* CompileType::FromCid(intptr_t cid) {
+ return new CompileType(IsNullableCid(cid), cid, NULL);
+}
+
+
+CompileType* CompileType::Dynamic() {
+ return New(kDynamicCid, Type::ZoneHandle(Type::DynamicType()));
+}
+
+
+CompileType* CompileType::Null() {
+ return New(kNullCid, Type::ZoneHandle(Type::NullType()));
+}
+
+
+CompileType* CompileType::Bool() {
+ return New(kBoolCid, Type::ZoneHandle(Type::BoolType()));
+}
+
+
+CompileType* CompileType::Int() {
+ return FromAbstractType(Type::ZoneHandle(Type::IntType()), kNonNullable);
+}
+
+
+intptr_t CompileType::ToCid() {
+ if ((cid_ == kNullCid) || (cid_ == kDynamicCid)) {
+ return cid_;
+ }
+
+ return is_nullable_ ? static_cast<intptr_t>(kDynamicCid) : ToNullableCid();
+}
+
+
+intptr_t CompileType::ToNullableCid() {
+ if (cid_ == kIllegalCid) {
+ ASSERT(type_ != NULL);
+
+ if (type_->IsMalformed()) {
+ cid_ = kDynamicCid;
+ } else if (type_->IsVoidType()) {
+ cid_ = kNullCid;
+ } else if (FLAG_use_cha && type_->HasResolvedTypeClass()) {
+ const intptr_t cid = Class::Handle(type_->type_class()).id();
+ if (!CHA::HasSubclasses(cid)) {
+ cid_ = cid;
+ }
+ } else {
+ cid_ = kDynamicCid;
+ }
+ }
+
+ return cid_;
+}
+
+
+bool CompileType::HasDecidableNullability() {
+ return !is_nullable_ || IsNull();
+}
+
+
+bool CompileType::IsNull() {
+ return (ToCid() == kNullCid);
+}
+
+
+const AbstractType* CompileType::ToAbstractType() {
+ if (type_ == NULL) {
+ ASSERT(cid_ != kIllegalCid);
+
+ const Class& type_class =
+ Class::Handle(Isolate::Current()->class_table()->At(cid_));
+
+ if (type_class.HasTypeArguments()) {
+ type_ = &Type::ZoneHandle(Type::DynamicType());
+ return type_;
+ }
+
+ type_ = &Type::ZoneHandle(Type::NewNonParameterizedType(type_class));
+ }
+
+ return type_;
+}
+
+
+bool CompileType::CanComputeIsInstanceOf(const AbstractType& type,
+ bool is_nullable,
+ bool* is_instance) {
+ ASSERT(is_instance != NULL);
+ // We cannot give an answer if the given type is malformed.
+ if (type.IsMalformed()) {
+ return false;
+ }
+
+ if (type.IsDynamicType() || type.IsObjectType()) {
+ *is_instance = true;
+ return true;
+ }
+
+ if (IsNone()) {
+ return false;
+ }
+
+ // We should never test for an instance of null.
+ ASSERT(!type.IsNullType());
+
+ // Consider the compile type of the value.
+ const AbstractType& compile_type = *ToAbstractType();
+ if (compile_type.IsMalformed()) {
+ return false;
+ }
+
+ // If the compile type of the value is void, we are type checking the result
+ // of a void function, which was checked to be null at the return statement
+ // inside the function.
+ if (compile_type.IsVoidType()) {
+ ASSERT(FLAG_enable_type_checks);
+ *is_instance = true;
+ return true;
+ }
+
+ // The Null type is only a subtype of Object and of dynamic.
+ // Functions that do not explicitly return a value, implicitly return null,
+ // except generative constructors, which return the object being constructed.
+ // It is therefore acceptable for void functions to return null.
+ if (compile_type.IsNullType()) {
+ *is_instance = is_nullable ||
+ type.IsObjectType() || type.IsDynamicType() || type.IsVoidType();
+ return true;
+ }
+
+ // A non-null value is not an instance of void.
+ if (type.IsVoidType()) {
+ *is_instance = IsNull();
+ return HasDecidableNullability();
+ }
+
+ // If the value can be null then we can't eliminate the
+ // check unless null is allowed.
+ if (is_nullable_ && !is_nullable) {
+ return false;
+ }
+
+ Error& malformed_error = Error::Handle();
+ *is_instance = compile_type.IsMoreSpecificThan(type, &malformed_error);
+ return malformed_error.IsNull() && *is_instance;
+}
+
+
+bool CompileType::IsMoreSpecificThan(const AbstractType& other) {
+ return !IsNone() && ToAbstractType()->IsMoreSpecificThan(other, NULL);
+}
+
+
+CompileType* Value::Type() {
+ if (reaching_type_ == NULL) {
+ reaching_type_ = definition()->Type();
+ }
+ return reaching_type_;
+}
+
+
+CompileType* PhiInstr::ComputeInitialType() const {
+ // Initially type of phis is unknown until type propagation is run
+ // for the first time.
+ return CompileType::None();
+}
+
+
+bool PhiInstr::RecomputeType() {
+ if (!is_alive()) {
+ return false;
+ }
+
+ CompileType* result = CompileType::None();
+
+ for (intptr_t i = 0; i < InputCount(); i++) {
+ if (FLAG_trace_type_propagation) {
+ OS::Print(" phi %"Pd" input %"Pd": v%"Pd" has reaching type %s\n",
+ ssa_temp_index(),
+ i,
+ InputAt(i)->definition()->ssa_temp_index(),
+ InputAt(i)->Type()->ToCString());
+ }
+ result->Union(InputAt(i)->Type());
+ }
+
+ if (result->IsNone()) {
+ ASSERT(Type()->IsNone());
+ return false;
+ }
+
+ if (Type()->IsNone() || !Type()->IsEqualTo(result)) {
+ Type()->ReplaceWith(result);
+ return true;
+ }
+
+ return false;
+}
+
+
+
+CompileType* ParameterInstr::ComputeInitialType() const {
+ // Note that returning the declared type of the formal parameter would be
+ // incorrect, because ParameterInstr is used as input to the type check
+ // verifying the run time type of the passed-in parameter and this check would
+ // always be wrongly eliminated.
+ return CompileType::Dynamic();
+}
+
+
+CompileType* PushArgumentInstr::ComputeInitialType() const {
+ return CompileType::Dynamic();
+}
+
+
+CompileType* ConstantInstr::ComputeInitialType() const {
+ if (value().IsNull()) {
+ return CompileType::Null();
+ }
+
+ if (value().IsInstance()) {
+ return CompileType::New(
+ Class::Handle(value().clazz()).id(),
+ AbstractType::ZoneHandle(Instance::Cast(value()).GetType()));
+ } else {
+ ASSERT(value().IsAbstractTypeArguments());
+ return CompileType::Dynamic();
+ }
+}
+
+
+CompileType* AssertAssignableInstr::ComputeInitialType() const {
+ CompileType* value_type = value()->Type();
+ if (value_type->IsMoreSpecificThan(dst_type())) {
+ return value_type;
+ }
+ return CompileType::FromAbstractType(dst_type());
+}
+
+
+bool AssertAssignableInstr::RecomputeType() {
+ CompileType* value_type = value()->Type();
+ if (value_type == Type()) {
+ return false;
+ }
+
+ if (value_type->IsMoreSpecificThan(dst_type()) &&
+ !Type()->IsEqualTo(value_type)) {
+ Type()->ReplaceWith(value_type);
+ return true;
+ }
+
+ return false;
+}
+
+
+CompileType* AssertBooleanInstr::ComputeInitialType() const {
+ return CompileType::Bool();
+}
+
+
+CompileType* ArgumentDefinitionTestInstr::ComputeInitialType() const {
+ return CompileType::Bool();
+}
+
+
+CompileType* BooleanNegateInstr::ComputeInitialType() const {
+ return CompileType::Bool();
+}
+
+
+CompileType* InstanceOfInstr::ComputeInitialType() const {
+ return CompileType::Bool();
+}
+
+
+CompileType* StrictCompareInstr::ComputeInitialType() const {
+ return CompileType::Bool();
+}
+
+
+CompileType* EqualityCompareInstr::ComputeInitialType() const {
+ return IsInlinedNumericComparison() ? CompileType::Bool()
+ : CompileType::Dynamic();
+}
+
+
+CompileType* RelationalOpInstr::ComputeInitialType() const {
+ return IsInlinedNumericComparison() ? CompileType::Bool()
+ : CompileType::Dynamic();
+}
+
+
+CompileType* CurrentContextInstr::ComputeInitialType() const {
+ return CompileType::FromCid(kContextCid);
+}
+
+
+CompileType* CloneContextInstr::ComputeInitialType() const {
+ return CompileType::FromCid(kContextCid);
+}
+
+
+CompileType* AllocateContextInstr::ComputeInitialType() const {
+ return CompileType::FromCid(kContextCid);
+}
+
+
+CompileType* StaticCallInstr::ComputeInitialType() const {
+ if (result_cid_ != kDynamicCid) {
+ return CompileType::FromCid(result_cid_);
+ }
+
+ if (FLAG_enable_type_checks) {
+ return CompileType::FromAbstractType(
+ AbstractType::ZoneHandle(function().result_type()));
+ }
+
+ return CompileType::Dynamic();
+}
+
+
+CompileType* LoadLocalInstr::ComputeInitialType() const {
+ if (FLAG_enable_type_checks) {
+ return CompileType::FromAbstractType(local().type());
+ }
+ return CompileType::Dynamic();
+}
+
+
+CompileType* StoreLocalInstr::ComputeInitialType() const {
+ // Returns stored value.
+ return value()->Type();
+}
+
+
+CompileType* StringFromCharCodeInstr::ComputeInitialType() const {
+ return CompileType::FromCid(cid_);
+}
+
+
+CompileType* StoreInstanceFieldInstr::ComputeInitialType() const {
+ return value()->Type();
+}
+
+
+CompileType* LoadStaticFieldInstr::ComputeInitialType() const {
+ if (FLAG_enable_type_checks) {
+ return CompileType::FromAbstractType(
+ AbstractType::ZoneHandle(field().type()));
+ }
+ return CompileType::Dynamic();
+}
+
+
+CompileType* StoreStaticFieldInstr::ComputeInitialType() const {
+ return value()->Type();
+}
+
+
+CompileType* CreateArrayInstr::ComputeInitialType() const {
+ return CompileType::FromAbstractType(type(), CompileType::kNonNullable);
+}
+
+
+CompileType* CreateClosureInstr::ComputeInitialType() const {
+ const Function& fun = function();
+ const Class& signature_class = Class::Handle(fun.signature_class());
+ return CompileType::FromAbstractType(
+ Type::ZoneHandle(signature_class.SignatureType()),
+ CompileType::kNonNullable);
+}
+
+
+CompileType* AllocateObjectInstr::ComputeInitialType() const {
+ // TODO(vegorov): Incorporate type arguments into the returned type.
+ return CompileType::FromCid(cid_);
+}
+
+
+CompileType* LoadFieldInstr::ComputeInitialType() const {
+ // Type may be null if the field is a VM field, e.g. context parent.
+ // Keep it as null for debug purposes and do not return dynamic in production
+ // mode, since misuse of the type would remain undetected.
+ if (type().IsNull()) {
+ return CompileType::Dynamic();
+ }
+
+ if (FLAG_enable_type_checks) {
+ return CompileType::FromAbstractType(type());
+ }
+
+ return CompileType::FromCid(result_cid_);
+}
+
+
+CompileType* StoreVMFieldInstr::ComputeInitialType() const {
+ return value()->Type();
+}
+
+
+CompileType* BinarySmiOpInstr::ComputeInitialType() const {
+ return CompileType::FromCid(kSmiCid);
+}
+
+
+CompileType* UnarySmiOpInstr::ComputeInitialType() const {
+ return CompileType::FromCid(kSmiCid);
+}
+
+
+CompileType* DoubleToSmiInstr::ComputeInitialType() const {
+ return CompileType::FromCid(kSmiCid);
+}
+
+
+CompileType* ConstraintInstr::ComputeInitialType() const {
+ return CompileType::FromCid(kSmiCid);
+}
+
+
+CompileType* BinaryMintOpInstr::ComputeInitialType() const {
+ return CompileType::Int();
+}
+
+
+CompileType* ShiftMintOpInstr::ComputeInitialType() const {
+ return CompileType::Int();
+}
+
+
+CompileType* UnaryMintOpInstr::ComputeInitialType() const {
+ return CompileType::Int();
+}
+
+
+CompileType* BoxIntegerInstr::ComputeInitialType() const {
+ return CompileType::Int();
+}
+
+
+CompileType* UnboxIntegerInstr::ComputeInitialType() const {
+ return CompileType::Int();
+}
+
+
+CompileType* DoubleToIntegerInstr::ComputeInitialType() const {
+ return CompileType::Int();
+}
+
+
+CompileType* BinaryDoubleOpInstr::ComputeInitialType() const {
+ return CompileType::FromCid(kDoubleCid);
+}
+
+
+CompileType* MathSqrtInstr::ComputeInitialType() const {
+ return CompileType::FromCid(kDoubleCid);
+}
+
+
+CompileType* UnboxDoubleInstr::ComputeInitialType() const {
+ return CompileType::FromCid(kDoubleCid);
+}
+
+
+CompileType* BoxDoubleInstr::ComputeInitialType() const {
+ return CompileType::FromCid(kDoubleCid);
+}
+
+
+CompileType* SmiToDoubleInstr::ComputeInitialType() const {
+ return CompileType::FromCid(kDoubleCid);
+}
+
+
+CompileType* DoubleToDoubleInstr::ComputeInitialType() const {
+ return CompileType::FromCid(kDoubleCid);
+}
+
+
+CompileType* InvokeMathCFunctionInstr::ComputeInitialType() const {
+ return CompileType::FromCid(kDoubleCid);
+}
+
+
+} // namespace dart
diff --git a/runtime/vm/flow_graph_type_propagator.h b/runtime/vm/flow_graph_type_propagator.h
new file mode 100644
index 0000000..fafd1b6
--- /dev/null
+++ b/runtime/vm/flow_graph_type_propagator.h
@@ -0,0 +1,77 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+#ifndef VM_FLOW_GRAPH_TYPE_PROPAGATOR_H_
+#define VM_FLOW_GRAPH_TYPE_PROPAGATOR_H_
+
+#include "vm/flow_graph.h"
+#include "vm/intermediate_language.h"
+
+namespace dart {
+
+class FlowGraphTypePropagator : public FlowGraphVisitor {
+ public:
+ explicit FlowGraphTypePropagator(FlowGraph* flow_graph);
+
+ void Propagate();
+
+ private:
+ void PropagateRecursive(BlockEntryInstr* block);
+
+ void VisitValue(Value* value);
+
+ virtual void VisitJoinEntry(JoinEntryInstr* instr);
+ virtual void VisitCheckSmi(CheckSmiInstr* instr);
+ virtual void VisitCheckClass(CheckClassInstr* instr);
+
+ // Current reaching type of the definition. Valid only during dominator tree
+ // traversal.
+ CompileType* TypeOf(Definition* def);
+
+ // Mark definition as having given compile type in all dominated instructions.
+ void SetTypeOf(Definition* def, CompileType* type);
+
+ // Mark definition as having given class id in all dominated instructions.
+ void SetCid(Definition* value, intptr_t cid);
+
+ void AddToWorklist(Definition* defn);
+ Definition* RemoveLastFromWorklist();
+
+ FlowGraph* flow_graph_;
+
+ // Mapping between SSA values and their current reaching types. Valid
+ // only during dominator tree traversal.
+ GrowableArray<CompileType*> types_;
+
+ // Worklist for fixpoint computation.
+ GrowableArray<Definition*> worklist_;
+ BitVector* in_worklist_;
+
+ // RollbackEntry is used to track and rollback changed in the types_ array
+ // done during dominator tree traversal.
+ class RollbackEntry {
+ public:
+ // Default constructor needed for the container.
+ RollbackEntry()
+ : index_(), type_() {
+ }
+
+ RollbackEntry(intptr_t index, CompileType* type)
+ : index_(index), type_(type) {
+ }
+
+ intptr_t index() const { return index_; }
+ CompileType* type() const { return type_; }
+
+ private:
+ intptr_t index_;
+ CompileType* type_;
+ };
+
+ GrowableArray<RollbackEntry> rollback_;
+};
+
+} // namespace dart
+
+#endif // VM_FLOW_GRAPH_TYPE_PROPAGATOR_H_
diff --git a/runtime/vm/il_printer.cc b/runtime/vm/il_printer.cc
index bd501ac..02db6e23 100644
--- a/runtime/vm/il_printer.cc
+++ b/runtime/vm/il_printer.cc
@@ -88,17 +88,12 @@
const AbstractType& dst_type,
const String& dst_name,
bool eliminated) {
- const Script& script = Script::Handle(parsed_function.function().script());
const char* compile_type_name = "unknown";
if (value != NULL) {
- const AbstractType& type = AbstractType::Handle(value->CompileType());
- if (!type.IsNull()) {
- compile_type_name = String::Handle(type.Name()).ToCString();
- }
+ compile_type_name = value->Type()->ToCString();
}
- Parser::PrintMessage(script, token_pos, "",
- "%s type check: compile type '%s' is %s specific than "
- "type '%s' of '%s'.",
+ OS::Print("%s type check: compile type %s is %s specific than "
+ "type '%s' of '%s'.\n",
eliminated ? "Eliminated" : "Generated",
compile_type_name,
eliminated ? "more" : "not more",
@@ -107,6 +102,31 @@
}
+void CompileType::PrintTo(BufferFormatter* f) const {
+ f->Print("T{");
+ f->Print("%s, ", is_nullable_ ? "null" : "not-null");
+ if (cid_ != kIllegalCid) {
+ const Class& cls =
+ Class::Handle(Isolate::Current()->class_table()->At(cid_));
+ f->Print("%s, ", String::Handle(cls.Name()).ToCString());
+ } else {
+ f->Print("?, ");
+ }
+ f->Print("%s}", (type_ != NULL) ? String::Handle(type_->Name()).ToCString()
+ : "?");
+}
+
+
+const char* CompileType::ToCString() const {
+ char buffer[1024];
+ BufferFormatter f(buffer, sizeof(buffer));
+ PrintTo(&f);
+ return Isolate::Current()->current_zone()->MakeCopyOfString(buffer);
+}
+
+
+
+
static void PrintICData(BufferFormatter* f, const ICData& ic_data) {
f->Print(" IC[%"Pd": ", ic_data.NumberOfChecks());
Function& target = Function::Handle();
@@ -134,20 +154,6 @@
}
-static void PrintPropagatedType(BufferFormatter* f, const Definition& def) {
- if (def.HasPropagatedType()) {
- String& name = String::Handle();
- name = AbstractType::Handle(def.PropagatedType()).Name();
- f->Print(" {PT: %s}", name.ToCString());
- }
- if (def.has_propagated_cid()) {
- const Class& cls = Class::Handle(
- Isolate::Current()->class_table()->At(def.propagated_cid()));
- f->Print(" {PCid: %s}", String::Handle(cls.Name()).ToCString());
- }
-}
-
-
static void PrintUse(BufferFormatter* f, const Definition& definition) {
if (definition.is_used()) {
if (definition.HasSSATemp()) {
@@ -182,11 +188,15 @@
f->Print("%s:%"Pd"(", DebugName(), GetDeoptId());
PrintOperandsTo(f);
f->Print(")");
- PrintPropagatedType(f, *this);
if (range_ != NULL) {
f->Print(" ");
range_->PrintTo(f);
}
+
+ if (type_ != NULL) {
+ f->Print(" ");
+ type_->PrintTo(f);
+ }
}
@@ -200,6 +210,11 @@
void Value::PrintTo(BufferFormatter* f) const {
PrintUse(f, *definition());
+ if ((reaching_type_ != NULL) &&
+ (reaching_type_ != definition()->Type())) {
+ f->Print(" ");
+ reaching_type_->PrintTo(f);
+ }
}
@@ -276,10 +291,9 @@
void AssertAssignableInstr::PrintOperandsTo(BufferFormatter* f) const {
value()->PrintTo(f);
- f->Print(", %s, '%s'%s",
- String::Handle(dst_type().Name()).ToCString(),
- dst_name().ToCString(),
- is_eliminated() ? " eliminated" : "");
+ f->Print(", %s, '%s'",
+ dst_type().ToCString(),
+ dst_name().ToCString());
f->Print(" instantiator(");
instantiator()->PrintTo(f);
f->Print(")");
@@ -291,7 +305,6 @@
void AssertBooleanInstr::PrintOperandsTo(BufferFormatter* f) const {
value()->PrintTo(f);
- f->Print("%s", is_eliminated() ? " eliminated" : "");
}
@@ -607,7 +620,6 @@
if (i < inputs_.length() - 1) f->Print(", ");
}
f->Print(")");
- PrintPropagatedType(f, *this);
if (is_alive()) {
f->Print(" alive");
} else {
@@ -617,6 +629,10 @@
f->Print(" ");
range_->PrintTo(f);
}
+ if (type_ != NULL) {
+ f->Print(" ");
+ type_->PrintTo(f);
+ }
}
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index 48edba3..9e92536 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -25,15 +25,15 @@
DEFINE_FLAG(bool, propagate_ic_data, true,
"Propagate IC data from unoptimized to optimized IC calls.");
DECLARE_FLAG(bool, enable_type_checks);
+DECLARE_FLAG(bool, eliminate_type_checks);
DECLARE_FLAG(int, max_polymorphic_checks);
DECLARE_FLAG(bool, trace_optimization);
Definition::Definition()
: range_(NULL),
+ type_(NULL),
temp_index_(-1),
ssa_temp_index_(-1),
- propagated_type_(AbstractType::Handle()),
- propagated_cid_(kIllegalCid),
input_use_list_(NULL),
env_use_list_(NULL),
use_kind_(kValue), // Phis and parameters rely on this default.
@@ -146,10 +146,7 @@
LoadFieldInstr* other_load = other->AsLoadField();
ASSERT(other_load != NULL);
ASSERT((offset_in_bytes() != other_load->offset_in_bytes()) ||
- ((immutable_ == other_load->immutable_) &&
- ((ResultCid() == other_load->ResultCid()) ||
- (ResultCid() == kDynamicCid) ||
- (other_load->ResultCid() == kDynamicCid))));
+ ((immutable_ == other_load->immutable_)));
return offset_in_bytes() == other_load->offset_in_bytes();
}
@@ -407,178 +404,17 @@
}
-// TODO(regis): Support a set of compile types for the given value.
-bool Value::CanComputeIsNull(bool* is_null) const {
- ASSERT(is_null != NULL);
- // For now, we can only return a meaningful result if the value is constant.
- if (!BindsToConstant()) {
+bool Value::NeedsStoreBuffer() {
+ if (Type()->IsNull() ||
+ (Type()->ToNullableCid() == kSmiCid) ||
+ (Type()->ToNullableCid() == kBoolCid)) {
return false;
}
- // Return true if the constant value is Object::null.
- if (BindsToConstantNull()) {
- *is_null = true;
- return true;
- }
-
- // Consider the compile type of the value to check for sentinels, which are
- // also treated as null.
- const AbstractType& compile_type = AbstractType::Handle(CompileType());
- ASSERT(!compile_type.IsMalformed());
- ASSERT(!compile_type.IsVoidType());
-
- // There are only three instances that can be of type Null:
- // Object::null(), Object::sentinel(), and Object::transition_sentinel().
- // The inline code and run time code performing the type check will only
- // encounter the 2 sentinel values if type check elimination was disabled.
- // Otherwise, the type check of a sentinel value will be eliminated here,
- // because these sentinel values can only be encountered as constants, never
- // as actual value of a heap object being type checked.
- if (compile_type.IsNullType()) {
- *is_null = true;
- return true;
- }
-
- return false;
-}
-
-
-// TODO(regis): Support a set of compile types for the given value.
-bool Value::CanComputeIsInstanceOf(const AbstractType& type,
- bool* is_instance) const {
- ASSERT(is_instance != NULL);
- // We cannot give an answer if the given type is malformed.
- if (type.IsMalformed()) {
- return false;
- }
-
- // We should never test for an instance of null.
- ASSERT(!type.IsNullType());
-
- // Consider the compile type of the value.
- const AbstractType& compile_type = AbstractType::Handle(CompileType());
- if (compile_type.IsMalformed()) {
- return false;
- }
-
- // If the compile type of the value is void, we are type checking the result
- // of a void function, which was checked to be null at the return statement
- // inside the function.
- if (compile_type.IsVoidType()) {
- ASSERT(FLAG_enable_type_checks);
- *is_instance = true;
- return true;
- }
-
- // The Null type is only a subtype of Object and of dynamic.
- // Functions that do not explicitly return a value, implicitly return null,
- // except generative constructors, which return the object being constructed.
- // It is therefore acceptable for void functions to return null.
- if (compile_type.IsNullType()) {
- *is_instance =
- type.IsObjectType() || type.IsDynamicType() || type.IsVoidType();
- return true;
- }
-
- // Until we support a set of compile types, we can only give answers for
- // constant values. Indeed, a variable of the proper compile time type may
- // still hold null at run time and therefore fail the test.
- if (!BindsToConstant()) {
- return false;
- }
-
- // A non-null constant is not an instance of void.
- if (type.IsVoidType()) {
- *is_instance = false;
- return true;
- }
-
- // Since the value is a constant, its type is instantiated.
- ASSERT(compile_type.IsInstantiated());
-
- // The run time type of the value is guaranteed to be a subtype of the
- // compile time type of the value. However, establishing here that the
- // compile time type is a subtype of the given type does not guarantee that
- // the run time type will also be a subtype of the given type, because the
- // subtype relation is not transitive when an uninstantiated type is
- // involved.
- Error& malformed_error = Error::Handle();
- if (type.IsInstantiated()) {
- // Perform the test on the compile-time type and provide the answer, unless
- // the type test produced a malformed error (e.g. an upper bound error).
- *is_instance = compile_type.IsSubtypeOf(type, &malformed_error);
- } else {
- // However, the 'more specific than' relation is transitive and used here.
- // In other words, if the compile type of the value is more specific than
- // the given type, the run time type of the value, which is guaranteed to be
- // a subtype of the compile type, is also guaranteed to be a subtype of the
- // given type.
- *is_instance = compile_type.IsMoreSpecificThan(type, &malformed_error);
- }
- return malformed_error.IsNull();
-}
-
-
-bool Value::NeedsStoreBuffer() const {
- const intptr_t cid = ResultCid();
- if ((cid == kSmiCid) || (cid == kBoolCid) || (cid == kNullCid)) {
- return false;
- }
return !BindsToConstant();
}
-RawAbstractType* PhiInstr::CompileType() const {
- ASSERT(!HasPropagatedType());
- // Since type propagation has not yet occured, we are reaching this phi via a
- // back edge phi input. Return null as compile type so that this input is
- // ignored in the first iteration of type propagation.
- return AbstractType::null();
-}
-
-
-RawAbstractType* PhiInstr::LeastSpecificInputType() const {
- AbstractType& least_specific_type = AbstractType::Handle();
- AbstractType& input_type = AbstractType::Handle();
- for (intptr_t i = 0; i < InputCount(); i++) {
- input_type = InputAt(i)->CompileType();
- if (input_type.IsNull()) {
- // This input is on a back edge and we are in the first iteration of type
- // propagation. Ignore it.
- continue;
- }
- ASSERT(!input_type.IsNull());
- if (least_specific_type.IsNull() ||
- least_specific_type.IsMoreSpecificThan(input_type, NULL)) {
- // Type input_type is less specific than the current least_specific_type.
- least_specific_type = input_type.raw();
- } else if (input_type.IsMoreSpecificThan(least_specific_type, NULL)) {
- // Type least_specific_type is less specific than input_type. No change.
- } else {
- // The types are unrelated. No need to continue.
- least_specific_type = Type::ObjectType();
- break;
- }
- }
- return least_specific_type.raw();
-}
-
-
-RawAbstractType* ParameterInstr::CompileType() const {
- ASSERT(!HasPropagatedType());
- // Note that returning the declared type of the formal parameter would be
- // incorrect, because ParameterInstr is used as input to the type check
- // verifying the run time type of the passed-in parameter and this check would
- // always be wrongly eliminated.
- return Type::DynamicType();
-}
-
-
-RawAbstractType* PushArgumentInstr::CompileType() const {
- return AbstractType::null();
-}
-
-
void JoinEntryInstr::AddPredecessor(BlockEntryInstr* predecessor) {
// Require the predecessors to be sorted by block_id to make managing
// their corresponding phi inputs simpler.
@@ -727,45 +563,6 @@
}
-bool Definition::SetPropagatedCid(intptr_t cid) {
- if (cid == kIllegalCid) {
- return false;
- }
- if (propagated_cid_ == kIllegalCid) {
- // First setting, nothing has changed.
- propagated_cid_ = cid;
- return false;
- }
- bool has_changed = (propagated_cid_ != cid);
- propagated_cid_ = cid;
- return has_changed;
-}
-
-
-intptr_t Definition::GetPropagatedCid() {
- if (has_propagated_cid()) return propagated_cid();
- intptr_t cid = ResultCid();
- ASSERT(cid != kIllegalCid);
- SetPropagatedCid(cid);
- return cid;
-}
-
-
-intptr_t PhiInstr::GetPropagatedCid() {
- return propagated_cid();
-}
-
-
-intptr_t ParameterInstr::GetPropagatedCid() {
- return propagated_cid();
-}
-
-
-intptr_t AssertAssignableInstr::GetPropagatedCid() {
- return propagated_cid();
-}
-
-
// ==== Postorder graph traversal.
static bool IsMarked(BlockEntryInstr* block,
GrowableArray<BlockEntryInstr*>* preorder) {
@@ -1027,154 +824,6 @@
}
-RawAbstractType* Value::CompileType() const {
- if (definition()->HasPropagatedType()) {
- return definition()->PropagatedType();
- }
- // The compile type may be requested when building the flow graph, i.e. before
- // type propagation has occurred. To avoid repeatedly computing the compile
- // type of the definition, we store it as initial propagated type.
- AbstractType& type = AbstractType::Handle(definition()->CompileType());
- definition()->SetPropagatedType(type);
- return type.raw();
-}
-
-
-intptr_t Value::ResultCid() const {
- if (reaching_cid() == kIllegalCid) {
- return definition()->GetPropagatedCid();
- }
- return reaching_cid();
-}
-
-
-
-RawAbstractType* ConstantInstr::CompileType() const {
- if (value().IsNull()) {
- return Type::NullType();
- }
- if (value().IsInstance()) {
- return Instance::Cast(value()).GetType();
- } else {
- ASSERT(value().IsAbstractTypeArguments());
- return AbstractType::null();
- }
-}
-
-
-intptr_t ConstantInstr::ResultCid() const {
- if (value().IsNull()) {
- return kNullCid;
- }
- if (value().IsInstance()) {
- return Class::Handle(value().clazz()).id();
- } else {
- ASSERT(value().IsAbstractTypeArguments());
- return kDynamicCid;
- }
-}
-
-
-RawAbstractType* AssertAssignableInstr::CompileType() const {
- const AbstractType& value_compile_type =
- AbstractType::Handle(value()->CompileType());
- if (!value_compile_type.IsNull() &&
- value_compile_type.IsMoreSpecificThan(dst_type(), NULL)) {
- return value_compile_type.raw();
- }
- return dst_type().raw();
-}
-
-
-RawAbstractType* AssertBooleanInstr::CompileType() const {
- return Type::BoolType();
-}
-
-
-RawAbstractType* ArgumentDefinitionTestInstr::CompileType() const {
- return Type::BoolType();
-}
-
-
-RawAbstractType* CurrentContextInstr::CompileType() const {
- return AbstractType::null();
-}
-
-
-RawAbstractType* StoreContextInstr::CompileType() const {
- return AbstractType::null();
-}
-
-
-RawAbstractType* ClosureCallInstr::CompileType() const {
- // Because of function subtyping rules, the declared return type of a closure
- // call cannot be relied upon for compile type analysis. For example, a
- // function returning dynamic can be assigned to a closure variable declared
- // to return int and may actually return a double at run-time.
- return Type::DynamicType();
-}
-
-
-RawAbstractType* InstanceCallInstr::CompileType() const {
- // TODO(regis): Return a more specific type than dynamic for recognized
- // combinations of receiver type and method name.
- return Type::DynamicType();
-}
-
-
-RawAbstractType* PolymorphicInstanceCallInstr::CompileType() const {
- return Type::DynamicType();
-}
-
-
-RawAbstractType* StaticCallInstr::CompileType() const {
- if (FLAG_enable_type_checks) {
- return function().result_type();
- }
- return Type::DynamicType();
-}
-
-
-RawAbstractType* LoadLocalInstr::CompileType() const {
- if (FLAG_enable_type_checks) {
- return local().type().raw();
- }
- return Type::DynamicType();
-}
-
-
-RawAbstractType* StoreLocalInstr::CompileType() const {
- return value()->CompileType();
-}
-
-
-RawAbstractType* StrictCompareInstr::CompileType() const {
- return Type::BoolType();
-}
-
-
-// Only known == targets return a Boolean.
-RawAbstractType* EqualityCompareInstr::CompileType() const {
- if ((receiver_class_id() == kSmiCid) ||
- (receiver_class_id() == kDoubleCid) ||
- (receiver_class_id() == kNumberCid)) {
- return Type::BoolType();
- }
- return Type::DynamicType();
-}
-
-
-intptr_t EqualityCompareInstr::ResultCid() const {
- if ((receiver_class_id() == kSmiCid) ||
- (receiver_class_id() == kDoubleCid) ||
- (receiver_class_id() == kNumberCid)) {
- // Known/library equalities that are guaranteed to return Boolean.
- return kBoolCid;
- }
- return kDynamicCid;
-}
-
-
bool EqualityCompareInstr::IsPolymorphic() const {
return HasICData() &&
(ic_data()->NumberOfChecks() > 0) &&
@@ -1182,194 +831,6 @@
}
-RawAbstractType* RelationalOpInstr::CompileType() const {
- if ((operands_class_id() == kSmiCid) ||
- (operands_class_id() == kDoubleCid) ||
- (operands_class_id() == kNumberCid)) {
- // Known/library relational ops that are guaranteed to return Boolean.
- return Type::BoolType();
- }
- return Type::DynamicType();
-}
-
-
-intptr_t RelationalOpInstr::ResultCid() const {
- if ((operands_class_id() == kSmiCid) ||
- (operands_class_id() == kDoubleCid) ||
- (operands_class_id() == kNumberCid)) {
- // Known/library relational ops that are guaranteed to return Boolean.
- return kBoolCid;
- }
- return kDynamicCid;
-}
-
-
-RawAbstractType* NativeCallInstr::CompileType() const {
- // The result type of the native function is identical to the result type of
- // the enclosing native Dart function. However, we prefer to check the type
- // of the value returned from the native call.
- return Type::DynamicType();
-}
-
-
-RawAbstractType* StringFromCharCodeInstr::CompileType() const {
- return Type::StringType();
-}
-
-
-RawAbstractType* LoadIndexedInstr::CompileType() const {
- switch (class_id_) {
- case kArrayCid:
- case kImmutableArrayCid:
- return Type::DynamicType();
- case kFloat32ArrayCid :
- case kFloat64ArrayCid :
- return Type::Double();
- case kInt8ArrayCid:
- case kUint8ArrayCid:
- case kUint8ClampedArrayCid:
- case kExternalUint8ArrayCid:
- case kExternalUint8ClampedArrayCid:
- case kInt16ArrayCid:
- case kUint16ArrayCid:
- case kInt32ArrayCid:
- case kUint32ArrayCid:
- case kOneByteStringCid:
- case kTwoByteStringCid:
- return Type::IntType();
- default:
- UNIMPLEMENTED();
- return Type::IntType();
- }
-}
-
-
-RawAbstractType* StoreIndexedInstr::CompileType() const {
- return AbstractType::null();
-}
-
-
-RawAbstractType* StoreInstanceFieldInstr::CompileType() const {
- return value()->CompileType();
-}
-
-
-RawAbstractType* LoadStaticFieldInstr::CompileType() const {
- if (FLAG_enable_type_checks) {
- return field().type();
- }
- return Type::DynamicType();
-}
-
-
-RawAbstractType* StoreStaticFieldInstr::CompileType() const {
- return value()->CompileType();
-}
-
-
-RawAbstractType* BooleanNegateInstr::CompileType() const {
- return Type::BoolType();
-}
-
-
-RawAbstractType* InstanceOfInstr::CompileType() const {
- return Type::BoolType();
-}
-
-
-RawAbstractType* CreateArrayInstr::CompileType() const {
- return type().raw();
-}
-
-
-RawAbstractType* CreateClosureInstr::CompileType() const {
- const Function& fun = function();
- const Class& signature_class = Class::Handle(fun.signature_class());
- return signature_class.SignatureType();
-}
-
-
-RawAbstractType* AllocateObjectInstr::CompileType() const {
- // TODO(regis): Be more specific.
- return Type::DynamicType();
-}
-
-
-RawAbstractType* AllocateObjectWithBoundsCheckInstr::CompileType() const {
- // TODO(regis): Be more specific.
- return Type::DynamicType();
-}
-
-
-RawAbstractType* LoadFieldInstr::CompileType() const {
- // Type may be null if the field is a VM field, e.g. context parent.
- // Keep it as null for debug purposes and do not return dynamic in production
- // mode, since misuse of the type would remain undetected.
- if (type().IsNull()) {
- return AbstractType::null();
- }
- if (FLAG_enable_type_checks) {
- return type().raw();
- }
- return Type::DynamicType();
-}
-
-
-RawAbstractType* StoreVMFieldInstr::CompileType() const {
- return value()->CompileType();
-}
-
-
-RawAbstractType* InstantiateTypeArgumentsInstr::CompileType() const {
- return AbstractType::null();
-}
-
-
-RawAbstractType* ExtractConstructorTypeArgumentsInstr::CompileType() const {
- return AbstractType::null();
-}
-
-
-RawAbstractType* ExtractConstructorInstantiatorInstr::CompileType() const {
- return AbstractType::null();
-}
-
-
-RawAbstractType* AllocateContextInstr::CompileType() const {
- return AbstractType::null();
-}
-
-
-RawAbstractType* ChainContextInstr::CompileType() const {
- return AbstractType::null();
-}
-
-
-RawAbstractType* CloneContextInstr::CompileType() const {
- return AbstractType::null();
-}
-
-
-RawAbstractType* CatchEntryInstr::CompileType() const {
- return AbstractType::null();
-}
-
-
-RawAbstractType* CheckStackOverflowInstr::CompileType() const {
- return AbstractType::null();
-}
-
-
-RawAbstractType* BinarySmiOpInstr::CompileType() const {
- return Type::SmiType();
-}
-
-
-intptr_t BinarySmiOpInstr::ResultCid() const {
- return kSmiCid;
-}
-
-
bool BinarySmiOpInstr::CanDeoptimize() const {
switch (op_kind()) {
case Token::kBIT_AND:
@@ -1398,47 +859,6 @@
}
-RawAbstractType* BinaryMintOpInstr::CompileType() const {
- return Type::IntType();
-}
-
-
-intptr_t BinaryMintOpInstr::ResultCid() const {
- return kDynamicCid;
-}
-
-
-RawAbstractType* ShiftMintOpInstr::CompileType() const {
- return Type::IntType();
-}
-
-
-intptr_t ShiftMintOpInstr::ResultCid() const {
- return kDynamicCid;
-}
-
-
-RawAbstractType* UnaryMintOpInstr::CompileType() const {
- return Type::IntType();
-}
-
-
-intptr_t UnaryMintOpInstr::ResultCid() const {
- return kDynamicCid;
-}
-
-
-RawAbstractType* BinaryDoubleOpInstr::CompileType() const {
- return Type::Double();
-}
-
-
-intptr_t BinaryDoubleOpInstr::ResultCid() const {
- // The output is not an instance but when it is boxed it becomes double.
- return kDoubleCid;
-}
-
-
static bool ToIntegerConstant(Value* value, intptr_t* result) {
if (!value->BindsToConstant()) {
if (value->definition()->IsUnboxDouble()) {
@@ -1599,96 +1019,6 @@
}
-RawAbstractType* MathSqrtInstr::CompileType() const {
- return Type::Double();
-}
-
-
-RawAbstractType* UnboxDoubleInstr::CompileType() const {
- return Type::null();
-}
-
-
-intptr_t BoxDoubleInstr::ResultCid() const {
- return kDoubleCid;
-}
-
-
-RawAbstractType* BoxDoubleInstr::CompileType() const {
- return Type::Double();
-}
-
-
-intptr_t BoxIntegerInstr::ResultCid() const {
- return kDynamicCid;
-}
-
-
-RawAbstractType* BoxIntegerInstr::CompileType() const {
- return Type::IntType();
-}
-
-
-intptr_t UnboxIntegerInstr::ResultCid() const {
- return kDynamicCid;
-}
-
-
-RawAbstractType* UnboxIntegerInstr::CompileType() const {
- return Type::null();
-}
-
-
-RawAbstractType* UnarySmiOpInstr::CompileType() const {
- return Type::SmiType();
-}
-
-
-RawAbstractType* SmiToDoubleInstr::CompileType() const {
- return Type::Double();
-}
-
-
-RawAbstractType* DoubleToIntegerInstr::CompileType() const {
- return Type::IntType();
-}
-
-
-RawAbstractType* DoubleToSmiInstr::CompileType() const {
- return Type::SmiType();
-}
-
-
-RawAbstractType* DoubleToDoubleInstr::CompileType() const {
- return Type::Double();
-}
-
-
-RawAbstractType* InvokeMathCFunctionInstr::CompileType() const {
- return Type::Double();
-}
-
-
-RawAbstractType* CheckClassInstr::CompileType() const {
- return AbstractType::null();
-}
-
-
-RawAbstractType* CheckSmiInstr::CompileType() const {
- return AbstractType::null();
-}
-
-
-RawAbstractType* CheckArrayBoundInstr::CompileType() const {
- return AbstractType::null();
-}
-
-
-RawAbstractType* CheckEitherNonSmiInstr::CompileType() const {
- return AbstractType::null();
-}
-
-
// Optimizations that eliminate or simplify individual instructions.
Instruction* Instruction::Canonicalize(FlowGraphOptimizer* optimizer) {
return this;
@@ -1752,7 +1082,7 @@
StaticCallInstr* call = value()->definition()->AsStaticCall();
if (call != NULL &&
call->is_known_constructor() &&
- call->ResultCid() == kArrayCid) {
+ (call->Type()->ToCid() == kArrayCid)) {
return call->ArgumentAt(1)->value()->definition();
}
return this;
@@ -1760,33 +1090,18 @@
Definition* AssertBooleanInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
- const intptr_t value_cid = value()->ResultCid();
- return (value_cid == kBoolCid) ? value()->definition() : this;
+ if (FLAG_eliminate_type_checks && (value()->Type()->ToCid() == kBoolCid)) {
+ return value()->definition();
+ }
+
+ return this;
}
Definition* AssertAssignableInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
- // (1) Replace the assert with its input if the input has a known compatible
- // class-id. The class-ids handled here are those that are known to be
- // results of IL instructions.
- intptr_t cid = value()->ResultCid();
- bool is_redundant = false;
- if (dst_type().IsIntType()) {
- is_redundant = (cid == kSmiCid) || (cid == kMintCid);
- } else if (dst_type().IsDoubleType()) {
- is_redundant = (cid == kDoubleCid);
- } else if (dst_type().IsBoolType()) {
- is_redundant = (cid == kBoolCid);
- }
- if (is_redundant) return value()->definition();
-
- // (2) Replace the assert with its input if the input is the result of a
- // compatible assert itself.
- AssertAssignableInstr* check = value()->definition()->AsAssertAssignable();
- if ((check != NULL) && check->dst_type().Equals(dst_type())) {
- // TODO(fschneider): Propagate type-assertions across phi-nodes.
- // TODO(fschneider): Eliminate more asserts with subtype relation.
- return check;
+ if (FLAG_eliminate_type_checks &&
+ value()->Type()->IsAssignableTo(dst_type())) {
+ return value()->definition();
}
// (3) For uninstantiated target types: If the instantiator type arguments
@@ -1868,7 +1183,7 @@
// Handles e === true.
if ((kind() == Token::kEQ_STRICT) &&
(right_constant.raw() == Bool::True().raw()) &&
- (left()->ResultCid() == kBoolCid)) {
+ (left()->Type()->ToCid() == kBoolCid)) {
// Return left subexpression as the replacement for this instruction.
return left_defn;
}
@@ -1877,7 +1192,10 @@
Instruction* CheckClassInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
- const intptr_t value_cid = value()->ResultCid();
+ // TODO(vegorov): Replace class checks with null checks when ToNullableCid
+ // matches.
+
+ const intptr_t value_cid = value()->Type()->ToCid();
if (value_cid == kDynamicCid) {
return this;
}
@@ -1896,14 +1214,14 @@
Instruction* CheckSmiInstr::Canonicalize(FlowGraphOptimizer* optimizer) {
- return (value()->ResultCid() == kSmiCid) ? NULL : this;
+ return (value()->Type()->ToCid() == kSmiCid) ? NULL : this;
}
Instruction* CheckEitherNonSmiInstr::Canonicalize(
FlowGraphOptimizer* optimizer) {
- if ((left()->ResultCid() == kDoubleCid) ||
- (right()->ResultCid() == kDoubleCid)) {
+ if ((left()->Type()->ToCid() == kDoubleCid) ||
+ (right()->Type()->ToCid() == kDoubleCid)) {
return NULL; // Remove from the graph.
}
return this;
@@ -2122,13 +1440,11 @@
void AssertAssignableInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- if (!is_eliminated()) {
- compiler->GenerateAssertAssignable(token_pos(),
- deopt_id(),
- dst_type(),
- dst_name(),
- locs());
- }
+ compiler->GenerateAssertAssignable(token_pos(),
+ deopt_id(),
+ dst_type(),
+ dst_name(),
+ locs());
ASSERT(locs()->in(0).reg() == locs()->out().reg());
}
@@ -2400,7 +1716,7 @@
void Definition::InferRange() {
- ASSERT(GetPropagatedCid() == kSmiCid); // Has meaning only for smis.
+ ASSERT(Type()->ToCid() == kSmiCid); // Has meaning only for smis.
if (range_ == NULL) {
range_ = Range::Unknown();
}
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index 1d70a29..7e875e1 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -77,6 +77,121 @@
};
+// CompileType describes type of the value produced by the definition.
+//
+// It captures the following properties:
+// - whether value can potentially be null or it is definitely not null;
+// - concrete class id of the value or kDynamicCid if unknown statically;
+// - abstract super type of the value, concrete type of the value in runtime
+// is guaranteed to be sub type of this type.
+//
+// Values of CompileType form a lattice with a None type as a bottom and a
+// nullable Dynamic type as a top element. Method Union provides a join
+// operation for the lattice.
+class CompileType : public ZoneAllocated {
+ public:
+ static const bool kNullable = true;
+ static const bool kNonNullable = false;
+
+ // Return type such that concrete value's type in runtime is guaranteed to
+ // be subtype of it.
+ const AbstractType* ToAbstractType();
+
+ // Return class id such that it is either kDynamicCid or in runtime
+ // value is guaranteed to have an equal class id.
+ intptr_t ToCid();
+
+ // Return class id such that it is either kDynamicCid or in runtime
+ // value is guaranteed to be either null or have an equal class id.
+ intptr_t ToNullableCid();
+
+ // Returns true if the value is guaranteed to be not-null or is known to be
+ // always null.
+ bool HasDecidableNullability();
+
+ // Returns true if the value is known to be always null.
+ bool IsNull();
+
+ // Returns true if this type is more specific than given type.
+ bool IsMoreSpecificThan(const AbstractType& other);
+
+ // Returns true if value of this type is assignable to a location of the
+ // given type.
+ bool IsAssignableTo(const AbstractType& type) {
+ bool is_instance;
+ return CanComputeIsInstanceOf(type, kNullable, &is_instance) &&
+ is_instance;
+ }
+
+ // Create a new CompileType representing given combination of class id and
+ // abstract type. The pair is assumed to be coherent.
+ static CompileType* New(intptr_t cid, const AbstractType& type);
+
+ // Create a new CompileType representing given abstract type. By default
+ // values as assumed to be nullable.
+ static CompileType* FromAbstractType(const AbstractType& type,
+ bool is_nullable = kNullable);
+
+ // Create a new CompileType representing an value with the given class id.
+ // Resulting CompileType is nullable only if cid is kDynamicCid or kNullCid.
+ static CompileType* FromCid(intptr_t cid);
+
+ // Create None CompileType. It is the bottom of the lattice and is used to
+ // represent type of the phi that was not yet inferred.
+ static CompileType* None() {
+ return new CompileType(true, kIllegalCid, NULL);
+ }
+
+ // Create Dynamic CompileType. It is the top of the lattice and is used to
+ // represent unknown type.
+ static CompileType* Dynamic();
+
+ static CompileType* Null();
+
+ // Create non-nullable Bool type.
+ static CompileType* Bool();
+
+ // Create non-nullable Int type.
+ static CompileType* Int();
+
+ // Perform a join operation over the type lattice.
+ void Union(CompileType* other);
+
+ // Returns true if this and other types are the same.
+ bool IsEqualTo(CompileType* other) {
+ return (is_nullable_ == other->is_nullable_) &&
+ (ToNullableCid() == other->ToNullableCid()) &&
+ (ToAbstractType()->Equals(*other->ToAbstractType()));
+ }
+
+ // Replaces this type with other.
+ void ReplaceWith(CompileType* other) {
+ is_nullable_ = other->is_nullable_;
+ cid_ = other->cid_;
+ type_ = other->type_;
+ }
+
+ bool IsNone() const {
+ return (cid_ == kIllegalCid) && (type_ == NULL);
+ }
+
+ void PrintTo(BufferFormatter* f) const;
+ const char* ToCString() const;
+
+ private:
+ CompileType(bool is_nullable, intptr_t cid, const AbstractType* type)
+ : is_nullable_(is_nullable), cid_(cid), type_(type) { }
+
+ bool CanComputeIsInstanceOf(const AbstractType& type,
+ bool is_nullable,
+ bool* is_instance);
+
+ bool is_nullable_;
+ intptr_t cid_;
+ const AbstractType* type_;
+};
+
+
class Value : public ZoneAllocated {
public:
// A forward iterator that allows removing the current value from the
@@ -102,7 +217,7 @@
next_use_(NULL),
instruction_(NULL),
use_index_(-1),
- reaching_cid_(kIllegalCid) { }
+ reaching_type_(NULL) { }
Definition* definition() const { return definition_; }
void set_definition(Definition* definition) { definition_ = definition; }
@@ -124,8 +239,11 @@
Value* Copy() { return new Value(definition_); }
- RawAbstractType* CompileType() const;
- intptr_t ResultCid() const;
+ CompileType* Type();
+
+ void SetReachingType(CompileType* type) {
+ reaching_type_ = type;
+ }
void PrintTo(BufferFormatter* f) const;
@@ -140,24 +258,12 @@
// Assert if BindsToConstant() is false, otherwise returns the constant value.
const Object& BoundConstant() const;
- // Compute a run-time null test at compile-time and set result in is_null.
- // Return false if the computation is not possible at compile time.
- bool CanComputeIsNull(bool* is_null) const;
-
- // Compute a run-time type test at compile-time and set result in is_instance.
- // Return false if the computation is not possible at compile time.
- bool CanComputeIsInstanceOf(const AbstractType& type,
- bool* is_instance) const;
-
// Compile time constants, Bool, Smi and Nulls do not need to update
// the store buffer.
- bool NeedsStoreBuffer() const;
+ bool NeedsStoreBuffer();
bool Equals(Value* other) const;
- void set_reaching_cid(intptr_t cid) { reaching_cid_ = cid; }
- intptr_t reaching_cid() const { return reaching_cid_; }
-
private:
Definition* definition_;
Value* previous_use_;
@@ -165,7 +271,7 @@
Instruction* instruction_;
intptr_t use_index_;
- intptr_t reaching_cid_;
+ CompileType* reaching_type_;
DISALLOW_COPY_AND_ASSIGN(Value);
};
@@ -1094,37 +1200,24 @@
// Compile time type of the definition, which may be requested before type
// propagation during graph building.
- virtual RawAbstractType* CompileType() const = 0;
-
- virtual intptr_t ResultCid() const = 0;
-
- bool HasPropagatedType() const {
- return !propagated_type_.IsNull();
- }
- RawAbstractType* PropagatedType() const {
- ASSERT(HasPropagatedType());
- return propagated_type_.raw();
- }
- // Returns true if the propagated type has changed.
- bool SetPropagatedType(const AbstractType& propagated_type) {
- if (propagated_type.IsNull()) {
- // Not a typed definition, e.g. access to a VM field.
- return false;
+ CompileType* Type() {
+ if (type_ == NULL) {
+ type_ = ComputeInitialType();
}
- const bool changed =
- propagated_type_.IsNull() || !propagated_type.Equals(propagated_type_);
- propagated_type_ = propagated_type.raw();
- return changed;
+ return type_;
}
- bool has_propagated_cid() const { return propagated_cid_ != kIllegalCid; }
- intptr_t propagated_cid() const { return propagated_cid_; }
+ // Compute initial compile type for this definition. It is safe to use this
+ // approximation even before type propagator was run (e.g. during graph
+ // building).
+ virtual CompileType* ComputeInitialType() const {
+ return CompileType::Dynamic();
+ }
- // May compute and set propagated cid.
- virtual intptr_t GetPropagatedCid();
-
- // Returns true if the propagated cid has changed.
- bool SetPropagatedCid(intptr_t cid);
+ // Update CompileType of the definition. Returns true if the type has changed.
+ virtual bool RecomputeType() {
+ return false;
+ }
bool HasUses() const {
return (input_use_list_ != NULL) || (env_use_list_ != NULL);
@@ -1193,14 +1286,11 @@
friend class RangeAnalysis;
Range* range_;
+ CompileType* type_;
private:
intptr_t temp_index_;
intptr_t ssa_temp_index_;
- // TODO(regis): GrowableArray<const AbstractType*> propagated_types_;
- // For now:
- AbstractType& propagated_type_;
- intptr_t propagated_cid_;
Value* input_use_list_;
Value* env_use_list_;
UseKind use_kind_;
@@ -1228,8 +1318,8 @@
virtual BlockEntryInstr* GetBlock() const { return block(); }
JoinEntryInstr* block() const { return block_; }
- virtual RawAbstractType* CompileType() const;
- virtual intptr_t GetPropagatedCid();
+ virtual CompileType* ComputeInitialType() const;
+ virtual bool RecomputeType();
virtual intptr_t ArgumentCount() const { return 0; }
@@ -1243,9 +1333,6 @@
virtual bool HasSideEffect() const { return false; }
- // TODO(regis): This helper will be removed once we support type sets.
- RawAbstractType* LeastSpecificInputType() const;
-
// Phi is alive if it reaches a non-environment use.
bool is_alive() const { return is_alive_; }
void mark_alive() { is_alive_ = true; }
@@ -1268,11 +1355,6 @@
return 0;
}
- virtual intptr_t ResultCid() const {
- UNREACHABLE();
- return kIllegalCid;
- }
-
DECLARE_INSTRUCTION(Phi)
virtual void PrintTo(BufferFormatter* f) const;
@@ -1313,12 +1395,6 @@
// Get the block entry for that instruction.
virtual BlockEntryInstr* GetBlock() const { return block_; }
- // Compile type of the passed-in parameter.
- virtual RawAbstractType* CompileType() const;
-
- // No known propagated cid for parameters.
- virtual intptr_t GetPropagatedCid();
-
virtual intptr_t ArgumentCount() const { return 0; }
intptr_t InputCount() const { return 0; }
@@ -1337,13 +1413,10 @@
return 0;
}
- virtual intptr_t ResultCid() const {
- UNREACHABLE();
- return kIllegalCid;
- }
-
virtual void PrintOperandsTo(BufferFormatter* f) const;
+ virtual CompileType* ComputeInitialType() const;
+
private:
const intptr_t index_;
GraphEntryInstr* block_;
@@ -1373,12 +1446,7 @@
virtual intptr_t ArgumentCount() const { return 0; }
- virtual RawAbstractType* CompileType() const;
- virtual intptr_t GetPropagatedCid() { return propagated_cid(); }
- virtual intptr_t ResultCid() const {
- UNREACHABLE();
- return kIllegalCid;
- }
+ virtual CompileType* ComputeInitialType() const;
Value* value() const { return value_; }
@@ -1599,7 +1667,6 @@
}
DECLARE_INSTRUCTION(StoreContext);
- virtual RawAbstractType* CompileType() const;
virtual intptr_t ArgumentCount() const { return 0; }
@@ -1818,16 +1885,12 @@
return (inputs_[1] == NULL) ? 1 : 2;
}
- virtual RawAbstractType* CompileType() const {
- return Type::SmiType();
- }
+ virtual CompileType* ComputeInitialType() const;
virtual bool CanDeoptimize() const { return false; }
virtual bool HasSideEffect() const { return false; }
- virtual intptr_t ResultCid() const { return kSmiCid; }
-
virtual bool AttributesEqual(Instruction* other) const {
UNREACHABLE();
return false;
@@ -1869,7 +1932,7 @@
: value_(value) { }
DECLARE_INSTRUCTION(Constant)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
const Object& value() const { return value_; }
@@ -1879,8 +1942,6 @@
virtual bool HasSideEffect() const { return false; }
- virtual intptr_t ResultCid() const;
-
virtual bool AttributesEqual(Instruction* other) const;
virtual bool AffectedBySideEffect() const { return false; }
@@ -1903,8 +1964,7 @@
const String& dst_name)
: token_pos_(token_pos),
dst_type_(AbstractType::ZoneHandle(dst_type.raw())),
- dst_name_(dst_name),
- is_eliminated_(false) {
+ dst_name_(dst_name) {
ASSERT(value != NULL);
ASSERT(instantiator != NULL);
ASSERT(instantiator_type_arguments != NULL);
@@ -1916,7 +1976,8 @@
}
DECLARE_INSTRUCTION(AssertAssignable)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
+ virtual bool RecomputeType();
Value* value() const { return inputs_[0]; }
Value* instantiator() const { return inputs_[1]; }
@@ -1929,14 +1990,6 @@
}
const String& dst_name() const { return dst_name_; }
- bool is_eliminated() const {
- return is_eliminated_;
- }
- void eliminate() {
- ASSERT(!is_eliminated_);
- is_eliminated_ = true;
- }
-
virtual void PrintOperandsTo(BufferFormatter* f) const;
virtual bool CanDeoptimize() const { return true; }
@@ -1946,16 +1999,12 @@
virtual bool AffectedBySideEffect() const { return false; }
virtual bool AttributesEqual(Instruction* other) const;
- virtual intptr_t ResultCid() const { return value()->ResultCid(); }
- virtual intptr_t GetPropagatedCid();
-
virtual Definition* Canonicalize(FlowGraphOptimizer* optimizer);
private:
const intptr_t token_pos_;
AbstractType& dst_type_;
const String& dst_name_;
- bool is_eliminated_;
DISALLOW_COPY_AND_ASSIGN(AssertAssignableInstr);
};
@@ -1964,26 +2013,17 @@
class AssertBooleanInstr : public TemplateDefinition<1> {
public:
AssertBooleanInstr(intptr_t token_pos, Value* value)
- : token_pos_(token_pos),
- is_eliminated_(false) {
+ : token_pos_(token_pos) {
ASSERT(value != NULL);
inputs_[0] = value;
}
DECLARE_INSTRUCTION(AssertBoolean)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
intptr_t token_pos() const { return token_pos_; }
Value* value() const { return inputs_[0]; }
- bool is_eliminated() const {
- return is_eliminated_;
- }
- void eliminate() {
- ASSERT(!is_eliminated_);
- is_eliminated_ = true;
- }
-
virtual void PrintOperandsTo(BufferFormatter* f) const;
virtual bool CanDeoptimize() const { return true; }
@@ -1993,13 +2033,10 @@
virtual bool AffectedBySideEffect() const { return false; }
virtual bool AttributesEqual(Instruction* other) const { return true; }
- virtual intptr_t ResultCid() const { return kBoolCid; }
-
virtual Definition* Canonicalize(FlowGraphOptimizer* optimizer);
private:
const intptr_t token_pos_;
- bool is_eliminated_;
DISALLOW_COPY_AND_ASSIGN(AssertBooleanInstr);
};
@@ -2015,7 +2052,7 @@
}
DECLARE_INSTRUCTION(ArgumentDefinitionTest)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
intptr_t token_pos() const { return ast_node_.token_pos(); }
intptr_t formal_parameter_index() const {
@@ -2024,6 +2061,7 @@
const String& formal_parameter_name() const {
return ast_node_.formal_parameter_name();
}
+
Value* saved_arguments_descriptor() const { return inputs_[0]; }
virtual void PrintOperandsTo(BufferFormatter* f) const;
@@ -2032,8 +2070,6 @@
virtual bool HasSideEffect() const { return true; }
- virtual intptr_t ResultCid() const { return kBoolCid; }
-
private:
const ArgumentDefinitionTestNode& ast_node_;
@@ -2048,14 +2084,12 @@
CurrentContextInstr() { }
DECLARE_INSTRUCTION(CurrentContext)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
virtual bool CanDeoptimize() const { return false; }
virtual bool HasSideEffect() const { return false; }
- virtual intptr_t ResultCid() const { return kDynamicCid; }
-
private:
DISALLOW_COPY_AND_ASSIGN(CurrentContextInstr);
};
@@ -2069,7 +2103,6 @@
arguments_(arguments) { }
DECLARE_INSTRUCTION(ClosureCall)
- virtual RawAbstractType* CompileType() const;
const Array& argument_names() const { return ast_node_.arguments()->names(); }
intptr_t token_pos() const { return ast_node_.token_pos(); }
@@ -2085,8 +2118,6 @@
virtual bool HasSideEffect() const { return true; }
- virtual intptr_t ResultCid() const { return kDynamicCid; }
-
private:
const ClosureCallNode& ast_node_;
ZoneGrowableArray<PushArgumentInstr*>* arguments_;
@@ -2123,7 +2154,6 @@
}
DECLARE_INSTRUCTION(InstanceCall)
- virtual RawAbstractType* CompileType() const;
const ICData* ic_data() const { return ic_data_; }
bool HasICData() const {
@@ -2149,8 +2179,6 @@
virtual bool HasSideEffect() const { return true; }
- virtual intptr_t ResultCid() const { return kDynamicCid; }
-
protected:
friend class FlowGraphOptimizer;
void set_ic_data(ICData* value) { ic_data_ = value; }
@@ -2190,7 +2218,6 @@
}
DECLARE_INSTRUCTION(PolymorphicInstanceCall)
- virtual RawAbstractType* CompileType() const;
const ICData& ic_data() const { return ic_data_; }
@@ -2198,8 +2225,6 @@
virtual bool HasSideEffect() const { return true; }
- virtual intptr_t ResultCid() const { return kDynamicCid; }
-
virtual void PrintOperandsTo(BufferFormatter* f) const;
private:
@@ -2296,7 +2321,7 @@
StrictCompareInstr(Token::Kind kind, Value* left, Value* right);
DECLARE_INSTRUCTION(StrictCompare)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
virtual void PrintOperandsTo(BufferFormatter* f) const;
@@ -2309,8 +2334,6 @@
virtual Definition* Canonicalize(FlowGraphOptimizer* optimizer);
- virtual intptr_t ResultCid() const { return kBoolCid; }
-
virtual void EmitBranchCode(FlowGraphCompiler* compiler,
BranchInstr* branch);
@@ -2341,7 +2364,7 @@
}
DECLARE_INSTRUCTION(EqualityCompare)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
const ICData* ic_data() const { return ic_data_; }
bool HasICData() const {
@@ -2354,20 +2377,21 @@
void set_receiver_class_id(intptr_t value) { receiver_class_id_ = value; }
intptr_t receiver_class_id() const { return receiver_class_id_; }
+ bool IsInlinedNumericComparison() const {
+ return (receiver_class_id() == kDoubleCid)
+ || (receiver_class_id() == kMintCid)
+ || (receiver_class_id() == kSmiCid);
+ }
+
virtual void PrintOperandsTo(BufferFormatter* f) const;
virtual bool CanDeoptimize() const {
- return (receiver_class_id() != kDoubleCid)
- && (receiver_class_id() != kMintCid)
- && (receiver_class_id() != kSmiCid);
- }
- virtual bool HasSideEffect() const {
- return (receiver_class_id() != kDoubleCid)
- && (receiver_class_id() != kMintCid)
- && (receiver_class_id() != kSmiCid);
+ return !IsInlinedNumericComparison();
}
- virtual intptr_t ResultCid() const;
+ virtual bool HasSideEffect() const {
+ return !IsInlinedNumericComparison();
+ }
virtual void EmitBranchCode(FlowGraphCompiler* compiler,
BranchInstr* branch);
@@ -2409,7 +2433,7 @@
}
DECLARE_INSTRUCTION(RelationalOp)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
const ICData* ic_data() const { return ic_data_; }
bool HasICData() const {
@@ -2426,21 +2450,21 @@
intptr_t operands_class_id() const { return operands_class_id_; }
+ bool IsInlinedNumericComparison() const {
+ return (operands_class_id() == kDoubleCid)
+ || (operands_class_id() == kMintCid)
+ || (operands_class_id() == kSmiCid);
+ }
+
virtual void PrintOperandsTo(BufferFormatter* f) const;
virtual bool CanDeoptimize() const {
- return (operands_class_id() != kDoubleCid)
- && (operands_class_id() != kMintCid)
- && (operands_class_id() != kSmiCid);
+ return !IsInlinedNumericComparison();
}
virtual bool HasSideEffect() const {
- return (operands_class_id() != kDoubleCid)
- && (operands_class_id() != kMintCid)
- && (operands_class_id() != kSmiCid);
+ return !IsInlinedNumericComparison();
}
- virtual intptr_t ResultCid() const;
-
virtual void EmitBranchCode(FlowGraphCompiler* compiler,
BranchInstr* branch);
@@ -2482,7 +2506,7 @@
}
DECLARE_INSTRUCTION(StaticCall)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
// Accessors forwarded to the AST node.
const Function& function() const { return function_; }
@@ -2500,7 +2524,6 @@
virtual bool HasSideEffect() const { return true; }
- virtual intptr_t ResultCid() const { return result_cid_; }
void set_result_cid(intptr_t value) { result_cid_ = value; }
bool is_known_constructor() const { return is_known_constructor_; }
@@ -2518,7 +2541,6 @@
// Some library constructors have known semantics.
bool is_known_constructor_;
-
DISALLOW_COPY_AND_ASSIGN(StaticCallInstr);
};
@@ -2530,7 +2552,7 @@
context_level_(context_level) { }
DECLARE_INSTRUCTION(LoadLocal)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
const LocalVariable& local() const { return local_; }
intptr_t context_level() const { return context_level_; }
@@ -2544,8 +2566,6 @@
return false;
}
- virtual intptr_t ResultCid() const { return kDynamicCid; }
-
private:
const LocalVariable& local_;
const intptr_t context_level_;
@@ -2566,7 +2586,7 @@
}
DECLARE_INSTRUCTION(StoreLocal)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
const LocalVariable& local() const { return local_; }
Value* value() const { return inputs_[0]; }
@@ -2584,8 +2604,6 @@
return false;
}
- virtual intptr_t ResultCid() const { return kDynamicCid; }
-
private:
const LocalVariable& local_;
const intptr_t context_level_;
@@ -2600,7 +2618,6 @@
: ast_node_(*node) {}
DECLARE_INSTRUCTION(NativeCall)
- virtual RawAbstractType* CompileType() const;
intptr_t token_pos() const { return ast_node_.token_pos(); }
@@ -2620,8 +2637,6 @@
virtual bool HasSideEffect() const { return true; }
- virtual intptr_t ResultCid() const { return kDynamicCid; }
-
private:
const NativeBodyNode& ast_node_;
@@ -2643,7 +2658,7 @@
}
DECLARE_INSTRUCTION(StoreInstanceField)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
const Field& field() const { return field_; }
@@ -2659,8 +2674,6 @@
virtual bool HasSideEffect() const { return true; }
- virtual intptr_t ResultCid() const { return kDynamicCid; }
-
private:
const Field& field_;
const bool emit_store_barrier_;
@@ -2674,7 +2687,7 @@
explicit LoadStaticFieldInstr(const Field& field) : field_(field) {}
DECLARE_INSTRUCTION(LoadStaticField);
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
const Field& field() const { return field_; }
@@ -2684,8 +2697,6 @@
virtual bool HasSideEffect() const { return false; }
- virtual intptr_t ResultCid() const { return kDynamicCid; }
-
virtual bool AffectedBySideEffect() const { return !field().is_final(); }
virtual bool AttributesEqual(Instruction* other) const;
@@ -2706,7 +2717,7 @@
}
DECLARE_INSTRUCTION(StoreStaticField);
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
const Field& field() const { return field_; }
Value* value() const { return inputs_[0]; }
@@ -2717,8 +2728,6 @@
virtual bool HasSideEffect() const { return true; }
- virtual intptr_t ResultCid() const { return kDynamicCid; }
-
private:
const Field& field_;
@@ -2742,7 +2751,7 @@
}
DECLARE_INSTRUCTION(LoadIndexed)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
Value* array() const { return inputs_[0]; }
Value* index() const { return inputs_[1]; }
@@ -2755,8 +2764,6 @@
virtual bool HasSideEffect() const { return false; }
- virtual intptr_t ResultCid() const;
-
virtual Representation representation() const;
virtual bool AttributesEqual(Instruction* other) const;
@@ -2785,7 +2792,7 @@
}
DECLARE_INSTRUCTION(StringFromCharCode)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
Value* char_code() const { return inputs_[0]; }
@@ -2793,8 +2800,6 @@
virtual bool HasSideEffect() const { return false; }
- virtual intptr_t ResultCid() const { return cid_; }
-
virtual bool AttributesEqual(Instruction* other) const { return true; }
virtual bool AffectedBySideEffect() const { return false; }
@@ -2826,7 +2831,6 @@
}
DECLARE_INSTRUCTION(StoreIndexed)
- virtual RawAbstractType* CompileType() const;
Value* array() const { return inputs_[0]; }
Value* index() const { return inputs_[1]; }
@@ -2841,8 +2845,6 @@
virtual bool HasSideEffect() const { return true; }
- virtual intptr_t ResultCid() const { return kDynamicCid; }
-
virtual Representation RequiredInputRepresentation(intptr_t idx) const;
virtual intptr_t DeoptimizationTarget() const {
@@ -2869,7 +2871,7 @@
}
DECLARE_INSTRUCTION(BooleanNegate)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
Value* value() const { return inputs_[0]; }
@@ -2877,8 +2879,6 @@
virtual bool HasSideEffect() const { return false; }
- virtual intptr_t ResultCid() const { return kBoolCid; }
-
private:
DISALLOW_COPY_AND_ASSIGN(BooleanNegateInstr);
};
@@ -2905,7 +2905,7 @@
}
DECLARE_INSTRUCTION(InstanceOf)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
Value* value() const { return inputs_[0]; }
Value* instantiator() const { return inputs_[1]; }
@@ -2921,8 +2921,6 @@
virtual bool HasSideEffect() const { return true; }
- virtual intptr_t ResultCid() const { return kBoolCid; }
-
private:
const intptr_t token_pos_;
Value* value_;
@@ -2947,7 +2945,7 @@
}
DECLARE_INSTRUCTION(AllocateObject)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
virtual intptr_t ArgumentCount() const { return arguments_->length(); }
PushArgumentInstr* ArgumentAt(intptr_t index) const {
@@ -2963,8 +2961,6 @@
virtual bool HasSideEffect() const { return true; }
- virtual intptr_t ResultCid() const { return cid_; }
-
private:
const ConstructorCallNode& ast_node_;
ZoneGrowableArray<PushArgumentInstr*>* const arguments_;
@@ -2987,7 +2983,6 @@
}
DECLARE_INSTRUCTION(AllocateObjectWithBoundsCheck)
- virtual RawAbstractType* CompileType() const;
const Function& constructor() const { return ast_node_.constructor(); }
intptr_t token_pos() const { return ast_node_.token_pos(); }
@@ -2998,8 +2993,6 @@
virtual bool HasSideEffect() const { return true; }
- virtual intptr_t ResultCid() const { return kDynamicCid; }
-
private:
const ConstructorCallNode& ast_node_;
@@ -3010,16 +3003,13 @@
class CreateArrayInstr : public TemplateDefinition<1> {
public:
CreateArrayInstr(intptr_t token_pos,
- ZoneGrowableArray<PushArgumentInstr*>* arguments,
+ intptr_t num_elements,
const AbstractType& type,
Value* element_type)
: token_pos_(token_pos),
- arguments_(arguments),
+ num_elements_(num_elements),
type_(type) {
#if defined(DEBUG)
- for (int i = 0; i < ArgumentCount(); ++i) {
- ASSERT(ArgumentAt(i) != NULL);
- }
ASSERT(element_type != NULL);
ASSERT(type_.IsZoneHandle());
ASSERT(!type_.IsNull());
@@ -3029,12 +3019,11 @@
}
DECLARE_INSTRUCTION(CreateArray)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
- virtual intptr_t ArgumentCount() const { return arguments_->length(); }
+ intptr_t num_elements() const { return num_elements_; }
intptr_t token_pos() const { return token_pos_; }
- PushArgumentInstr* ArgumentAt(intptr_t i) const { return (*arguments_)[i]; }
const AbstractType& type() const { return type_; }
Value* element_type() const { return inputs_[0]; }
@@ -3044,11 +3033,9 @@
virtual bool HasSideEffect() const { return true; }
- virtual intptr_t ResultCid() const { return kArrayCid; }
-
private:
const intptr_t token_pos_;
- ZoneGrowableArray<PushArgumentInstr*>* const arguments_;
+ const intptr_t num_elements_;
const AbstractType& type_;
DISALLOW_COPY_AND_ASSIGN(CreateArrayInstr);
@@ -3065,7 +3052,7 @@
token_pos_(token_pos) { }
DECLARE_INSTRUCTION(CreateClosure)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
intptr_t token_pos() const { return token_pos_; }
const Function& function() const { return function_; }
@@ -3081,8 +3068,6 @@
virtual bool HasSideEffect() const { return true; }
- virtual intptr_t ResultCid() const { return kDynamicCid; }
-
private:
const Function& function_;
ZoneGrowableArray<PushArgumentInstr*>* arguments_;
@@ -3109,7 +3094,7 @@
}
DECLARE_INSTRUCTION(LoadField)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
Value* value() const { return inputs_[0]; }
intptr_t offset_in_bytes() const { return offset_in_bytes_; }
@@ -3122,8 +3107,6 @@
virtual bool HasSideEffect() const { return false; }
- virtual intptr_t ResultCid() const { return result_cid_; }
-
virtual bool AttributesEqual(Instruction* other) const;
virtual bool AffectedBySideEffect() const { return !immutable_; }
@@ -3171,7 +3154,7 @@
}
DECLARE_INSTRUCTION(StoreVMField)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
Value* value() const { return inputs_[0]; }
Value* dest() const { return inputs_[1]; }
@@ -3184,8 +3167,6 @@
virtual bool HasSideEffect() const { return true; }
- virtual intptr_t ResultCid() const { return kDynamicCid; }
-
private:
const intptr_t offset_in_bytes_;
const AbstractType& type_;
@@ -3207,7 +3188,6 @@
}
DECLARE_INSTRUCTION(InstantiateTypeArguments)
- virtual RawAbstractType* CompileType() const;
Value* instantiator() const { return inputs_[0]; }
const AbstractTypeArguments& type_arguments() const {
@@ -3221,8 +3201,6 @@
virtual bool HasSideEffect() const { return true; }
- virtual intptr_t ResultCid() const { return kDynamicCid; }
-
private:
const intptr_t token_pos_;
const AbstractTypeArguments& type_arguments_;
@@ -3244,7 +3222,6 @@
}
DECLARE_INSTRUCTION(ExtractConstructorTypeArguments)
- virtual RawAbstractType* CompileType() const;
Value* instantiator() const { return inputs_[0]; }
const AbstractTypeArguments& type_arguments() const {
@@ -3258,8 +3235,6 @@
virtual bool HasSideEffect() const { return false; }
- virtual intptr_t ResultCid() const { return kDynamicCid; }
-
private:
const intptr_t token_pos_;
const AbstractTypeArguments& type_arguments_;
@@ -3278,7 +3253,6 @@
}
DECLARE_INSTRUCTION(ExtractConstructorInstantiator)
- virtual RawAbstractType* CompileType() const;
Value* instantiator() const { return inputs_[0]; }
const AbstractTypeArguments& type_arguments() const {
@@ -3291,8 +3265,6 @@
virtual bool HasSideEffect() const { return false; }
- virtual intptr_t ResultCid() const { return kDynamicCid; }
-
private:
const ConstructorCallNode& ast_node_;
@@ -3308,7 +3280,7 @@
num_context_variables_(num_context_variables) {}
DECLARE_INSTRUCTION(AllocateContext);
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
intptr_t token_pos() const { return token_pos_; }
intptr_t num_context_variables() const { return num_context_variables_; }
@@ -3319,8 +3291,6 @@
virtual bool HasSideEffect() const { return false; }
- virtual intptr_t ResultCid() const { return kDynamicCid; }
-
private:
const intptr_t token_pos_;
const intptr_t num_context_variables_;
@@ -3337,7 +3307,6 @@
}
DECLARE_INSTRUCTION(ChainContext)
- virtual RawAbstractType* CompileType() const;
virtual intptr_t ArgumentCount() const { return 0; }
@@ -3364,14 +3333,12 @@
Value* context_value() const { return inputs_[0]; }
DECLARE_INSTRUCTION(CloneContext)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
virtual bool CanDeoptimize() const { return true; }
virtual bool HasSideEffect() const { return false; }
- virtual intptr_t ResultCid() const { return kContextCid; }
-
private:
const intptr_t token_pos_;
@@ -3389,7 +3356,6 @@
const LocalVariable& stacktrace_var() const { return stacktrace_var_; }
DECLARE_INSTRUCTION(CatchEntry)
- virtual RawAbstractType* CompileType() const;
virtual intptr_t ArgumentCount() const { return 0; }
@@ -3420,7 +3386,6 @@
}
DECLARE_INSTRUCTION(CheckEitherNonSmi)
- virtual RawAbstractType* CompileType() const;
virtual intptr_t ArgumentCount() const { return 0; }
@@ -3462,15 +3427,13 @@
virtual bool AffectedBySideEffect() const { return false; }
virtual bool AttributesEqual(Instruction* other) const { return true; }
- virtual intptr_t ResultCid() const;
-
virtual Representation RequiredInputRepresentation(intptr_t idx) const {
ASSERT(idx == 0);
return kUnboxedDouble;
}
DECLARE_INSTRUCTION(BoxDouble)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
private:
const intptr_t token_pos_;
@@ -3495,15 +3458,13 @@
virtual bool AffectedBySideEffect() const { return false; }
virtual bool AttributesEqual(Instruction* other) const { return true; }
- virtual intptr_t ResultCid() const;
-
virtual Representation RequiredInputRepresentation(intptr_t idx) const {
ASSERT(idx == 0);
return kUnboxedMint;
}
DECLARE_INSTRUCTION(BoxInteger)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
private:
DISALLOW_COPY_AND_ASSIGN(BoxIntegerInstr);
@@ -3521,15 +3482,12 @@
Value* value() const { return inputs_[0]; }
virtual bool CanDeoptimize() const {
- return (value()->ResultCid() != kDoubleCid)
- && (value()->ResultCid() != kSmiCid);
+ return (value()->Type()->ToCid() != kDoubleCid)
+ && (value()->Type()->ToCid() != kSmiCid);
}
virtual bool HasSideEffect() const { return false; }
- // The output is not an instance but when it is boxed it becomes double.
- virtual intptr_t ResultCid() const { return kDoubleCid; }
-
virtual Representation representation() const {
return kUnboxedDouble;
}
@@ -3538,7 +3496,7 @@
virtual bool AttributesEqual(Instruction* other) const { return true; }
DECLARE_INSTRUCTION(UnboxDouble)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
private:
DISALLOW_COPY_AND_ASSIGN(UnboxDoubleInstr);
@@ -3556,15 +3514,13 @@
Value* value() const { return inputs_[0]; }
virtual bool CanDeoptimize() const {
- return (value()->ResultCid() != kMintCid)
- && (value()->ResultCid() != kSmiCid);
+ return (value()->Type()->ToCid() != kSmiCid)
+ && (value()->Type()->ToCid() != kMintCid);
}
virtual bool HasSideEffect() const { return false; }
- virtual intptr_t ResultCid() const;
-
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
virtual Representation representation() const {
return kUnboxedMint;
@@ -3599,9 +3555,6 @@
return true;
}
- // The output is not an instance but when it is boxed it becomes double.
- virtual intptr_t ResultCid() const { return kDoubleCid; }
-
virtual Representation representation() const {
return kUnboxedDouble;
}
@@ -3618,7 +3571,7 @@
}
DECLARE_INSTRUCTION(MathSqrt)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
private:
DISALLOW_COPY_AND_ASSIGN(MathSqrtInstr);
@@ -3656,8 +3609,6 @@
return op_kind() == other->AsBinaryDoubleOp()->op_kind();
}
- virtual intptr_t ResultCid() const;
-
virtual Representation representation() const {
return kUnboxedDouble;
}
@@ -3674,7 +3625,7 @@
}
DECLARE_INSTRUCTION(BinaryDoubleOp)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
virtual Definition* Canonicalize(FlowGraphOptimizer* optimizer);
@@ -3718,8 +3669,7 @@
return op_kind() == other->AsBinaryMintOp()->op_kind();
}
- virtual intptr_t ResultCid() const;
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
virtual Representation representation() const {
return kUnboxedMint;
@@ -3779,8 +3729,7 @@
return op_kind() == other->AsShiftMintOp()->op_kind();
}
- virtual intptr_t ResultCid() const;
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
virtual Representation representation() const {
return kUnboxedMint;
@@ -3834,8 +3783,7 @@
return op_kind() == other->AsUnaryMintOp()->op_kind();
}
- virtual intptr_t ResultCid() const;
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
virtual Representation representation() const {
return kUnboxedMint;
@@ -3890,7 +3838,7 @@
DECLARE_INSTRUCTION(BinarySmiOp)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
virtual bool CanDeoptimize() const;
@@ -3899,8 +3847,6 @@
virtual bool AffectedBySideEffect() const { return false; }
virtual bool AttributesEqual(Instruction* other) const;
- virtual intptr_t ResultCid() const;
-
void set_overflow(bool overflow) {
overflow_ = overflow;
}
@@ -3943,14 +3889,12 @@
virtual void PrintOperandsTo(BufferFormatter* f) const;
DECLARE_INSTRUCTION(UnarySmiOp)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
virtual bool CanDeoptimize() const { return op_kind() == Token::kNEGATE; }
virtual bool HasSideEffect() const { return false; }
- virtual intptr_t ResultCid() const { return kSmiCid; }
-
private:
const Token::Kind op_kind_;
@@ -3966,7 +3910,6 @@
intptr_t token_pos() const { return token_pos_; }
DECLARE_INSTRUCTION(CheckStackOverflow)
- virtual RawAbstractType* CompileType() const;
virtual intptr_t ArgumentCount() const { return 0; }
@@ -3989,7 +3932,7 @@
InstanceCallInstr* instance_call() const { return instance_call_; }
DECLARE_INSTRUCTION(SmiToDouble)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
virtual intptr_t ArgumentCount() const { return 1; }
@@ -3997,8 +3940,6 @@
virtual bool HasSideEffect() const { return false; }
- virtual intptr_t ResultCid() const { return kDoubleCid; }
-
private:
InstanceCallInstr* instance_call_;
@@ -4018,7 +3959,7 @@
InstanceCallInstr* instance_call() const { return instance_call_; }
DECLARE_INSTRUCTION(DoubleToInteger)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
virtual intptr_t ArgumentCount() const { return 1; }
@@ -4026,9 +3967,6 @@
virtual bool HasSideEffect() const { return false; }
- // Result could be any of the int types.
- virtual intptr_t ResultCid() const { return kDynamicCid; }
-
private:
InstanceCallInstr* instance_call_;
@@ -4049,14 +3987,12 @@
Value* value() const { return inputs_[0]; }
DECLARE_INSTRUCTION(DoubleToSmi)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
virtual bool CanDeoptimize() const { return true; }
virtual bool HasSideEffect() const { return false; }
- virtual intptr_t ResultCid() const { return kSmiCid; }
-
virtual Representation RequiredInputRepresentation(intptr_t idx) const {
ASSERT(idx == 0);
return kUnboxedDouble;
@@ -4085,14 +4021,12 @@
MethodRecognizer::Kind recognized_kind() const { return recognized_kind_; }
DECLARE_INSTRUCTION(DoubleToDouble)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
virtual bool CanDeoptimize() const { return false; }
virtual bool HasSideEffect() const { return false; }
- virtual intptr_t ResultCid() const { return kDoubleCid; }
-
virtual Representation representation() const {
return kUnboxedDouble;
}
@@ -4128,15 +4062,13 @@
MethodRecognizer::Kind recognized_kind() const { return recognized_kind_; }
DECLARE_INSTRUCTION(InvokeMathCFunction)
- virtual RawAbstractType* CompileType() const;
+ virtual CompileType* ComputeInitialType() const;
virtual void PrintOperandsTo(BufferFormatter* f) const;
virtual bool CanDeoptimize() const { return false; }
virtual bool HasSideEffect() const { return false; }
- virtual intptr_t ResultCid() const { return kDoubleCid; }
-
virtual Representation representation() const {
return kUnboxedDouble;
}
@@ -4188,7 +4120,6 @@
const ICData& unary_checks);
DECLARE_INSTRUCTION(CheckClass)
- virtual RawAbstractType* CompileType() const;
virtual intptr_t ArgumentCount() const { return 0; }
@@ -4225,7 +4156,6 @@
}
DECLARE_INSTRUCTION(CheckSmi)
- virtual RawAbstractType* CompileType() const;
virtual intptr_t ArgumentCount() const { return 0; }
@@ -4261,7 +4191,6 @@
}
DECLARE_INSTRUCTION(CheckArrayBound)
- virtual RawAbstractType* CompileType() const;
virtual intptr_t ArgumentCount() const { return 0; }
diff --git a/runtime/vm/intermediate_language_arm.cc b/runtime/vm/intermediate_language_arm.cc
index 176e4a4..2e3f226 100644
--- a/runtime/vm/intermediate_language_arm.cc
+++ b/runtime/vm/intermediate_language_arm.cc
@@ -172,9 +172,9 @@
}
-intptr_t LoadIndexedInstr::ResultCid() const {
+CompileType* LoadIndexedInstr::ComputeInitialType() const {
UNIMPLEMENTED();
- return kDynamicCid;
+ return NULL;
}
diff --git a/runtime/vm/intermediate_language_ia32.cc b/runtime/vm/intermediate_language_ia32.cc
index 0787527..a475fd6 100644
--- a/runtime/vm/intermediate_language_ia32.cc
+++ b/runtime/vm/intermediate_language_ia32.cc
@@ -212,9 +212,7 @@
Register obj = locs()->in(0).reg();
Register result = locs()->out().reg();
- if (!is_eliminated()) {
- EmitAssertBoolean(obj, token_pos(), deopt_id(), locs(), compiler);
- }
+ EmitAssertBoolean(obj, token_pos(), deopt_id(), locs(), compiler);
ASSERT(obj == result);
}
@@ -1097,14 +1095,16 @@
}
-intptr_t LoadIndexedInstr::ResultCid() const {
+CompileType* LoadIndexedInstr::ComputeInitialType() const {
switch (class_id_) {
case kArrayCid:
case kImmutableArrayCid:
- return kDynamicCid;
+ return CompileType::Dynamic();
+
case kFloat32ArrayCid :
case kFloat64ArrayCid :
- return kDoubleCid;
+ return CompileType::FromCid(kDoubleCid);
+
case kInt8ArrayCid:
case kUint8ArrayCid:
case kUint8ClampedArrayCid:
@@ -1114,16 +1114,19 @@
case kUint16ArrayCid:
case kOneByteStringCid:
case kTwoByteStringCid:
- return kSmiCid;
+ return CompileType::FromCid(kSmiCid);
+
case kInt32ArrayCid:
case kUint32ArrayCid:
// Result can be Smi or Mint when boxed.
// Instruction can deoptimize if we optimistically assumed that the result
// fits into Smi.
- return CanDeoptimize() ? kSmiCid : kDynamicCid;
+ return CanDeoptimize() ? CompileType::FromCid(kSmiCid)
+ : CompileType::Int();
+
default:
UNIMPLEMENTED();
- return kDynamicCid;
+ return CompileType::Dynamic();
}
}
@@ -1163,12 +1166,19 @@
LocationSummary* locs =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
locs->set_in(0, Location::RequiresRegister());
- // The smi index is either untagged and tagged again at the end of the
- // operation (element size == 1), or it is left smi tagged (for all element
- // sizes > 1).
- locs->set_in(1, CanBeImmediateIndex(index(), class_id())
- ? Location::RegisterOrSmiConstant(index())
- : Location::RequiresRegister());
+ // The smi index is either untagged (element size == 1), or it is left smi
+ // tagged (for all element sizes > 1).
+ if (index_scale() == 1) {
+ locs->set_in(1, CanBeImmediateIndex(index(), class_id())
+ ? Location::Constant(
+ index()->definition()->AsConstant()->value())
+ : Location::WritableRegister());
+ } else {
+ locs->set_in(1, CanBeImmediateIndex(index(), class_id())
+ ? Location::Constant(
+ index()->definition()->AsConstant()->value())
+ : Location::RequiresRegister());
+ }
if (representation() == kUnboxedDouble) {
locs->set_out(Location::RequiresFpuRegister());
} else {
@@ -1199,9 +1209,6 @@
FieldAddress(array, ExternalUint8Array::data_offset()));
__ movzxb(result, element_address);
__ SmiTag(result);
- if (index.IsRegister()) {
- __ SmiTag(index.reg()); // Re-tag.
- }
return;
}
@@ -1236,9 +1243,6 @@
__ movsd(result, element_address);
break;
}
- if ((index_scale() == 1) && index.IsRegister()) {
- __ SmiTag(index.reg()); // Re-tag.
- }
return;
}
@@ -1291,9 +1295,6 @@
__ movl(result, element_address);
break;
}
- if ((index_scale() == 1) && index.IsRegister()) {
- __ SmiTag(index.reg()); // Re-tag.
- }
}
@@ -1305,7 +1306,9 @@
case kArrayCid:
case kInt8ArrayCid:
case kUint8ArrayCid:
+ case kExternalUint8ArrayCid:
case kUint8ClampedArrayCid:
+ case kExternalUint8ClampedArrayCid:
case kInt16ArrayCid:
case kUint16ArrayCid:
return kTagged;
@@ -1328,18 +1331,31 @@
LocationSummary* locs =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
locs->set_in(0, Location::RequiresRegister());
- // The smi index is either untagged and tagged again at the end of the
- // operation (element size == 1), or it is left smi tagged (for all element
- // sizes > 1).
- locs->set_in(1, CanBeImmediateIndex(index(), class_id())
- ? Location::RegisterOrSmiConstant(index())
- : Location::RequiresRegister());
+ // The smi index is either untagged (element size == 1), or it is left smi
+ // tagged (for all element sizes > 1).
+ intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(class_id());
+ if (index_scale == 1) {
+ locs->set_in(1, CanBeImmediateIndex(index(), class_id())
+ ? Location::Constant(
+ index()->definition()->AsConstant()->value())
+ : Location::WritableRegister());
+ } else {
+ locs->set_in(1, CanBeImmediateIndex(index(), class_id())
+ ? Location::Constant(
+ index()->definition()->AsConstant()->value())
+ : Location::RequiresRegister());
+ }
switch (class_id()) {
case kArrayCid:
locs->set_in(2, ShouldEmitStoreBarrier()
? Location::WritableRegister()
: Location::RegisterOrConstant(value()));
break;
+ case kExternalUint8ArrayCid:
+ case kExternalUint8ClampedArrayCid:
+ // Need temp register to load the external array's data array.
+ locs->AddTemp(Location::RequiresRegister());
+ // Fall through.
case kInt8ArrayCid:
case kUint8ArrayCid:
case kUint8ClampedArrayCid:
@@ -1376,11 +1392,25 @@
intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(class_id());
- FieldAddress element_address = index.IsRegister() ?
- FlowGraphCompiler::ElementAddressForRegIndex(
- class_id(), index_scale, array, index.reg()) :
- FlowGraphCompiler::ElementAddressForIntIndex(
+ Address element_address(kNoRegister, 0);
+ if ((class_id() == kExternalUint8ArrayCid) ||
+ (class_id() == kExternalUint8ClampedArrayCid)) {
+ Register temp = locs()->temp(0).reg();
+ element_address = index.IsRegister()
+ ? FlowGraphCompiler::ExternalElementAddressForRegIndex(
+ class_id(), index_scale, temp, index.reg())
+ : FlowGraphCompiler::ExternalElementAddressForIntIndex(
+ class_id(), index_scale, temp,
+ Smi::Cast(index.constant()).Value());
+ __ movl(temp,
+ FieldAddress(array, ExternalUint8Array::data_offset()));
+ } else {
+ 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:
@@ -1397,6 +1427,7 @@
break;
case kInt8ArrayCid:
case kUint8ArrayCid:
+ case kExternalUint8ArrayCid:
if (index.IsRegister()) {
__ SmiUntag(index.reg());
}
@@ -1409,11 +1440,9 @@
__ SmiUntag(EAX);
__ movb(element_address, AL);
}
- if (index.IsRegister()) {
- __ SmiTag(index.reg()); // Re-tag.
- }
break;
- case kUint8ClampedArrayCid: {
+ case kUint8ClampedArrayCid:
+ case kExternalUint8ClampedArrayCid: {
if (index.IsRegister()) {
__ SmiUntag(index.reg());
}
@@ -1443,9 +1472,6 @@
__ Bind(&store_value);
__ movb(element_address, AL);
}
- if (index.IsRegister()) {
- __ SmiTag(index.reg()); // Re-tag.
- }
break;
}
case kInt16ArrayCid:
@@ -1586,18 +1612,12 @@
void CreateArrayInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
// Allocate the array. EDX = length, ECX = element type.
ASSERT(locs()->in(0).reg() == ECX);
- __ movl(EDX, Immediate(Smi::RawValue(ArgumentCount())));
+ __ movl(EDX, Immediate(Smi::RawValue(num_elements())));
compiler->GenerateCall(token_pos(),
&StubCode::AllocateArrayLabel(),
PcDescriptors::kOther,
locs());
ASSERT(locs()->out().reg() == EAX);
-
- // Pop the element values from the stack into the array.
- __ leal(EDX, FieldAddress(EAX, Array::data_offset()));
- for (int i = ArgumentCount() - 1; i >= 0; --i) {
- __ popl(Address(EDX, i * kWordSize));
- }
}
@@ -2219,10 +2239,38 @@
break;
}
case Token::kSHL: {
+ Range* right_range = this->right()->definition()->range();
+ if (this->left()->BindsToConstant()) {
+ // If left is constant, we know the maximal allowed size for right.
+ const Object& obj = this->left()->BoundConstant();
+ if (obj.IsSmi()) {
+ const intptr_t left_int = Smi::Cast(obj).Value();
+ if (left_int == 0) {
+ __ cmpl(right, Immediate(0));
+ __ j(NEGATIVE, deopt);
+ break;
+ }
+ intptr_t tmp = (left_int > 0) ? left_int : ~left_int;
+ intptr_t max_right = kSmiBits;
+ while ((tmp >>= 1) != 0) {
+ max_right--;
+ }
+ const bool right_needs_check =
+ (right_range == NULL) ||
+ !right_range->IsWithin(0, max_right - 1);
+ if (right_needs_check) {
+ __ cmpl(right,
+ Immediate(reinterpret_cast<int32_t>(Smi::New(max_right))));
+ __ j(ABOVE_EQUAL, deopt);
+ }
+ __ SmiUntag(right);
+ __ shll(left, right);
+ break;
+ }
+ }
Register temp = locs()->temp(0).reg();
// Check if count too large for handling it inlined.
__ movl(temp, left);
- Range* right_range = this->right()->definition()->range();
const bool right_needs_check =
(right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1));
if (right_needs_check) {
@@ -2267,8 +2315,8 @@
LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary() const {
- ASSERT((left()->ResultCid() != kDoubleCid) &&
- (right()->ResultCid() != kDoubleCid));
+ ASSERT((left()->Type()->ToCid() != kDoubleCid) &&
+ (right()->Type()->ToCid() != kDoubleCid));
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 1;
LocationSummary* summary =
@@ -2354,18 +2402,23 @@
LocationSummary* UnboxDoubleInstr::MakeLocationSummary() const {
const intptr_t kNumInputs = 1;
- const intptr_t kNumTemps = CanDeoptimize() ? 1 : 0;
+ const intptr_t value_cid = value()->Type()->ToCid();
+ const bool needs_temp = ((value_cid != kSmiCid) && (value_cid != kDoubleCid));
+ const bool needs_writable_input = (value_cid == kSmiCid);
+ const intptr_t kNumTemps = needs_temp ? 1 : 0;
LocationSummary* summary =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
- summary->set_in(0, Location::RequiresRegister());
- if (CanDeoptimize()) summary->set_temp(0, Location::RequiresRegister());
+ summary->set_in(0, needs_writable_input
+ ? Location::WritableRegister()
+ : Location::RequiresRegister());
+ if (needs_temp) summary->set_temp(0, Location::RequiresRegister());
summary->set_out(Location::RequiresFpuRegister());
return summary;
}
void UnboxDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- const intptr_t value_cid = value()->ResultCid();
+ const intptr_t value_cid = value()->Type()->ToCid();
const Register value = locs()->in(0).reg();
const XmmRegister result = locs()->out().fpu_reg();
@@ -2374,13 +2427,21 @@
} else if (value_cid == kSmiCid) {
__ SmiUntag(value); // Untag input before conversion.
__ cvtsi2sd(result, value);
- __ SmiTag(value); // Restore input register.
} else {
Label* deopt = compiler->AddDeoptStub(deopt_id_, kDeoptBinaryDoubleOp);
- compiler->LoadDoubleOrSmiToFpu(result,
- value,
- locs()->temp(0).reg(),
- deopt);
+ Register temp = locs()->temp(0).reg();
+ Label is_smi, done;
+ __ testl(value, Immediate(kSmiTagMask));
+ __ j(ZERO, &is_smi);
+ __ CompareClassId(value, kDoubleCid, temp);
+ __ j(NOT_EQUAL, deopt);
+ __ movsd(result, FieldAddress(value, Double::value_offset()));
+ __ jmp(&done);
+ __ Bind(&is_smi);
+ __ movl(temp, value);
+ __ SmiUntag(temp);
+ __ cvtsi2sd(result, temp);
+ __ Bind(&done);
}
}
@@ -2753,8 +2814,6 @@
void CheckSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- // TODO(srdjan): Check if we can remove this by reordering CSE and LICM.
- if (value()->ResultCid() == kSmiCid) return;
Register value = locs()->in(0).reg();
Label* deopt = compiler->AddDeoptStub(deopt_id(),
kDeoptCheckSmi);
@@ -2809,18 +2868,23 @@
LocationSummary* UnboxIntegerInstr::MakeLocationSummary() const {
const intptr_t kNumInputs = 1;
- const intptr_t kNumTemps = CanDeoptimize() ? 1 : 0;
+ const intptr_t value_cid = value()->Type()->ToCid();
+ const bool needs_temp = ((value_cid != kSmiCid) && (value_cid != kMintCid));
+ const bool needs_writable_input = (value_cid == kSmiCid);
+ const intptr_t kNumTemps = needs_temp ? 1 : 0;
LocationSummary* summary =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
- summary->set_in(0, Location::RequiresRegister());
- if (CanDeoptimize()) summary->set_temp(0, Location::RequiresRegister());
+ summary->set_in(0, needs_writable_input
+ ? Location::WritableRegister()
+ : Location::RequiresRegister());
+ if (needs_temp) summary->set_temp(0, Location::RequiresRegister());
summary->set_out(Location::RequiresFpuRegister());
return summary;
}
void UnboxIntegerInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- const intptr_t value_cid = value()->ResultCid();
+ const intptr_t value_cid = value()->Type()->ToCid();
const Register value = locs()->in(0).reg();
const XmmRegister result = locs()->out().fpu_reg();
@@ -2830,7 +2894,6 @@
__ SmiUntag(value); // Untag input before conversion.
__ movd(result, value);
__ pmovsxdq(result, result);
- __ SmiTag(value); // Restore input register.
} else {
Register temp = locs()->temp(0).reg();
Label* deopt = compiler->AddDeoptStub(deopt_id_, kDeoptUnboxInteger);
diff --git a/runtime/vm/intermediate_language_mips.cc b/runtime/vm/intermediate_language_mips.cc
index 77bd6a2..2ec2dc6 100644
--- a/runtime/vm/intermediate_language_mips.cc
+++ b/runtime/vm/intermediate_language_mips.cc
@@ -172,9 +172,9 @@
}
-intptr_t LoadIndexedInstr::ResultCid() const {
+CompileType* LoadIndexedInstr::ComputeInitialType() const {
UNIMPLEMENTED();
- return kDynamicCid;
+ return NULL;
}
diff --git a/runtime/vm/intermediate_language_x64.cc b/runtime/vm/intermediate_language_x64.cc
index c0e93f9..41b82f9 100644
--- a/runtime/vm/intermediate_language_x64.cc
+++ b/runtime/vm/intermediate_language_x64.cc
@@ -219,9 +219,7 @@
Register obj = locs()->in(0).reg();
Register result = locs()->out().reg();
- if (!is_eliminated()) {
- EmitAssertBoolean(obj, token_pos(), deopt_id(), locs(), compiler);
- }
+ EmitAssertBoolean(obj, token_pos(), deopt_id(), locs(), compiler);
ASSERT(obj == result);
}
@@ -961,14 +959,16 @@
}
-intptr_t LoadIndexedInstr::ResultCid() const {
+CompileType* LoadIndexedInstr::ComputeInitialType() const {
switch (class_id_) {
case kArrayCid:
case kImmutableArrayCid:
- return kDynamicCid;
+ return CompileType::Dynamic();
+
case kFloat32ArrayCid :
case kFloat64ArrayCid :
- return kDoubleCid;
+ return CompileType::FromCid(kDoubleCid);
+
case kInt8ArrayCid:
case kUint8ArrayCid:
case kUint8ClampedArrayCid:
@@ -980,10 +980,11 @@
case kTwoByteStringCid:
case kInt32ArrayCid:
case kUint32ArrayCid:
- return kSmiCid;
+ return CompileType::FromCid(kSmiCid);
+
default:
UNIMPLEMENTED();
- return kSmiCid;
+ return NULL;
}
}
@@ -1020,12 +1021,19 @@
LocationSummary* locs =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
locs->set_in(0, Location::RequiresRegister());
- // The smi index is either untagged and tagged again at the end of the
- // operation (element size == 1), or it is left smi tagged (for all element
- // sizes > 1).
- locs->set_in(1, CanBeImmediateIndex(index(), class_id())
- ? Location::RegisterOrSmiConstant(index())
- : Location::RequiresRegister());
+ // The smi index is either untagged (element size == 1), or it is left smi
+ // tagged (for all element sizes > 1).
+ if (index_scale() == 1) {
+ locs->set_in(1, CanBeImmediateIndex(index(), class_id())
+ ? Location::Constant(
+ index()->definition()->AsConstant()->value())
+ : Location::WritableRegister());
+ } else {
+ locs->set_in(1, CanBeImmediateIndex(index(), class_id())
+ ? Location::Constant(
+ index()->definition()->AsConstant()->value())
+ : Location::RequiresRegister());
+ }
if (representation() == kUnboxedDouble) {
locs->set_out(Location::RequiresFpuRegister());
} else {
@@ -1056,9 +1064,6 @@
FieldAddress(array, ExternalUint8Array::data_offset()));
__ movzxb(result, element_address);
__ SmiTag(result);
- if (index.IsRegister()) {
- __ SmiTag(index.reg()); // Re-tag.
- }
return;
}
@@ -1084,10 +1089,6 @@
ASSERT(class_id() == kFloat64ArrayCid);
__ movsd(result, element_address);
}
-
- if ((index_scale() == 1) && index.IsRegister()) {
- __ SmiTag(index.reg()); // Re-tag.
- }
return;
}
@@ -1129,9 +1130,6 @@
__ movq(result, element_address);
break;
}
- if ((index_scale() == 1) && index.IsRegister()) {
- __ SmiTag(index.reg()); // Re-tag.
- }
}
@@ -1143,7 +1141,9 @@
case kArrayCid:
case kInt8ArrayCid:
case kUint8ArrayCid:
+ case kExternalUint8ArrayCid:
case kUint8ClampedArrayCid:
+ case kExternalUint8ClampedArrayCid:
case kInt16ArrayCid:
case kUint16ArrayCid:
case kInt32ArrayCid:
@@ -1164,19 +1164,32 @@
const intptr_t kNumTemps = 0;
LocationSummary* locs =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
- // The smi index is either untagged and tagged again at the end of the
- // operation (element size == 1), or it is left smi tagged (for all element
- // sizes > 1).
locs->set_in(0, Location::RequiresRegister());
- locs->set_in(1, CanBeImmediateIndex(index(), class_id())
- ? Location::RegisterOrSmiConstant(index())
- : Location::RequiresRegister());
+ // The smi index is either untagged (element size == 1), or it is left smi
+ // tagged (for all element sizes > 1).
+ intptr_t index_scale = FlowGraphCompiler::ElementSizeFor(class_id());
+ if (index_scale == 1) {
+ locs->set_in(1, CanBeImmediateIndex(index(), class_id())
+ ? Location::Constant(
+ index()->definition()->AsConstant()->value())
+ : Location::WritableRegister());
+ } else {
+ locs->set_in(1, CanBeImmediateIndex(index(), class_id())
+ ? Location::Constant(
+ index()->definition()->AsConstant()->value())
+ : Location::RequiresRegister());
+ }
switch (class_id()) {
case kArrayCid:
locs->set_in(2, ShouldEmitStoreBarrier()
? Location::WritableRegister()
: Location::RegisterOrConstant(value()));
break;
+ case kExternalUint8ArrayCid:
+ case kExternalUint8ClampedArrayCid:
+ // Need temp register to load the external array's data array.
+ locs->AddTemp(Location::RequiresRegister());
+ // Fall through.
case kInt8ArrayCid:
case kUint8ArrayCid:
case kUint8ClampedArrayCid:
@@ -1212,13 +1225,26 @@
Location index = locs()->in(1);
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());
+ Address element_address(kNoRegister, 0);
+ if ((class_id() == kExternalUint8ArrayCid) ||
+ (class_id() == kExternalUint8ClampedArrayCid)) {
+ Register temp = locs()->temp(0).reg();
+ element_address = index.IsRegister()
+ ? FlowGraphCompiler::ExternalElementAddressForRegIndex(
+ class_id(), index_scale, temp, index.reg())
+ : FlowGraphCompiler::ExternalElementAddressForIntIndex(
+ class_id(), index_scale, temp,
+ Smi::Cast(index.constant()).Value());
+ __ movq(temp,
+ FieldAddress(array, ExternalUint8Array::data_offset()));
+ } else {
+ 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:
@@ -1235,6 +1261,7 @@
break;
case kInt8ArrayCid:
case kUint8ArrayCid:
+ case kExternalUint8ArrayCid:
if (index.IsRegister()) {
__ SmiUntag(index.reg());
}
@@ -1247,11 +1274,9 @@
__ SmiUntag(RAX);
__ movb(element_address, RAX);
}
- if (index.IsRegister()) {
- __ SmiTag(index.reg()); // Re-tag.
- }
break;
- case kUint8ClampedArrayCid: {
+ case kUint8ClampedArrayCid:
+ case kExternalUint8ClampedArrayCid: {
if (index.IsRegister()) {
__ SmiUntag(index.reg());
}
@@ -1281,9 +1306,6 @@
__ Bind(&store_value);
__ movb(element_address, RAX);
}
- if (index.IsRegister()) {
- __ SmiTag(index.reg()); // Re-tag.
- }
break;
}
case kInt16ArrayCid:
@@ -1425,18 +1447,12 @@
void CreateArrayInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
// Allocate the array. R10 = length, RBX = element type.
ASSERT(locs()->in(0).reg() == RBX);
- __ movq(R10, Immediate(Smi::RawValue(ArgumentCount())));
+ __ movq(R10, Immediate(Smi::RawValue(num_elements())));
compiler->GenerateCall(token_pos(),
&StubCode::AllocateArrayLabel(),
PcDescriptors::kOther,
locs());
ASSERT(locs()->out().reg() == RAX);
-
- // Pop the element values from the stack into the array.
- __ leaq(R10, FieldAddress(RAX, Array::data_offset()));
- for (int i = ArgumentCount() - 1; i >= 0; --i) {
- __ popq(Address(R10, i * kWordSize));
- }
}
@@ -2079,10 +2095,38 @@
break;
}
case Token::kSHL: {
+ Range* right_range = this->right()->definition()->range();
+ if (this->left()->BindsToConstant()) {
+ // If left is constant, we know the maximal allowed size for right.
+ const Object& obj = this->left()->BoundConstant();
+ if (obj.IsSmi()) {
+ const intptr_t left_int = Smi::Cast(obj).Value();
+ if (left_int == 0) {
+ __ cmpq(right, Immediate(0));
+ __ j(NEGATIVE, deopt);
+ break;
+ }
+ intptr_t tmp = (left_int > 0) ? left_int : ~left_int;
+ intptr_t max_right = kSmiBits;
+ while ((tmp >>= 1) != 0) {
+ max_right--;
+ }
+ const bool right_needs_check =
+ (right_range == NULL) ||
+ !right_range->IsWithin(0, max_right - 1);
+ if (right_needs_check) {
+ __ cmpq(right,
+ Immediate(reinterpret_cast<int64_t>(Smi::New(max_right))));
+ __ j(ABOVE_EQUAL, deopt);
+ }
+ __ SmiUntag(right);
+ __ shlq(left, right);
+ break;
+ }
+ }
Register temp = locs()->temp(0).reg();
// Check if count too large for handling it inlined.
__ movq(temp, left);
- Range* right_range = this->right()->definition()->range();
const bool right_needs_check =
(right_range == NULL) || !right_range->IsWithin(0, (Smi::kBits - 1));
if (right_needs_check) {
@@ -2127,8 +2171,8 @@
LocationSummary* CheckEitherNonSmiInstr::MakeLocationSummary() const {
- ASSERT((left()->ResultCid() != kDoubleCid) &&
- (right()->ResultCid() != kDoubleCid));
+ ASSERT((left()->Type()->ToCid() != kDoubleCid) &&
+ (right()->Type()->ToCid() != kDoubleCid));
const intptr_t kNumInputs = 2;
const intptr_t kNumTemps = 1;
LocationSummary* summary =
@@ -2214,18 +2258,20 @@
LocationSummary* UnboxDoubleInstr::MakeLocationSummary() const {
const intptr_t kNumInputs = 1;
- const intptr_t kNumTemps = CanDeoptimize() ? 1 : 0;
+ const intptr_t kNumTemps = 0;
LocationSummary* summary =
new LocationSummary(kNumInputs, kNumTemps, LocationSummary::kNoCall);
- summary->set_in(0, Location::RequiresRegister());
- if (CanDeoptimize()) summary->set_temp(0, Location::RequiresRegister());
+ const bool needs_writable_input = (value()->Type()->ToCid() != kDoubleCid);
+ summary->set_in(0, needs_writable_input
+ ? Location::WritableRegister()
+ : Location::RequiresRegister());
summary->set_out(Location::RequiresFpuRegister());
return summary;
}
void UnboxDoubleInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- const intptr_t value_cid = value()->ResultCid();
+ const intptr_t value_cid = value()->Type()->ToCid();
const Register value = locs()->in(0).reg();
const XmmRegister result = locs()->out().fpu_reg();
@@ -2234,13 +2280,19 @@
} else if (value_cid == kSmiCid) {
__ SmiUntag(value); // Untag input before conversion.
__ cvtsi2sd(result, value);
- __ SmiTag(value); // Restore input register.
} else {
Label* deopt = compiler->AddDeoptStub(deopt_id_, kDeoptBinaryDoubleOp);
- compiler->LoadDoubleOrSmiToFpu(result,
- value,
- locs()->temp(0).reg(),
- deopt);
+ Label is_smi, done;
+ __ testq(value, Immediate(kSmiTagMask));
+ __ j(ZERO, &is_smi);
+ __ CompareClassId(value, kDoubleCid);
+ __ j(NOT_EQUAL, deopt);
+ __ movsd(result, FieldAddress(value, Double::value_offset()));
+ __ jmp(&done);
+ __ Bind(&is_smi);
+ __ SmiUntag(value);
+ __ cvtsi2sd(result, value);
+ __ Bind(&done);
}
}
@@ -2627,8 +2679,6 @@
void CheckSmiInstr::EmitNativeCode(FlowGraphCompiler* compiler) {
- // TODO(srdjan): Check if we can remove this by reordering CSE and LICM.
- if (value()->ResultCid() == kSmiCid) return;
Register value = locs()->in(0).reg();
Label* deopt = compiler->AddDeoptStub(deopt_id(),
kDeoptCheckSmi);
diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
index 5ed01da..5ed104a 100644
--- a/runtime/vm/object.cc
+++ b/runtime/vm/object.cc
@@ -42,8 +42,10 @@
"instead of showing the corresponding interface names (e.g. \"String\")");
DEFINE_FLAG(bool, trace_disabling_optimized_code, false,
"Trace disabling optimized code.");
-DEFINE_FLAG(int, huge_method_cutoff, 20000,
- "Huge method cutoff: Disables optimizations for huge methods.");
+DEFINE_FLAG(int, huge_method_cutoff_in_tokens, 20000,
+ "Huge method cutoff in tokens: Disables optimizations for huge methods.");
+DEFINE_FLAG(int, huge_method_cutoff_in_code_size, 200000,
+ "Huge method cutoff in unoptimized code size (in bytes).");
DECLARE_FLAG(bool, trace_compiler);
DECLARE_FLAG(bool, eliminate_type_checks);
DECLARE_FLAG(bool, enable_type_checks);
@@ -2075,6 +2077,13 @@
}
+void Class::set_mixin(const Type& value) const {
+ // Resolution and application of mixin type occurs in finalizer.
+ ASSERT(!value.IsNull());
+ StorePointer(&raw_ptr()->mixin_, value.raw());
+}
+
+
void Class::AddDirectSubclass(const Class& subclass) const {
ASSERT(!subclass.IsNull());
ASSERT(subclass.SuperClass() == raw());
@@ -2185,12 +2194,13 @@
// Since we do not truncate the type argument vector of a subclass (see
// below), we only check a prefix of the proper length.
// Check for covariance.
- if (other_type_arguments.IsNull() ||
- other_type_arguments.IsRawInstantiatedRaw(len)) {
+ if (other_type_arguments.IsNull() || other_type_arguments.IsRaw(len)) {
return true;
}
- if (type_arguments.IsNull() ||
- type_arguments.IsRawInstantiatedRaw(len)) {
+ if (type_arguments.IsNull() || type_arguments.IsRaw(len)) {
+ // Other type can't be more specific than this one because for that
+ // it would have to have all dynamic type arguments which is checked
+ // above.
return test_kind == kIsSubtypeOf;
}
return type_arguments.TypeTest(test_kind,
@@ -3663,10 +3673,20 @@
bool Function::is_optimizable() const {
- return OptimizableBit::decode(raw_ptr()->kind_tag_) &&
- (script() != Script::null()) &&
- !is_native() &&
- ((end_token_pos() - token_pos()) < FLAG_huge_method_cutoff);
+ if (OptimizableBit::decode(raw_ptr()->kind_tag_) &&
+ (script() != Script::null()) &&
+ !is_native() &&
+ ((end_token_pos() - token_pos()) < FLAG_huge_method_cutoff_in_tokens)) {
+ // Additional check needed for implicit getters.
+ if (HasCode() &&
+ (Code::Handle(unoptimized_code()).Size() >=
+ FLAG_huge_method_cutoff_in_code_size)) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+ return false;
}
@@ -4081,6 +4101,15 @@
}
+// The compiler generates an implicit constructor if a class definition
+// does not contain an explicit constructor or factory. The implicit
+// constructor has the same token position as the owner class.
+bool Function::IsImplicitConstructor() const {
+ return IsConstructor() &&
+ (token_pos() == Class::Handle(Owner()).token_pos());
+}
+
+
bool Function::IsImplicitClosureFunction() const {
if (!IsClosureFunction()) {
return false;
@@ -4140,6 +4169,24 @@
}
+RawFunction* Function::Clone(const Class& new_owner) const {
+ ASSERT(!IsConstructor());
+ Function& clone = Function::Handle();
+ clone ^= Object::Clone(*this, Heap::kOld);
+ const Class& owner = Class::Handle(this->Owner());
+ const PatchClass& clone_owner =
+ PatchClass::Handle(PatchClass::New(new_owner, owner));
+ clone.set_owner(clone_owner);
+ clone.StorePointer(&clone.raw_ptr()->code_, Code::null());
+ clone.StorePointer(&clone.raw_ptr()->unoptimized_code_, Code::null());
+ clone.set_usage_counter(0);
+ clone.set_deoptimization_counter(0);
+ clone.set_optimized_instruction_count(0);
+ clone.set_optimized_call_site_count(0);
+ return clone.raw();
+}
+
+
RawFunction* Function::NewClosureFunction(const String& name,
const Function& parent,
intptr_t token_pos) {
@@ -4378,6 +4425,16 @@
}
+RawClass* Function::origin() const {
+ const Object& obj = Object::Handle(raw_ptr()->owner_);
+ if (obj.IsClass()) {
+ return Class::Cast(obj).raw();
+ }
+ ASSERT(obj.IsPatchClass());
+ return PatchClass::Cast(obj).source_class();
+}
+
+
RawScript* Function::script() const {
const Object& obj = Object::Handle(raw_ptr()->owner_);
if (obj.IsClass()) {
@@ -4637,6 +4694,26 @@
}
+RawClass* Field::owner() const {
+ const Object& obj = Object::Handle(raw_ptr()->owner_);
+ if (obj.IsClass()) {
+ return Class::Cast(obj).raw();
+ }
+ ASSERT(obj.IsPatchClass());
+ return PatchClass::Cast(obj).patched_class();
+}
+
+
+RawClass* Field::origin() const {
+ const Object& obj = Object::Handle(raw_ptr()->owner_);
+ if (obj.IsClass()) {
+ return Class::Cast(obj).raw();
+ }
+ ASSERT(obj.IsPatchClass());
+ return PatchClass::Cast(obj).source_class();
+}
+
+
RawInstance* Field::value() const {
ASSERT(is_static()); // Valid only for static dart fields.
return raw_ptr()->value_;
@@ -4688,6 +4765,21 @@
}
+
+RawField* Field::Clone(const Class& new_owner) const {
+ Field& clone = Field::Handle();
+ clone ^= Object::Clone(*this, Heap::kOld);
+ const Class& owner = Class::Handle(this->owner());
+ const PatchClass& clone_owner =
+ PatchClass::Handle(PatchClass::New(new_owner, owner));
+ clone.set_owner(clone_owner);
+ if (!clone.is_static()) {
+ clone.SetOffset(0);
+ }
+ return clone.raw();
+}
+
+
RawString* Field::UserVisibleName() const {
const String& str = String::Handle(name());
return IdentifierPrettyName(str);
diff --git a/runtime/vm/object.h b/runtime/vm/object.h
index 7a4c908..88e93d2 100644
--- a/runtime/vm/object.h
+++ b/runtime/vm/object.h
@@ -661,6 +661,9 @@
// Asserts that the class of the super type has been resolved.
RawClass* SuperClass() const;
+ RawType* mixin() const { return raw_ptr()->mixin_; }
+ void set_mixin(const Type& value) const;
+
// Interfaces is an array of Types.
RawArray* interfaces() const { return raw_ptr()->interfaces_; }
void set_interfaces(const Array& value) const;
@@ -1197,7 +1200,7 @@
bool HasInstantiatedSignature() const;
RawClass* Owner() const;
-
+ RawClass* origin() const;
RawScript* script() const;
RawAbstractType* result_type() const { return raw_ptr()->result_type_; }
@@ -1205,12 +1208,14 @@
RawAbstractType* ParameterTypeAt(intptr_t index) const;
void SetParameterTypeAt(intptr_t index, const AbstractType& value) const;
+ RawArray* parameter_types() const { return raw_ptr()->parameter_types_; }
void set_parameter_types(const Array& value) const;
// Parameter names are valid for all valid parameter indices, and are not
// limited to named optional parameters.
RawString* ParameterNameAt(intptr_t index) const;
void SetParameterNameAt(intptr_t index, const String& value) const;
+ RawArray* parameter_names() const { return raw_ptr()->parameter_names_; }
void set_parameter_names(const Array& value) const;
// Sets function's code and code's function.
@@ -1284,6 +1289,7 @@
bool IsConstructor() const {
return (kind() == RawFunction::kConstructor) && !is_static();
}
+ bool IsImplicitConstructor() const;
bool IsFactory() const {
return (kind() == RawFunction::kConstructor) && is_static();
}
@@ -1561,6 +1567,10 @@
const Function& parent,
intptr_t token_pos);
+ // Allocate new function object, clone values from this function. The
+ // owner of the clone is new_owner.
+ RawFunction* Clone(const Class& new_owner) const;
+
// Slow function, use in asserts to track changes in important library
// functions.
int32_t SourceFingerprint() const;
@@ -1723,7 +1733,8 @@
RawInstance* value() const;
void set_value(const Instance& value) const;
- RawClass* owner() const { return raw_ptr()->owner_; }
+ RawClass* owner() const;
+ RawClass* origin() const; // Either mixin class, or same as owner().
RawAbstractType* type() const { return raw_ptr()->type_; }
void set_type(const AbstractType& value) const;
@@ -1739,6 +1750,10 @@
const Class& owner,
intptr_t token_pos);
+ // Allocate new field object, clone values from this field. The
+ // owner of the clone is new_owner.
+ RawField* Clone(const Class& new_owner) const;
+
static intptr_t value_offset() { return OFFSET_OF(RawField, value_); }
intptr_t token_pos() const { return raw_ptr()->token_pos_; }
@@ -1783,7 +1798,7 @@
void set_is_const(bool value) const {
set_kind_bits(ConstBit::update(value, raw_ptr()->kind_bits_));
}
- void set_owner(const Class& value) const {
+ void set_owner(const Object& value) const {
StorePointer(&raw_ptr()->owner_, value.raw());
}
void set_token_pos(intptr_t token_pos) const {
diff --git a/runtime/vm/parser.cc b/runtime/vm/parser.cc
index cee4d82..0c9427e 100644
--- a/runtime/vm/parser.cc
+++ b/runtime/vm/parser.cc
@@ -114,6 +114,13 @@
}
+LocalVariable* ParsedFunction::CreateArrayLiteralVar(intptr_t token_pos) {
+ return new LocalVariable(token_pos,
+ Symbols::ArrayLiteralVar(),
+ Type::ZoneHandle(Type::ArrayType()));
+}
+
+
void ParsedFunction::SetNodeSequence(SequenceNode* node_sequence) {
ASSERT(node_sequence_ == NULL);
ASSERT(node_sequence != NULL);
@@ -284,7 +291,8 @@
parsed_function_(parsed_function),
innermost_function_(Function::Handle(parsed_function->function().raw())),
current_class_(Class::Handle(parsed_function->function().Owner())),
- library_(Library::Handle(current_class_.library())),
+ library_(Library::Handle(Class::Handle(
+ parsed_function->function().origin()).library())),
try_blocks_list_(NULL) {
ASSERT(tokens_iterator_.IsValid());
ASSERT(!current_function().IsNull());
@@ -758,6 +766,10 @@
UNREACHABLE();
}
+ parsed_function->set_array_literal_var(
+ ParsedFunction::CreateArrayLiteralVar(func.token_pos()));
+ node_sequence->scope()->AddVariable(parsed_function->array_literal_var());
+
if (!HasReturnNode(node_sequence)) {
// Add implicit return node.
node_sequence->Add(new ReturnNode(func.end_token_pos()));
@@ -1375,6 +1387,18 @@
}
+LocalVariable* Parser::BuildArrayTempLocal(intptr_t token_pos) {
+ char name[64];
+ OS::SNPrint(name, 64, ":arrlit%"Pd, token_pos);
+ LocalVariable* temp =
+ new LocalVariable(token_pos,
+ String::ZoneHandle(Symbols::New(name)),
+ Type::ZoneHandle(Type::ArrayType()));
+ current_block_->scope->AddVariable(temp);
+ return temp;
+}
+
+
StaticCallNode* Parser::BuildInvocationMirrorAllocation(
intptr_t call_pos,
const String& function_name,
@@ -1393,7 +1417,8 @@
// The third argument is an array containing the original function arguments,
// including the receiver.
ArrayNode* args_array = new ArrayNode(
- args_pos, Type::ZoneHandle(Type::ArrayType()));
+ args_pos, Type::ZoneHandle(Type::ArrayType()),
+ *BuildArrayTempLocal(call_pos));
for (intptr_t i = 0; i < function_args.length(); i++) {
args_array->AddElement(function_args.NodeAt(i));
}
@@ -1817,6 +1842,13 @@
initialized_fields->Add(&field);
}
intptr_t field_pos = field.token_pos();
+ if (current_class().raw() != field.origin()) {
+ const Class& origin_class = Class::Handle(field.origin());
+ if (origin_class.library() != library_.raw()) {
+ ErrorMsg("Cannot handle initialized mixin field '%s'"
+ "from imported library\n", field.ToCString());
+ }
+ }
SetPosition(field_pos);
ASSERT(IsIdentifier());
ConsumeToken();
@@ -2009,13 +2041,11 @@
const Class& cls = Class::Handle(func.Owner());
ASSERT(!cls.IsNull());
- if (CurrentToken() == Token::kCLASS) {
+ if (func.IsImplicitConstructor()) {
// Special case: implicit constructor.
// The parser adds an implicit default constructor when a class
// does not have any explicit constructor or factory (see
- // Parser::AddImplicitConstructor). The token position of this implicit
- // constructor points to the 'class' keyword, which is followed
- // by the name of the class (which is also the constructor name).
+ // Parser::AddImplicitConstructor).
// There is no source text to parse. We just build the
// sequence node by hand.
return MakeImplicitConstructor(func);
@@ -3220,8 +3250,11 @@
String::Handle(type.UserVisibleName()).ToCString());
}
super_type ^= type.raw();
+ if (CurrentToken() == Token::kWITH) {
+ super_type = ParseMixins(super_type);
+ }
} else {
- // No extends clause: Implicitly extend Object.
+ // No extends clause: implicitly extend Object.
super_type = Type::ObjectType();
}
ASSERT(!super_type.IsNull());
@@ -3246,13 +3279,13 @@
cls.set_is_abstract();
}
- // Add an implicit constructor if no explicit constructor is present. No
- // implicit constructors are needed for patch classes.
- if (!members.has_constructor() && !is_patch) {
- AddImplicitConstructor(&members);
- }
CheckConstructors(&members);
+ // Need to compute this here since MakeArray() will clear the
+ // functions array in members.
+ const bool need_implicit_constructor =
+ !members.has_constructor() && !is_patch;
+
Array& array = Array::Handle();
array = Array::MakeArray(members.fields());
cls.SetFields(array);
@@ -3261,6 +3294,12 @@
array = Array::MakeArray(members.functions());
cls.SetFunctions(array);
+ // Add an implicit constructor if no explicit constructor is present.
+ // No implicit constructors are needed for patch classes.
+ if (need_implicit_constructor) {
+ AddImplicitConstructor(cls);
+ }
+
if (!is_patch) {
pending_classes.Add(cls, Heap::kOld);
} else {
@@ -3276,15 +3315,14 @@
}
-// Add an implicit constructor if no explicit constructor is present.
-void Parser::AddImplicitConstructor(ClassDesc* class_desc) {
- // The implicit constructor is unnamed, has no explicit parameter,
- // and contains a supercall in the initializer list.
- String& ctor_name = String::ZoneHandle(
- String::Concat(class_desc->class_name(), Symbols::Dot()));
+// Add an implicit constructor to the given class.
+void Parser::AddImplicitConstructor(const Class& cls) {
+ // The implicit constructor is unnamed, has no explicit parameter.
+ String& ctor_name = String::ZoneHandle(cls.Name());
+ ctor_name = String::Concat(ctor_name, Symbols::Dot());
ctor_name = Symbols::New(ctor_name);
- // The token position for the implicit constructor is the 'class'
- // keyword of the constructor's class.
+ // To indicate that this is an implicit constructor, we set the
+ // token position is the same as the token position of the class.
Function& ctor = Function::Handle(
Function::New(ctor_name,
RawFunction::kConstructor,
@@ -3292,22 +3330,23 @@
/* is_const = */ false,
/* is_abstract = */ false,
/* is_external = */ false,
- current_class(),
- class_desc->token_pos()));
+ cls,
+ cls.token_pos()));
ParamList params;
- // Add implicit 'this' parameter.
- ASSERT(current_class().raw() == ctor.Owner());
- params.AddReceiver(ReceiverType(TokenPos()));
+ // Add implicit 'this' parameter. We don't care about the specific type
+ // and just specify dynamic.
+ const Type& receiver_type = Type::Handle(Type::DynamicType());
+ params.AddReceiver(&receiver_type);
// Add implicit parameter for construction phase.
- params.AddFinalParameter(TokenPos(),
+ params.AddFinalParameter(cls.token_pos(),
&Symbols::PhaseParameter(),
&Type::ZoneHandle(Type::SmiType()));
AddFormalParamsToFunction(¶ms, ctor);
// The body of the constructor cannot modify the type of the constructed
// instance, which is passed in as the receiver.
- ctor.set_result_type(*((*params.parameters)[0].type));
- class_desc->AddFunction(ctor);
+ ctor.set_result_type(receiver_type);
+ cls.AddFunction(ctor);
}
@@ -3352,6 +3391,75 @@
}
+void Parser::ParseMixinTypedef(const GrowableObjectArray& pending_classes) {
+ TRACE_PARSER("ParseMixinTypedef");
+ const intptr_t classname_pos = TokenPos();
+ String& class_name = *ExpectUserDefinedTypeIdentifier("class name expected");
+ if (FLAG_trace_parser) {
+ OS::Print("toplevel parsing typedef class '%s'\n", class_name.ToCString());
+ }
+ const Object& obj = Object::Handle(library_.LookupLocalObject(class_name));
+ if (!obj.IsNull()) {
+ ErrorMsg(classname_pos, "'%s' is already defined",
+ class_name.ToCString());
+ }
+ const Class& mixin_application =
+ Class::Handle(Class::New(class_name, script_, classname_pos));
+ library_.AddClass(mixin_application);
+ set_current_class(mixin_application);
+ ParseTypeParameters(mixin_application);
+ ExpectToken(Token::kASSIGN);
+
+ if (CurrentToken() == Token::kABSTRACT) {
+ mixin_application.set_is_abstract();
+ ConsumeToken();
+ }
+
+ const intptr_t supertype_pos = TokenPos();
+ const AbstractType& type =
+ AbstractType::Handle(ParseType(ClassFinalizer::kTryResolve));
+ if (type.IsTypeParameter()) {
+ ErrorMsg(supertype_pos,
+ "class '%s' may not extend type parameter '%s'",
+ class_name.ToCString(),
+ String::Handle(type.UserVisibleName()).ToCString());
+ }
+ Type& mixin_super_type = Type::Handle();
+ mixin_super_type ^= type.raw();
+
+ if (CurrentToken() != Token::kWITH) {
+ ErrorMsg("mixin application 'with Type' expected");
+ }
+
+ Type& mixin_application_type = Type::Handle(ParseMixins(mixin_super_type));
+ // The result of ParseMixins() is a chain of super classes that is the
+ // result of the mixin composition 'S with M1, M2, ...'. The mixin
+ // application classes are anonymous (i.e. not registered in the current
+ // library). We steal the super type and mixin type from the bottom of
+ // the chain and add it to the named mixin application class. The bottom
+ // anonymous class in the chain is thrown away.
+ const Class& anon_mixin_app_class =
+ Class::Handle(mixin_application_type.type_class());
+ mixin_application.set_super_type(
+ Type::Handle(anon_mixin_app_class.super_type()));
+ mixin_application.set_mixin(Type::Handle(anon_mixin_app_class.mixin()));
+ const Array& interfaces = Array::Handle(anon_mixin_app_class.interfaces());
+ mixin_application.set_interfaces(interfaces);
+ AddImplicitConstructor(mixin_application);
+
+ if (CurrentToken() == Token::kIMPLEMENTS) {
+ Array& interfaces = Array::Handle();
+ const intptr_t interfaces_pos = TokenPos();
+ const Type& super_type = Type::Handle(mixin_application.super_type());
+ interfaces = ParseInterfaceList(super_type);
+ AddInterfaces(interfaces_pos, mixin_application, interfaces);
+ }
+
+ pending_classes.Add(mixin_application, Heap::kOld);
+ ExpectSemicolon();
+}
+
+
// Look ahead to detect if we are seeing ident [ TypeParameters ] "(".
// We need this lookahead to distinguish between the optional return type
// and the alias name of a function type alias.
@@ -3373,11 +3481,34 @@
}
-void Parser::ParseFunctionTypeAlias(
- const GrowableObjectArray& pending_classes) {
- TRACE_PARSER("ParseFunctionTypeAlias");
+// Look ahead to detect if we are seeing ident [ TypeParameters ] "=".
+// Token position remains unchanged.
+bool Parser::IsMixinTypedef() {
+ if (IsIdentifier() && (LookaheadToken(1) == Token::kASSIGN)) {
+ return true;
+ }
+ const intptr_t saved_pos = TokenPos();
+ bool is_mixin_def = false;
+ if (IsIdentifier() && (LookaheadToken(1) == Token::kLT)) {
+ ConsumeToken();
+ if (TryParseTypeParameter() && (CurrentToken() == Token::kASSIGN)) {
+ is_mixin_def = true;
+ }
+ }
+ SetPosition(saved_pos);
+ return is_mixin_def;
+}
+
+
+void Parser::ParseTypedef(const GrowableObjectArray& pending_classes) {
+ TRACE_PARSER("ParseTypedef");
ExpectToken(Token::kTYPEDEF);
+ if (IsMixinTypedef()) {
+ ParseMixinTypedef(pending_classes);
+ return;
+ }
+
// Parse the result type of the function type.
AbstractType& result_type = Type::Handle(Type::DynamicType());
if (CurrentToken() == Token::kVOID) {
@@ -3659,8 +3790,7 @@
// Parse and return an array of interface types.
RawArray* Parser::ParseInterfaceList(const Type& super_type) {
TRACE_PARSER("ParseInterfaceList");
- ASSERT((CurrentToken() == Token::kIMPLEMENTS) ||
- (CurrentToken() == Token::kEXTENDS));
+ ASSERT(CurrentToken() == Token::kIMPLEMENTS);
const GrowableObjectArray& interfaces =
GrowableObjectArray::Handle(GrowableObjectArray::New());
String& interface_name = String::Handle();
@@ -3674,6 +3804,9 @@
interface = ParseType(ClassFinalizer::kTryResolve);
interface_name = interface.UserVisibleName();
if (interface_name.Equals(super_type_name)) {
+ // TODO(hausner): I think this check is not necessary. There is
+ // no such restriction. If the check is removed, the 'super_type'
+ // parameter to this function can be eliminated.
ErrorMsg(interface_pos, "class may not extend and implement '%s'",
interface_name.ToCString());
}
@@ -3691,6 +3824,72 @@
}
+RawType* Parser::ParseMixins(const Type& super_type) {
+ TRACE_PARSER("ParseMixins");
+ ASSERT(CurrentToken() == Token::kWITH);
+
+ // TODO(hausner): Remove this restriction.
+ if (super_type.arguments() != AbstractTypeArguments::null()) {
+ ErrorMsg(super_type.token_pos(),
+ "super class of mixin may not have type arguments");
+ }
+
+ AbstractType& mixin_type = AbstractType::Handle();
+ AbstractTypeArguments& mixin_type_arguments =
+ AbstractTypeArguments::Handle();
+ Class& mixin_application = Class::Handle();
+ Type& mixin_application_type = Type::Handle();
+ Type& mixin_super_type = Type::Handle(super_type.raw());
+ Array& mixin_application_interfaces = Array::Handle();
+ const TypeArguments& no_type_arguments = TypeArguments::Handle();
+ do {
+ ConsumeToken();
+ const intptr_t mixin_pos = TokenPos();
+ mixin_type = ParseType(ClassFinalizer::kTryResolve);
+ if (mixin_type.IsTypeParameter()) {
+ ErrorMsg(mixin_pos,
+ "mixin type '%s' may not be a type parameter",
+ String::Handle(mixin_type.UserVisibleName()).ToCString());
+ }
+ // TODO(hausner): Remove this check once we handle mixins with type
+ // arguments.
+ mixin_type_arguments = mixin_type.arguments();
+ if (!mixin_type_arguments.IsNull()) {
+ ErrorMsg(mixin_pos,
+ "mixin type '%s' may not have type arguments",
+ String::Handle(mixin_type.UserVisibleName()).ToCString());
+ }
+
+ // The name of the mixin application class is a combination of
+ // the superclass and mixin class.
+ String& mixin_app_name = String::Handle();
+ mixin_app_name = mixin_super_type.Name();
+ mixin_app_name = String::Concat(mixin_app_name, Symbols::Ampersand());
+ mixin_app_name = String::Concat(mixin_app_name,
+ String::Handle(mixin_type.Name()));
+ mixin_app_name = Symbols::New(mixin_app_name);
+
+ mixin_application = Class::New(mixin_app_name, script_, mixin_pos);
+ mixin_application.set_super_type(mixin_super_type);
+ mixin_application.set_mixin(Type::Cast(mixin_type));
+ mixin_application.set_library(library_);
+ AddImplicitConstructor(mixin_application);
+ // Add the mixin type to the interfaces that the mixin application
+ // class implements. This is necessary so that type tests work.
+ mixin_application_interfaces = Array::New(1);
+ mixin_application_interfaces.SetAt(0, mixin_type);
+ mixin_application.set_interfaces(mixin_application_interfaces);
+
+ // TODO(hausner): Need to support type arguments.
+ mixin_application_type = Type::New(mixin_application,
+ no_type_arguments,
+ Scanner::kDummyTokenIndex);
+ mixin_super_type = mixin_application_type.raw();
+ } while (CurrentToken() == Token::kCOMMA);
+ return mixin_application_type.raw();
+}
+
+
// Add 'interface' to 'interface_list' if it is not already in the list.
// An error is reported if the interface conflicts with an interface already in
// the list with the same class and same type arguments.
@@ -4425,7 +4624,7 @@
} else if ((CurrentToken() == Token::kTYPEDEF) &&
(LookaheadToken(1) != Token::kLPAREN)) {
set_current_class(toplevel_class);
- ParseFunctionTypeAlias(pending_classes);
+ ParseTypedef(pending_classes);
} else if ((CurrentToken() == Token::kABSTRACT) &&
(LookaheadToken(1) == Token::kCLASS)) {
ParseClassDefinition(pending_classes);
@@ -8683,7 +8882,8 @@
}
factory_type_args = factory_type_args.Canonicalize();
ArgumentListNode* factory_param = new ArgumentListNode(literal_pos);
- ArrayNode* list = new ArrayNode(TokenPos(), type, element_list);
+ const LocalVariable& temp_local = *BuildArrayTempLocal(type_pos);
+ ArrayNode* list = new ArrayNode(TokenPos(), type, temp_local, element_list);
factory_param->Add(list);
return CreateConstructorCallNode(literal_pos,
factory_type_args,
@@ -8773,8 +8973,6 @@
ASSERT(map_type_arguments.IsNull() || (map_type_arguments.Length() == 2));
map_type_arguments ^= map_type_arguments.Canonicalize();
- // The kv_pair array is temporary and of element type dynamic. It is passed
- // to the factory to initialize a properly typed map.
GrowableArray<AstNode*> kv_pairs_list;
// Parse the map entries. Note: there may be an optional extra
// comma after the last entry.
@@ -8902,8 +9100,13 @@
}
factory_type_args = factory_type_args.Canonicalize();
ArgumentListNode* factory_param = new ArgumentListNode(literal_pos);
+ // The kv_pair array is temporary and of element type dynamic. It is passed
+ // to the factory to initialize a properly typed map.
ArrayNode* kv_pairs = new ArrayNode(
- TokenPos(), Type::ZoneHandle(Type::ArrayType()), kv_pairs_list);
+ TokenPos(),
+ Type::ZoneHandle(Type::ArrayType()),
+ *BuildArrayTempLocal(type_pos),
+ kv_pairs_list);
factory_param->Add(kv_pairs);
return CreateConstructorCallNode(literal_pos,
factory_type_args,
@@ -9279,7 +9482,10 @@
} else {
ArgumentListNode* interpolate_arg = new ArgumentListNode(TokenPos());
ArrayNode* values = new ArrayNode(
- TokenPos(), Type::ZoneHandle(Type::ArrayType()), values_list);
+ TokenPos(),
+ Type::ZoneHandle(Type::ArrayType()),
+ *BuildArrayTempLocal(TokenPos()),
+ values_list);
interpolate_arg->Add(values);
primary = MakeStaticCall(Symbols::StringBase(),
PrivateCoreLibName(Symbols::Interpolate()),
@@ -9444,6 +9650,14 @@
ErrorMsg("class '%s' does not have a superclass",
String::Handle(current_class().Name()).ToCString());
}
+ if (current_class().mixin() != Type::null()) {
+ const Type& mixin_type = Type::Handle(current_class().mixin());
+ if (mixin_type.type_class() == current_function().origin()) {
+ ErrorMsg("class '%s' may not use super "
+ "because it is used as mixin class",
+ String::Handle(current_class().Name()).ToCString());
+ }
+ }
ConsumeToken();
if (CurrentToken() == Token::kPERIOD) {
ConsumeToken();
diff --git a/runtime/vm/parser.h b/runtime/vm/parser.h
index 6ca97c4..f0ca6d5 100644
--- a/runtime/vm/parser.h
+++ b/runtime/vm/parser.h
@@ -40,6 +40,7 @@
saved_current_context_var_(NULL),
saved_entry_context_var_(NULL),
expression_temp_var_(NULL),
+ array_literal_var_(NULL),
first_parameter_index_(0),
first_stack_local_index_(0),
num_copied_params_(0),
@@ -102,6 +103,17 @@
}
static LocalVariable* CreateExpressionTempVar(intptr_t token_pos);
+ void set_array_literal_var(LocalVariable* local) {
+ ASSERT((local != NULL) && (array_literal_var_ == NULL));
+ array_literal_var_ = local;
+ }
+ LocalVariable* array_literal_var() const {
+ ASSERT(array_literal_var_ != NULL);
+ return array_literal_var_;
+ }
+
+ static LocalVariable* CreateArrayLiteralVar(intptr_t token_pos);
+
int first_parameter_index() const { return first_parameter_index_; }
int first_stack_local_index() const { return first_stack_local_index_; }
int num_copied_params() const { return num_copied_params_; }
@@ -117,6 +129,9 @@
LocalVariable* saved_current_context_var_;
LocalVariable* saved_entry_context_var_;
LocalVariable* expression_temp_var_;
+ // TODO(hausner): Remove once ArrayNode creation is removed from flow
+ // graph builder.
+ LocalVariable* array_literal_var_;
int first_parameter_index_;
int first_stack_local_index_;
@@ -313,7 +328,8 @@
// Support for parsing of scripts.
void ParseTopLevel();
void ParseClassDefinition(const GrowableObjectArray& pending_classes);
- void ParseFunctionTypeAlias(const GrowableObjectArray& pending_classes);
+ void ParseMixinTypedef(const GrowableObjectArray& pending_classes);
+ void ParseTypedef(const GrowableObjectArray& pending_classes);
void ParseTopLevelVariable(TopLevel* top_level);
void ParseTopLevelFunction(TopLevel* top_level);
void ParseTopLevelAccessor(TopLevel* top_level);
@@ -351,7 +367,7 @@
void ParseFormalParameterList(bool allow_explicit_default_values,
ParamList* params);
void CheckConstFieldsInitialized(const Class& cls);
- void AddImplicitConstructor(ClassDesc* members);
+ void AddImplicitConstructor(const Class& cls);
void CheckConstructors(ClassDesc* members);
void ParseInitializedInstanceFields(
const Class& cls,
@@ -372,6 +388,7 @@
GrowableArray<Field*>* initialized_fields);
String& ParseNativeDeclaration();
RawArray* ParseInterfaceList(const Type& super_type);
+ RawType* ParseMixins(const Type& super_type);
void AddInterfaceIfUnique(intptr_t interfaces_pos,
const GrowableObjectArray& interface_list,
const AbstractType& interface);
@@ -474,6 +491,7 @@
bool IsIdentifier();
bool IsSimpleLiteral(const AbstractType& type, Instance* value);
bool IsFunctionTypeAliasName();
+ bool IsMixinTypedef();
bool TryParseTypeParameter();
bool TryParseOptionalType();
bool TryParseReturnType();
@@ -612,6 +630,7 @@
const Function& constructor,
ArgumentListNode* arguments);
+ LocalVariable* BuildArrayTempLocal(intptr_t token_pos);
const Script& script_;
TokenStream::Iterator tokens_iterator_;
@@ -642,6 +661,9 @@
Class& current_class_;
// The current library (and thus class dictionary) used to resolve names.
+ // When parsing a function, this is the library in which the function
+ // is defined. This can be the library in which the current_class_ is
+ // defined, or the library of a mixin class where the function originates.
const Library& library_;
// List of try blocks seen so far, this is used to generate inlined finally
diff --git a/runtime/vm/raw_object.h b/runtime/vm/raw_object.h
index ac66f62..9dd8faa 100644
--- a/runtime/vm/raw_object.h
+++ b/runtime/vm/raw_object.h
@@ -433,6 +433,7 @@
RawLibrary* library_;
RawTypeArguments* type_parameters_; // Array of TypeParameter.
RawType* super_type_;
+ RawType* mixin_;
RawFunction* signature_function_; // Associated function for signature class.
RawArray* constants_; // Canonicalized values of this class.
RawArray* canonical_types_; // Canonicalized types of this class.
@@ -555,7 +556,8 @@
RawObject** from() { return reinterpret_cast<RawObject**>(&ptr()->name_); }
RawString* name_;
- RawObject* owner_; // Class or patch class where this function was defined.
+ RawObject* owner_; // Class or patch class or mixin class
+ // where this function is defined.
RawAbstractType* result_type_;
RawArray* parameter_types_;
RawArray* parameter_names_;
@@ -619,7 +621,8 @@
RawObject** from() { return reinterpret_cast<RawObject**>(&ptr()->name_); }
RawString* name_;
- RawClass* owner_;
+ RawObject* owner_; // Class or patch class or mixin class
+ // where this field is defined.
RawAbstractType* type_;
RawInstance* value_; // Offset in words for instance and value for static.
RawObject** to() { return reinterpret_cast<RawObject**>(&ptr()->value_); }
diff --git a/runtime/vm/symbols.h b/runtime/vm/symbols.h
index caec906..0e6e274 100644
--- a/runtime/vm/symbols.h
+++ b/runtime/vm/symbols.h
@@ -59,6 +59,7 @@
V(SavedTryContextVar, ":saved_try_context_var") \
V(ExceptionVar, ":exception_var") \
V(StacktraceVar, ":stacktrace_var") \
+ V(ArrayLiteralVar, ":array_literal_var") \
V(ListLiteralElement, "list literal element") \
V(ForInIter, ":for-in-iter") \
V(Library, "library") \
@@ -281,6 +282,9 @@
static const String& Dash() {
return *(symbol_handles_[kNullCharId + '-']);
}
+ static const String& Ampersand() {
+ return *(symbol_handles_[kNullCharId + '&']);
+ }
// Access methods for symbol handles stored in the vm isolate.
#define DEFINE_SYMBOL_HANDLE_ACCESSOR(symbol, literal) \
diff --git a/runtime/vm/token.h b/runtime/vm/token.h
index ee57ca9..aebd94a 100644
--- a/runtime/vm/token.h
+++ b/runtime/vm/token.h
@@ -185,7 +185,8 @@
KW(kTYPEDEF, "typedef", 0, kPseudoKeyword) \
KW(kVAR, "var", 0, kKeyword) \
KW(kVOID, "void", 0, kKeyword) \
- KW(kWHILE, "while", 0, kKeyword) /* == kLastKeyword */
+ KW(kWHILE, "while", 0, kKeyword) \
+ KW(kWITH, "with", 0, kKeyword) /* == kLastKeyword */
class String;
@@ -207,8 +208,8 @@
};
static const Kind kFirstKeyword = kABSTRACT;
- static const Kind kLastKeyword = kWHILE;
- static const int numKeywords = kWHILE - kABSTRACT + 1;
+ static const Kind kLastKeyword = kWITH;
+ static const int numKeywords = kLastKeyword - kFirstKeyword + 1;
static bool IsAssignmentOperator(Kind tok) {
return kASSIGN <= tok && tok <= kASSIGN_MOD;
diff --git a/runtime/vm/vm_sources.gypi b/runtime/vm/vm_sources.gypi
index 1f53461..2f70b1a 100644
--- a/runtime/vm/vm_sources.gypi
+++ b/runtime/vm/vm_sources.gypi
@@ -155,6 +155,8 @@
'flow_graph_inliner.h',
'flow_graph_optimizer.cc',
'flow_graph_optimizer.h',
+ 'flow_graph_type_propagator.cc',
+ 'flow_graph_type_propagator.h',
'freelist.cc',
'freelist.h',
'freelist_test.cc',
diff --git a/sdk/lib/_collection_dev/iterable.dart b/sdk/lib/_collection_dev/iterable.dart
index ac490e1..676ad73 100644
--- a/sdk/lib/_collection_dev/iterable.dart
+++ b/sdk/lib/_collection_dev/iterable.dart
@@ -4,6 +4,317 @@
part of dart._collection.dev;
+
+/**
+ * An [Iterable] for classes that have efficient [length] and [elementAt].
+ *
+ * All other methods are implemented in terms of [length] and [elementAt],
+ * including [iterator].
+ */
+abstract class ListIterable<E> extends Iterable<E> {
+ int get length;
+ E elementAt(int i);
+
+ Iterator<E> get iterator => new ListIterableIterator<E>(this);
+
+ void forEach(void action(E element)) {
+ int length = this.length;
+ for (int i = 0; i < length; i++) {
+ action(elementAt(i));
+ if (length != this.length) {
+ throw new ConcurrentModificationError(this);
+ }
+ }
+ }
+
+ bool get isEmpty => length != 0;
+
+ E get first {
+ if (length == 0) throw new StateError("No elements");
+ return elementAt(0);
+ }
+
+ E get last {
+ if (length == 0) throw new StateError("No elements");
+ return elementAt(length - 1);
+ }
+
+ E get single {
+ if (length == 0) throw new StateError("No elements");
+ if (length > 1) throw new StateError("Too many elements");
+ return elementAt(0);
+ }
+
+ bool contains(E element) {
+ int length = this.length;
+ for (int i = 0; i < length; i++) {
+ if (elementAt(i) == element) return true;
+ if (length != this.length) {
+ throw new ConcurrentModificationError(this);
+ }
+ }
+ return false;
+ }
+
+ bool every(bool test(E element)) {
+ int length = this.length;
+ for (int i = 0; i < length; i++) {
+ if (!test(elementAt(i))) return false;
+ if (length != this.length) {
+ throw new ConcurrentModificationError(this);
+ }
+ }
+ return true;
+ }
+
+ bool any(bool test(E element)) {
+ int length = this.length;
+ for (int i = 0; i < length; i++) {
+ if (test(elementAt(i))) return true;
+ if (length != this.length) {
+ throw new ConcurrentModificationError(this);
+ }
+ }
+ return false;
+ }
+
+ E firstMatching(bool test(E element), { E orElse() }) {
+ int length = this.length;
+ for (int i = 0; i < length; i++) {
+ E element = elementAt(i);
+ if (test(element)) return element;
+ if (length != this.length) {
+ throw new ConcurrentModificationError(this);
+ }
+ }
+ if (orElse != null) return orElse();
+ throw new StateError("No matching element");
+ }
+
+ E lastMatching(bool test(E element), { E orElse() }) {
+ int length = this.length;
+ for (int i = length - 1; i >= 0; i++) {
+ E element = elementAt(i);
+ if (test(element)) return element;
+ if (length != this.length) {
+ throw new ConcurrentModificationError(this);
+ }
+ }
+ if (orElse != null) return orElse();
+ throw new StateError("No matching element");
+ }
+
+ E singleMatching(bool test(E element)) {
+ int length = this.length;
+ E match = null;
+ bool matchFound = false;
+ for (int i = 0; i < length; i++) {
+ E element = elementAt(i);
+ if (test(element)) {
+ if (matchFound) {
+ throw new StateError("More than one matching element");
+ }
+ matchFound = true;
+ match = element;
+ }
+ if (length != this.length) {
+ throw new ConcurrentModificationError(this);
+ }
+ }
+ if (matchFound) return match;
+ throw new StateError("No matching element");
+ }
+
+ E min([int compare(E a, E b)]) {
+ if (length == 0) return null;
+ if (compare == null) {
+ var defaultCompare = Comparable.compare;
+ compare = defaultCompare;
+ }
+ E min = elementAt(0);
+ int length = this.length;
+ for (int i = 1; i < length; i++) {
+ E element = elementAt(i);
+ if (compare(min, element) > 0) {
+ min = element;
+ }
+ if (length != this.length) {
+ throw new ConcurrentModificationError(this);
+ }
+ }
+ return min;
+ }
+
+ E max([int compare(E a, E b)]) {
+ if (length == 0) return null;
+ if (compare == null) {
+ var defaultCompare = Comparable.compare;
+ compare = defaultCompare;
+ }
+ E max = elementAt(0);
+ int length = this.length;
+ for (int i = 1; i < length; i++) {
+ E element = elementAt(i);
+ if (compare(max, element) < 0) {
+ max = element;
+ }
+ if (length != this.length) {
+ throw new ConcurrentModificationError(this);
+ }
+ }
+ return max;
+ }
+
+ String join([String separator]) {
+ int length = this.length;
+ if (separator != null && !separator.isEmpty) {
+ if (length == 0) return "";
+ String first = "${elementAt(0)}";
+ if (length != this.length) {
+ throw new ConcurrentModificationError(this);
+ }
+ StringBuffer buffer = new StringBuffer(first);
+ for (int i = 1; i < length; i++) {
+ buffer.add(separator);
+ buffer.add("${elementAt(i)}");
+ if (length != this.length) {
+ throw new ConcurrentModificationError(this);
+ }
+ }
+ return buffer.toString();
+ } else {
+ StringBuffer buffer = new StringBuffer();
+ for (int i = 0; i < length; i++) {
+ buffer.add("${elementAt(i)}");
+ if (length != this.length) {
+ throw new ConcurrentModificationError(this);
+ }
+ }
+ return buffer.toString();
+ }
+ }
+
+ Iterable<E> where(bool test(E element)) => super.where(test);
+
+ Iterable map(f(E element)) => new MappedIterable(this, f);
+
+ Iterable mappedBy(f(E element)) => super.mappedBy(f);
+
+ reduce(var initialValue, combine(var previousValue, E element)) {
+ var value = initialValue;
+ int length = this.length;
+ for (int i = 0; i < length; i++) {
+ value = reduce(value, elementAt(i));
+ if (length != this.length) {
+ throw new ConcurrentModificationError(this);
+ }
+ }
+ return value;
+ }
+
+ Iterable<E> skip(int count) => new SubListIterable(this, count, null);
+
+ Iterable<E> skipWhile(bool test(E element)) => super.skipWhile(test);
+
+ Iterable<E> take(int count) => new SubListIterable(this, 0, count);
+
+ Iterable<E> takeWhile(bool test(E element)) => super.takeWhile(test);
+
+ List<E> toList() {
+ List<E> result = new List(length);
+ for (int i = 0; i < length; i++) {
+ result[i] = elementAt(i);
+ }
+ return result;
+ }
+
+ Set<E> toSet() {
+ Set<E> result = new Set<E>();
+ for (int i = 0; i < length; i++) {
+ result.add(elementAt(i));
+ }
+ return result;
+ }
+}
+
+abstract class SubListIterable<E> extends ListIterable<E> {
+ final Iterable<E> _iterable;
+ final int _start;
+ /** If null, represents the length of the iterable. */
+ final int _endOrLength;
+
+ SubListIterable(this._iterable, this._start, this._endOrLength);
+
+ int get _endIndex {
+ int length = _iterable.length;
+ if (_endOrLength == null || _endOrLength > length) return length;
+ return _endOrLength;
+ }
+
+ int get _startIndex {
+ int length = _iterable.length;
+ if (_start > length) return length;
+ return _start;
+ }
+
+ int get length {
+ int length = _iterable.length;
+ if (_start >= length) return 0;
+ if (_endOrLength == null || _endOrLength >= length) {
+ return length - _start;
+ }
+ return _endOrLength - _start;
+ }
+
+ E elementAt(int index) {
+ int realIndex = _startIndex + index;
+ if (index < 0 || realIndex >= _endIndex) {
+ throw new RangeError.range(index, 0, length);
+ }
+ return _iterable.elementAt(realIndex);
+ }
+
+ Iterable<E> skip(int count) {
+ if (count < 0) throw new ArgumentError(count);
+ return new SubListIterable(_iterable, _start + count, _endOrLength);
+ }
+
+ Iterable<E> take(int count) {
+ if (count < 0) throw new ArgumentError(count);
+ if (_endOrLength == null) {
+ return new SubListIterable(_iterable, _start, _start + count);
+ } else {
+ newEnd = _start + count;
+ if (_endOrLength < newEnd) return this;
+ return new SubListIterable(_iterable, _start, newEnd);
+ }
+ }
+}
+
+class ListIterableIterator<E> implements Iterator<E> {
+ final Iterable<E> _iterable;
+ final int _length;
+ int _index;
+ E _current;
+ ListIterableIterator(Iterable<E> iterable)
+ : _iterable = iterable, _length = iterable.length, _index = 0;
+
+ E get current => _current;
+
+ bool moveNext() {
+ if (_length != _iterable.length) {
+ throw new ConcurrentModificationError(_iterable);
+ }
+ if (_index == _length) {
+ _current = null;
+ return false;
+ }
+ _current = _iterable.elementAt(_index);
+ _index++;
+ return true;
+ }
+}
+
typedef T _Transformation<S, T>(S value);
class MappedIterable<S, T> extends Iterable<T> {
diff --git a/sdk/lib/_internal/compiler/implementation/apiimpl.dart b/sdk/lib/_internal/compiler/implementation/apiimpl.dart
index 663e003..c9759f3 100644
--- a/sdk/lib/_internal/compiler/implementation/apiimpl.dart
+++ b/sdk/lib/_internal/compiler/implementation/apiimpl.dart
@@ -134,7 +134,7 @@
* Reads the script designated by [readableUri].
*/
leg.Script readScript(Uri readableUri, [tree.Node node]) {
- if (!readableUri.isAbsolute()) {
+ if (!readableUri.isAbsolute) {
internalError('Relative uri $readableUri provided to readScript(Uri)',
node: node);
}
diff --git a/sdk/lib/_internal/compiler/implementation/compiler.dart b/sdk/lib/_internal/compiler/implementation/compiler.dart
index 71c3860..adf2a77 100644
--- a/sdk/lib/_internal/compiler/implementation/compiler.dart
+++ b/sdk/lib/_internal/compiler/implementation/compiler.dart
@@ -650,13 +650,13 @@
if (analyzeOnly) return;
assert(main != null);
- log('Inferring types...');
- typesTask.onResolutionComplete(main);
-
// TODO(ahe): Remove this line. Eventually, enqueuer.resolution
// should know this.
world.populate();
+ log('Inferring types...');
+ typesTask.onResolutionComplete(main);
+
log('Compiling...');
phase = PHASE_COMPILING;
// TODO(johnniwinther): Move these to [CodegenEnqueuer].
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart
index 6a3b000..45a6523 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/backend.dart
@@ -360,10 +360,9 @@
classMembers[enclosingClass].add(element);
processElement(element, elementAst);
} else {
- if (!element.isTopLevel()) {
- compiler.cancel('Cannot process $element', element: element);
+ if (element.isTopLevel()) {
+ addTopLevel(element, elementAst);
}
- addTopLevel(element, elementAst);
}
});
diff --git a/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart b/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart
index d184663..669aa02 100644
--- a/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart
+++ b/sdk/lib/_internal/compiler/implementation/dart_backend/placeholder_collector.dart
@@ -579,6 +579,12 @@
}
}
+ visitNamedMixinApplication(NamedMixinApplication node) {
+ ClassElement classElement = currentElement;
+ makeElementPlaceholder(node.name, classElement);
+ node.visitChildren(this);
+ }
+
bool tryResolveAndCollectTypeVariable(
TypeDeclarationElement typeDeclaration, Identifier name) {
// Hack for case when interface and default class are in different
diff --git a/sdk/lib/_internal/compiler/implementation/elements/elements.dart b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
index 0a06ad4..312b35b 100644
--- a/sdk/lib/_internal/compiler/implementation/elements/elements.dart
+++ b/sdk/lib/_internal/compiler/implementation/elements/elements.dart
@@ -612,6 +612,13 @@
void set type(DartType value);
}
+/**
+ * A synthetic element which holds a getter and/or a setter.
+ *
+ * This element unifies handling of fields and getters/setters. When
+ * looking at code like "foo.x", we don't have to look for both a
+ * field named "x", a getter named "x", and a setter named "x=".
+ */
abstract class AbstractFieldElement extends Element {
FunctionElement get getter;
FunctionElement get setter;
diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_number.dart b/sdk/lib/_internal/compiler/implementation/lib/js_number.dart
index fa5677f..c15fcae 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/js_number.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/js_number.dart
@@ -235,22 +235,22 @@
bool operator <(num other) {
if (other is !num) throw new ArgumentError(other);
- return JS('num', '# < #', this, other);
+ return JS('bool', '# < #', this, other);
}
bool operator >(num other) {
if (other is !num) throw new ArgumentError(other);
- return JS('num', '# > #', this, other);
+ return JS('bool', '# > #', this, other);
}
bool operator <=(num other) {
if (other is !num) throw new ArgumentError(other);
- return JS('num', '# <= #', this, other);
+ return JS('bool', '# <= #', this, other);
}
bool operator >=(num other) {
if (other is !num) throw new ArgumentError(other);
- return JS('num', '# >= #', this, other);
+ return JS('bool', '# >= #', this, other);
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/lib/js_string.dart b/sdk/lib/_internal/compiler/implementation/lib/js_string.dart
index dcb5b4e..6d81f32 100644
--- a/sdk/lib/_internal/compiler/implementation/lib/js_string.dart
+++ b/sdk/lib/_internal/compiler/implementation/lib/js_string.dart
@@ -149,9 +149,7 @@
return result;
}
- Iterable<int> get codeUnits {
- throw new UnimplementedError("String.codeUnits");
- }
+ Iterable<int> get codeUnits => new CodeUnits(this);
Runes get runes => new Runes(this);
diff --git a/sdk/lib/_internal/compiler/implementation/library_loader.dart b/sdk/lib/_internal/compiler/implementation/library_loader.dart
index 074cece..e5854b5 100644
--- a/sdk/lib/_internal/compiler/implementation/library_loader.dart
+++ b/sdk/lib/_internal/compiler/implementation/library_loader.dart
@@ -358,7 +358,7 @@
* used as is, any URI resolution should be done beforehand.
*/
void scanPart(Part part, Uri resolvedUri, LibraryElement library) {
- if (!resolvedUri.isAbsolute()) throw new ArgumentError(resolvedUri);
+ if (!resolvedUri.isAbsolute) throw new ArgumentError(resolvedUri);
Uri readableUri = compiler.translateResolvedUri(library, resolvedUri, part);
Script sourceScript = compiler.readScript(readableUri, part);
CompilationUnitElement unit =
diff --git a/sdk/lib/_internal/compiler/implementation/resolution/members.dart b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
index e62aa70..c13a959 100644
--- a/sdk/lib/_internal/compiler/implementation/resolution/members.dart
+++ b/sdk/lib/_internal/compiler/implementation/resolution/members.dart
@@ -1837,6 +1837,9 @@
FunctionElement function = new FunctionElementX.node(
name, node, ElementKind.FUNCTION, Modifiers.EMPTY,
enclosingElement);
+ // [function] and its enclosing method share the same
+ // [TreeElementMapping].
+ compiler.enqueuer.resolution.resolvedElements[function] = mapping;
Scope oldScope = scope; // The scope is modified by [setupFunction].
setupFunction(node, function);
defineElement(node, function, doAddToScope: node.name != null);
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
index 8b44913..916b4db 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/builder.dart
@@ -296,8 +296,7 @@
builder.parameters[parameterElement] = parameter;
directLocals[parameterElement] = parameter;
parameter.guaranteedType =
- builder.mapInferredType(
- typesTask.getGuaranteedTypeOfElement(parameterElement));
+ builder.getGuaranteedTypeOfElement(parameterElement);
});
}
@@ -2586,24 +2585,12 @@
HInstruction createForeignArray(String code, inputs) {
return createForeign(code, HType.READABLE_ARRAY, inputs);
}
- HInstruction typeInfo;
-
- /// Helper to create an instruction that contains the runtime value of
- /// the type variable [variable].
- HInstruction getTypeArgument(TypeVariableType variable) {
- if (typeInfo == null) {
- typeInfo = getRuntimeTypeInfo(localsHandler.readThis());
- }
- int intIndex = RuntimeTypeInformation.getTypeVariableIndex(variable);
- HInstruction index = graph.addConstantInt(intIndex, constantSystem);
- return createForeignArray('#[#]', <HInstruction>[typeInfo, index]);
- }
// Compute the representation of the type arguments, including access
// to the runtime type information for type variables as instructions.
HInstruction representations;
if (type.element.isTypeVariable()) {
- return <HInstruction>[getTypeArgument(type)];
+ return <HInstruction>[addTypeVariableReference(type)];
} else {
assert(type.element.isClass());
List<HInstruction> arguments = <HInstruction>[];
@@ -2611,8 +2598,7 @@
for (DartType argument in interface.typeArguments) {
List<HInstruction> inputs = <HInstruction>[];
String template = rti.getTypeRepresentation(argument, (variable) {
- HInstruction runtimeType = getTypeArgument(variable);
- add(runtimeType);
+ HInstruction runtimeType = addTypeVariableReference(variable);
inputs.add(runtimeType);
});
HInstruction representation = createForeignArray(template, inputs);
@@ -3151,6 +3137,49 @@
}
/**
+ * Helper to create an instruction that gets the value of a type variable.
+ */
+ HInstruction addTypeVariableReference(TypeVariableType type) {
+ Element member = currentElement;
+ if (member.enclosingElement.isClosure()) {
+ ClosureClassElement closureClass = member.enclosingElement;
+ member = closureClass.methodElement;
+ member = member.getOutermostEnclosingMemberOrTopLevel();
+ }
+ if (member.isFactoryConstructor()) {
+ // The type variable is stored in a parameter of the method.
+ return localsHandler.readLocal(type.element);
+ } else if (member.isInstanceMember() ||
+ member.isGenerativeConstructor()) {
+ // The type variable is stored on the object. Generate code to extract
+ // the type arguments from the object, substitute them as an instance
+ // of the type we are testing against (if necessary), and extract the
+ // type argument by the index of the variable in the list of type
+ // variables for that class.
+ int index = RuntimeTypeInformation.getTypeVariableIndex(type);
+ HInstruction thisObject = localsHandler.readThis();
+ String substitutionNameString =
+ backend.namer.substitutionName(member.getEnclosingClass());
+ HInstruction substitutionName = graph.addConstantString(
+ new LiteralDartString(substitutionNameString), null, constantSystem);
+ HInstruction substitution = createForeign('#[#]', HType.UNKNOWN,
+ <HInstruction>[thisObject, substitutionName]);
+ add(substitution);
+ pushInvokeHelper3(backend.getGetRuntimeTypeArgument(),
+ thisObject,
+ substitution,
+ graph.addConstantInt(index, constantSystem),
+ HType.UNKNOWN);
+ return pop();
+ } else {
+ // TODO(ngeoffray): Match the VM behavior and throw an
+ // exception at runtime.
+ compiler.cancel('Unimplemented unresolved type variable',
+ element: type.element);
+ }
+ }
+
+ /**
* Documentation wanted -- johnniwinther
*
* Invariant: [argument] must not be malformed in checked mode.
@@ -3164,54 +3193,12 @@
return graph.addConstantNull(constantSystem);
}
- // The inputs are shared between invocations of the helper.
List<HInstruction> inputs = <HInstruction>[];
- /**
- * Helper to create an instruction that gets the value of a type variable.
- */
- String addTypeVariableReference(TypeVariableType type) {
- Element member = currentElement;
- if (member.enclosingElement.isClosure()) {
- ClosureClassElement closureClass = member.enclosingElement;
- member = closureClass.methodElement;
- member = member.getOutermostEnclosingMemberOrTopLevel();
- }
- if (member.isFactoryConstructor()) {
- // The type variable is stored in a parameter of the method.
- inputs.add(localsHandler.readLocal(type.element));
- } else if (member.isInstanceMember() ||
- member.isGenerativeConstructor()) {
- // The type variable is stored on the object. Generate code to extract
- // the type arguments from the object, substitute them as an instance
- // of the type we are testing against (if necessary), and extract the
- // type argument by the index of the variable in the list of type
- // variables for that class.
- int index = RuntimeTypeInformation.getTypeVariableIndex(type);
- HInstruction thisObject = localsHandler.readThis();
- String substitutionNameString =
- backend.namer.substitutionName(member.getEnclosingClass());
- HInstruction substitutionName = graph.addConstantString(
- new LiteralDartString(substitutionNameString), null, constantSystem);
- HInstruction substitution = createForeign('#[#]', HType.UNKNOWN,
- <HInstruction>[thisObject, substitutionName]);
- add(substitution);
- pushInvokeHelper3(backend.getGetRuntimeTypeArgument(),
- thisObject,
- substitution,
- graph.addConstantInt(index, constantSystem),
- HType.UNKNOWN);
- inputs.add(pop());
- } else {
- // TODO(ngeoffray): Match the VM behavior and throw an
- // exception at runtime.
- compiler.cancel('Unimplemented unresolved type variable',
- node: currentNode);
- }
- }
+ String template = rti.getTypeRepresentation(argument, (variable) {
+ inputs.add(addTypeVariableReference(variable));
+ });
- String template = rti.getTypeRepresentation(argument,
- addTypeVariableReference);
HInstruction result = createForeign(template, HType.STRING, inputs);
add(result);
return result;
@@ -3376,11 +3363,14 @@
}
HInvokeStatic instruction = new HInvokeStatic(inputs, HType.UNKNOWN);
- // TODO(ngeoffray): Only do this if knowing the return type is
- // useful.
- HType returnType =
- builder.backend.optimisticReturnTypesWithRecompilationOnTypeChange(
- currentElement, element);
+ HType returnType = getGuaranteedTypeOfElement(element);
+ if (returnType.isUnknown()) {
+ // TODO(ngeoffray): Only do this if knowing the return type is
+ // useful.
+ returnType =
+ builder.backend.optimisticReturnTypesWithRecompilationOnTypeChange(
+ currentElement, element);
+ }
if (returnType != null) instruction.guaranteedType = returnType;
pushWithPosition(instruction, node);
} else {
@@ -3572,7 +3562,14 @@
}
inputs.add(receiver);
inputs.addAll(arguments);
- return new HInvokeDynamicMethod(selector, inputs, isIntercepted);
+ HInstruction invoke = new HInvokeDynamicMethod(
+ selector, inputs, isIntercepted);
+ HType returnType = mapInferredType(
+ compiler.typesTask.getGuaranteedTypeOfNode(work.element, node));
+ if (returnType != null) {
+ invoke.guaranteedType = returnType;
+ }
+ return invoke;
}
visitSendSet(SendSet node) {
@@ -4656,10 +4653,15 @@
for (BaseType baseType in concreteType.baseTypes) {
ssaType = ssaType.union(mapBaseType(baseType), compiler);
}
- assert(!ssaType.isConflicting());
+ if (ssaType.isConflicting()) return HType.UNKNOWN;
return ssaType;
}
+ HType getGuaranteedTypeOfElement(Element element) {
+ return mapInferredType(
+ compiler.typesTask.getGuaranteedTypeOfElement(element));
+ }
+
// [type] is either an instance of [DartType] or special objects
// like [native.SpecialType.JsObject], or [native.SpecialType.JsArray].
HType mapNativeType(type) {
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
index d9407c0..def1a12 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/codegen.dart
@@ -1528,6 +1528,30 @@
} else if (target == backend.jsStringConcat) {
push(new js.Binary('+', object, arguments[0]), node);
return;
+ } else if (target.isNative()
+ && !compiler.enableTypeAssertions
+ && target.isFunction()) {
+ // Enable direct calls to a native method only if we don't
+ // run in checked mode, where the Dart version may have
+ // type annotations on parameters and return type that it
+ // should check.
+ // Also check that the parameters are not functions: it's
+ // the callee that will translate them to JS functions.
+ // TODO(ngeoffray): There are some cases where we could
+ // still inline in checked mode if we know the arguments
+ // have the right type. And we could do the closure
+ // conversion as well as the return type annotation check.
+ bool canInlineNativeCall = true;
+ FunctionElement function = target;
+ function.computeSignature(compiler).forEachParameter((Element element) {
+ DartType type = element.computeType(compiler).unalias(compiler);
+ if (type is FunctionType) {
+ canInlineNativeCall = false;
+ }
+ });
+ if (canInlineNativeCall) {
+ methodName = target.fixedBackendName();
+ }
}
}
}
@@ -1617,6 +1641,7 @@
if (target != null) {
// If we know we're calling a specific method, register that
// method only.
+ assert(selector.typeKind != TypedSelectorKind.UNKNOWN);
world.registerDynamicInvocationOf(target, selector);
} else {
SourceString name = node.selector.name;
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
index 5d7a29c..4d83538 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/nodes.dart
@@ -1369,7 +1369,8 @@
}
HType computeTypeFromInputTypes(HTypeMap types, Compiler compiler) {
- return specializer.computeTypeFromInputTypes(this, types, compiler);
+ HType type = specializer.computeTypeFromInputTypes(this, types, compiler);
+ return type.isUnknown() ? guaranteedType : type;
}
}
@@ -1671,6 +1672,9 @@
abstract class HBinaryBitOp extends HBinaryArithmetic {
HBinaryBitOp(HInstruction left, HInstruction right) : super(left, right);
HType get guaranteedType => HType.INTEGER;
+ HType computeTypeFromInputTypes(HTypeMap types, Compiler compiler) {
+ return guaranteedType;
+ }
}
class HShiftLeft extends HBinaryBitOp {
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
index 0166ac0..1b2ae05 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/optimize.dart
@@ -58,7 +58,7 @@
// Previous optimizations may have generated new
// opportunities for constant folding.
new SsaConstantFolder(constantSystem, backend, work, types),
- new SsaSimplifyInterceptors(constantSystem),
+ new SsaSimplifyInterceptors(constantSystem, types),
new SsaDeadCodeEliminator(types)];
runPhases(graph, phases);
if (!speculative) {
@@ -150,8 +150,10 @@
// If we can replace [instruction] with [replacement], then
// [replacement]'s type can be narrowed.
- types[replacement] =
- types[replacement].intersection(types[instruction], compiler);
+ types[replacement] = types[replacement].intersection(
+ types[instruction], compiler);
+ replacement.guaranteedType = replacement.guaranteedType.intersection(
+ instruction.guaranteedType, compiler);
// If the replacement instruction does not know its
// source element, use the source element of the
@@ -258,9 +260,6 @@
}
HInstruction handleInterceptorCall(HInvokeDynamic node) {
- // We only optimize for intercepted method calls in this method.
- Selector selector = node.selector;
-
// Try constant folding the instruction.
Operation operation = node.specializer.operation(constantSystem);
if (operation != null) {
@@ -275,17 +274,22 @@
node.specializer.tryConvertToBuiltin(node, types);
if (instruction != null) return instruction;
- // Check if this call does not need to be intercepted.
- HInstruction input = node.inputs[1];
- HType type = types[input];
+ Selector selector = node.selector;
var interceptor = node.inputs[0];
- if (interceptor.isConstant() && selector.isCall()) {
+ // If the intercepted call is through a constant interceptor, we
+ // know which element to call.
+ if (node is !HOneShotInterceptor
+ && interceptor.isConstant()
+ && selector.isCall()) {
DartType type = types[interceptor].computeType(compiler);
ClassElement cls = type.element;
node.element = cls.lookupSelector(selector);
}
+ HInstruction input = node.inputs[1];
+ HType type = types[input];
+ // Check if this call does not need to be intercepted.
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.
@@ -385,19 +389,16 @@
HInstruction visitInvokeDynamicMethod(HInvokeDynamicMethod node) {
if (node.isInterceptorCall) return handleInterceptorCall(node);
HType receiverType = types[node.receiver];
- if (receiverType.isExact()) {
- Element element = receiverType.lookupMember(node.selector.name, compiler);
- // TODO(ngeoffray): Also fold if it's a getter or variable.
- if (element != null && element.isFunction()) {
- if (node.selector.applies(element, compiler)) {
- FunctionElement method = element;
- FunctionSignature parameters = method.computeSignature(compiler);
- if (parameters.optionalParameterCount == 0) {
- node.element = element;
- }
- // TODO(ngeoffray): If the method has optional parameters,
- // we should pass the default values here.
- }
+ Element element = receiverType.lookupSingleTarget(node.selector, compiler);
+ // TODO(ngeoffray): Also fold if it's a getter or variable.
+ if (element != null && element.isFunction()) {
+ FunctionElement method = element;
+ FunctionSignature parameters = method.computeSignature(compiler);
+ // TODO(ngeoffray): If the method has optional parameters,
+ // we should pass the default values.
+ if (parameters.optionalParameterCount == 0
+ || parameters.parameterCount == node.selector.argumentCount) {
+ node.element = element;
}
}
return node;
@@ -599,9 +600,9 @@
Selector selector) {
HType receiverType = types[receiver];
if (!receiverType.isUseful()) return null;
- if (receiverType.canBeNull()) return null;
DartType type = receiverType.computeType(compiler);
if (type == null) return null;
+ if (Elements.isErroneousElement(type.element)) return null;
return compiler.world.locateSingleField(type, selector);
}
@@ -635,11 +636,17 @@
}
HFieldGet result = new HFieldGet(
field, node.inputs[0], isAssignable: !isFinalOrConst);
- HType type = backend.optimisticFieldType(field);
- if (type != null) {
- result.guaranteedType = type;
- backend.registerFieldTypesOptimization(
- work.element, field, result.guaranteedType);
+
+ if (field.getEnclosingClass().isNative()) {
+ result.guaranteedType =
+ new HType.subtype(field.computeType(compiler), compiler);
+ } else {
+ HType type = backend.optimisticFieldType(field);
+ if (type != null) {
+ backend.registerFieldTypesOptimization(
+ work.element, field, result.guaranteedType);
+ result.guaranteedType = type;
+ }
}
return result;
}
@@ -1502,9 +1509,10 @@
implements OptimizationPhase {
final String name = "SsaSimplifyInterceptors";
final ConstantSystem constantSystem;
+ final HTypeMap types;
HGraph graph;
- SsaSimplifyInterceptors(this.constantSystem);
+ SsaSimplifyInterceptors(this.constantSystem, this.types);
void visitGraph(HGraph graph) {
this.graph = graph;
@@ -1531,6 +1539,8 @@
user.selector, inputs, node.interceptedClasses);
interceptor.sourcePosition = user.sourcePosition;
interceptor.sourceElement = user.sourceElement;
+ interceptor.guaranteedType = user.guaranteedType;
+ types[interceptor] = types[user];
HBasicBlock block = user.block;
block.addAfter(user, interceptor);
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/types.dart b/sdk/lib/_internal/compiler/implementation/ssa/types.dart
index 3e01f1a..8b55c23 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/types.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/types.dart
@@ -26,18 +26,28 @@
isInterfaceType: isInterfaceType);
}
- if (element == compiler.intClass) {
+ JavaScriptBackend backend = compiler.backend;
+ if (element == compiler.intClass || element == backend.jsIntClass) {
return canBeNull ? HType.INTEGER_OR_NULL : HType.INTEGER;
- } else if (element == compiler.numClass) {
+ } else if (element == compiler.numClass
+ || element == backend.jsNumberClass) {
return canBeNull ? HType.NUMBER_OR_NULL : HType.NUMBER;
- } else if (element == compiler.doubleClass) {
+ } else if (element == compiler.doubleClass
+ || element == backend.jsDoubleClass) {
return canBeNull ? HType.DOUBLE_OR_NULL : HType.DOUBLE;
- } else if (element == compiler.stringClass) {
+ } else if (element == compiler.stringClass
+ || element == backend.jsStringClass) {
return canBeNull ? HType.STRING_OR_NULL : HType.STRING;
- } else if (element == compiler.boolClass) {
+ } else if (element == compiler.boolClass
+ || element == backend.jsBoolClass) {
return canBeNull ? HType.BOOLEAN_OR_NULL : HType.BOOLEAN;
- } else if (element == compiler.nullClass) {
+ } else if (element == compiler.nullClass
+ || element == backend.jsNullClass) {
return HType.NULL;
+ } else if (element == backend.jsArrayClass) {
+ return canBeNull
+ ? HType.READABLE_ARRAY.union(HType.NULL, compiler)
+ : HType.READABLE_ARRAY;
} else if (!isExact) {
if (element == compiler.listClass
|| Elements.isListSupertype(element, compiler)) {
@@ -55,7 +65,8 @@
type,
canBeNull: canBeNull,
isInterfaceType: isInterfaceType);
- } else if (element == compiler.objectClass) {
+ } else if (element == compiler.objectClass
+ || element == compiler.dynamicClass) {
return new HBoundedPotentialPrimitiveType(
compiler.objectClass.computeType(compiler),
true,
@@ -158,12 +169,23 @@
/** Alias for isReadableArray. */
bool isArray() => isReadableArray();
- Element lookupMember(SourceString name, Compiler compiler) {
- if (!isExact()) return null;
+ Element lookupSingleTarget(Selector selector, Compiler compiler) {
+ if (isInterfaceType()) return null;
DartType type = computeType(compiler);
if (type == null) return null;
ClassElement cls = type.element;
- return cls.lookupMember(name);
+ Element member = cls.lookupSelector(selector);
+ if (member == null) return null;
+ // [:ClassElement.lookupSelector:] may return an abstract field,
+ // and selctors don't work well with them.
+ // TODO(ngeoffray): Clean up lookupSelector and selectors to know
+ // if it's a getter or a setter that we're interested in.
+ if (!member.isFunction()) return null;
+ if (!selector.applies(member, compiler)) return null;
+ if (!isExact() && !compiler.world.hasNoOverridingMember(member)) {
+ return null;
+ }
+ return member;
}
DartType computeType(Compiler compiler);
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart b/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart
index ee0f1a1..223e017 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/types_propagation.dart
@@ -20,7 +20,6 @@
pendingOptimizations = new Map<HInstruction, Function>();
HType computeType(HInstruction instruction) {
- if (instruction.hasGuaranteedType()) return instruction.guaranteedType;
return instruction.computeTypeFromInputTypes(types, compiler);
}
diff --git a/sdk/lib/_internal/compiler/implementation/ssa/value_range_analyzer.dart b/sdk/lib/_internal/compiler/implementation/ssa/value_range_analyzer.dart
index c28d5c4..7ea24ed 100644
--- a/sdk/lib/_internal/compiler/implementation/ssa/value_range_analyzer.dart
+++ b/sdk/lib/_internal/compiler/implementation/ssa/value_range_analyzer.dart
@@ -647,6 +647,8 @@
HInstruction next = check.next;
Range indexRange = ranges[check.index];
Range lengthRange = ranges[check.length];
+ assert(check.index.isInteger(types));
+ assert(check.length.isInteger(types));
// Check if the index is strictly below the upper bound of the length
// range.
diff --git a/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
index 6c05203..f268488 100644
--- a/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/concrete_types_inferrer.dart
@@ -86,7 +86,7 @@
*/
factory ConcreteType.singleton(int maxConcreteTypeSize, BaseType baseType) {
if (baseType.isUnknown() || maxConcreteTypeSize < 1) {
- return new UnknownConcreteType();
+ return const UnknownConcreteType();
}
Set<BaseType> singletonSet = new Set<BaseType>();
singletonSet.add(baseType);
@@ -391,7 +391,7 @@
* A task which conservatively infers a [ConcreteType] for each sub expression
* of the program. The entry point is [analyzeMain].
*/
-class ConcreteTypesInferrer {
+class ConcreteTypesInferrer extends TypesInferrer {
static final bool LOG_FAILURES = true;
final String name = "Type inferrer";
@@ -686,13 +686,16 @@
/**
* Get the inferred concrete type of [node].
*/
- ConcreteType getConcreteTypeOfNode(Node node) => inferredTypes[node];
+ ConcreteType getConcreteTypeOfNode(Element owner, Node node) {
+ return inferredTypes[node];
+ }
/**
- * Get the inferred concrete type of [parameter].
+ * Get the inferred concrete type of [element].
*/
- ConcreteType getConcreteTypeOfParameter(VariableElement parameter) {
- return inferredParameterTypes[parameter];
+ ConcreteType getConcreteTypeOfElement(Element element) {
+ if (!element.isParameter()) return null;
+ return inferredParameterTypes[element];
}
// --- analysis ---
diff --git a/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart b/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
new file mode 100644
index 0000000..e4a16b0
--- /dev/null
+++ b/sdk/lib/_internal/compiler/implementation/types/simple_types_inferrer.dart
@@ -0,0 +1,779 @@
+// 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 simple_types_inferrer;
+
+import '../native_handler.dart' as native;
+import '../elements/elements.dart';
+import '../dart2jslib.dart';
+import '../tree/tree.dart';
+import '../util/util.dart' show Link;
+import 'types.dart' show TypesInferrer, ConcreteType, ClassBaseType;
+
+/**
+ * A work queue that ensures there are no duplicates, and adds and
+ * removes in LIFO.
+ */
+class WorkSet<E extends Element> {
+ final List<E> queue = new List<E>();
+ final Set<E> elementsInQueue = new Set<E>();
+
+ void add(E element) {
+ element = element.implementation;
+ if (elementsInQueue.contains(element)) return;
+ queue.addLast(element);
+ elementsInQueue.add(element);
+ }
+
+ E remove() {
+ E element = queue.removeLast();
+ elementsInQueue.remove(element);
+ return element;
+ }
+
+ bool get isEmpty => queue.isEmpty;
+}
+
+class SimpleTypesInferrer extends TypesInferrer {
+ /**
+ * Maps an element to its callers.
+ */
+ final Map<Element, Set<Element>> callersOf =
+ new Map<Element, Set<Element>>();
+
+ /**
+ * Maps an element to its return type.
+ */
+ final Map<Element, Element> returnTypeOf =
+ new Map<Element, Element>();
+
+ /**
+ * Maps a name to elements in the universe that have that name.
+ */
+ final Map<SourceString, Set<Element>> methodCache =
+ new Map<SourceString, Set<Element>>();
+
+ /**
+ * Maps an element to the number of times this type inferrer
+ * analyzed it.
+ */
+ final Map<Element, int> analyzeCount = new Map<Element, int>();
+
+ /**
+ * The work list of the inferrer.
+ */
+ final WorkSet<Element> workSet = new WorkSet<Element>();
+
+ /**
+ * Heuristic for avoiding too many re-analysis of an element.
+ */
+ final int MAX_ANALYSIS_COUNT_PER_ELEMENT = 5;
+
+ /**
+ * Sentinal used by the inferrer to notify that it gave up finding a type
+ * on a specific element.
+ */
+ Element giveUpType;
+
+ final Compiler compiler;
+
+ // Times the computation of the call graph.
+ final Stopwatch memberWatch = new Stopwatch();
+ // Times the computation of re-analysis of methods.
+ final Stopwatch recomputeWatch = new Stopwatch();
+ // Number of re-analysis.
+ int recompiles = 0;
+
+ SimpleTypesInferrer(this.compiler);
+
+ /**
+ * Main entry point of the inferrer. Analyzes all elements that the
+ * resolver found as reachable. Returns whether it succeeded.
+ */
+ bool analyzeMain(Element element) {
+ // We use the given element as the sentinel. This is a temporary
+ // situation as long as this inferrer is using [ClassElement] for
+ // expressing types.
+ giveUpType = element;
+ buildWorkQueue();
+ int analyzed = 0;
+ compiler.progress.reset();
+ do {
+ if (compiler.progress.elapsedMilliseconds > 500) {
+ compiler.log('Inferred $analyzed methods.');
+ compiler.progress.reset();
+ }
+ element = workSet.remove();
+ if (element.isErroneous()) continue;
+
+ bool wasAnalyzed = analyzeCount.containsKey(element);
+ if (wasAnalyzed) {
+ recompiles++;
+ recomputeWatch.start();
+ }
+ bool changed = analyze(element);
+ analyzed++;
+ if (wasAnalyzed) {
+ recomputeWatch.stop();
+ }
+ if (!changed) continue;
+ // If something changed during the analysis of [element],
+ // put back callers of it in the work list.
+ Set<Element> methodCallers = callersOf[element];
+ if (methodCallers != null) {
+ methodCallers.forEach(enqueueAgain);
+ }
+ } while (!workSet.isEmpty);
+ dump();
+ clear();
+ return true;
+ }
+
+ /**
+ * Query method after the analysis to know the type of [element].
+ */
+ getConcreteTypeOfElement(element) {
+ return getTypeIfValuable(returnTypeOf[element]);
+ }
+
+ getTypeIfValuable(returnType) {
+ if (returnType == null
+ || returnType == compiler.dynamicClass
+ || returnType == giveUpType) {
+ return null;
+ }
+ return new ConcreteType.singleton(
+ compiler.maxConcreteTypeSize, new ClassBaseType(returnType));
+ }
+
+ /**
+ * Query method after the analysis to know the type of [node],
+ * defined in the context of [owner].
+ */
+ getConcreteTypeOfNode(Element owner, Node node) {
+ var elements = compiler.enqueuer.resolution.resolvedElements[owner];
+ Selector selector = elements.getSelector(node);
+ // TODO(ngeoffray): Should the builder call this method with a
+ // SendSet?
+ if (selector == null || selector.isSetter() || selector.isIndexSet()) {
+ return null;
+ }
+ return getTypeIfValuable(returnTypeOfSelector(selector));
+ }
+
+ /**
+ * Enqueues [e] in the work queue if it is valuable.
+ */
+ void enqueueAgain(Element e) {
+ Element returnType = returnTypeOf[e];
+ // If we have found a type for [e], no need to re-analyze it.
+ if (returnType != compiler.dynamicClass) return;
+ if (analyzeCount[e] > MAX_ANALYSIS_COUNT_PER_ELEMENT) return;
+ workSet.add(e);
+ }
+
+ /**
+ * Builds the initial work queue by adding all resolved elements in
+ * the work queue, ordered by the number of selectors they use. This
+ * order is benficial for the analysis of return types, but we may
+ * have to refine it once we analyze parameter types too.
+ */
+ void buildWorkQueue() {
+ int max = 0;
+ Map<int, Set<Element>> methodSizes = new Map<int, Set<Element>>();
+ compiler.enqueuer.resolution.resolvedElements.forEach(
+ (Element element, TreeElementMapping mapping) {
+ // TODO(ngeoffray): Not sure why the resolver would put a null
+ // mapping.
+ if (mapping == null) return;
+ if (element.isAbstract(compiler)) return;
+ int length = mapping.selectors.length;
+ max = length > max ? length : max;
+ Set<Element> set = methodSizes.putIfAbsent(
+ length, () => new Set<Element>());
+ set.add(element);
+ });
+
+ // This iteration assumes the [WorkSet] is LIFO.
+ for (int i = max; i >= 0; i--) {
+ Set<Element> set = methodSizes[i];
+ if (set != null) {
+ set.forEach((e) { workSet.add(e); });
+ }
+ }
+ }
+
+ dump() {
+ int interestingTypes = 0;
+ int giveUpTypes = 0;
+ returnTypeOf.forEach((Element method, Element type) {
+ if (type == giveUpType) {
+ giveUpTypes++;
+ } else if (type != compiler.nullClass && type != compiler.dynamicClass) {
+ interestingTypes++;
+ }
+ });
+ compiler.log('Type inferrer spent ${memberWatch.elapsedMilliseconds} ms '
+ 'computing a call graph.');
+ compiler.log('Type inferrer re-analyzed methods $recompiles times '
+ 'in ${recomputeWatch.elapsedMilliseconds} ms.');
+ compiler.log('Type inferrer found $interestingTypes interesting '
+ 'return types and gave up on $giveUpTypes methods.');
+ }
+
+ /**
+ * Clear data structures that are not used after the analysis.
+ */
+ void clear() {
+ callersOf.clear();
+ analyzeCount.clear();
+ }
+
+ bool analyze(Element element) {
+ if (element.isField()) {
+ // TODO(ngeoffray): Analyze its initializer.
+ return false;
+ } else {
+ SimpleTypeInferrerVisitor visitor =
+ new SimpleTypeInferrerVisitor(element, compiler, this);
+ return visitor.run();
+ }
+ }
+
+ /**
+ * Records [returnType] as the return type of [analyzedElement].
+ * Returns whether the new type is worth recompiling the callers of
+ * [analyzedElement].
+ */
+ bool recordReturnType(analyzedElement, returnType) {
+ assert(returnType != null);
+ Element existing = returnTypeOf[analyzedElement];
+ if (existing == null) {
+ // First time we analyzed [analyzedElement]. Initialize the
+ // return type.
+ assert(!analyzeCount.containsKey(analyzedElement));
+ returnTypeOf[analyzedElement] = returnType;
+ // If the return type is useful, say it has changed.
+ return returnType != compiler.dynamicClass
+ && returnType != compiler.nullClass;
+ } else if (existing == compiler.dynamicClass) {
+ // Previous analysis did not find any type.
+ returnTypeOf[analyzedElement] = returnType;
+ // If the return type is useful, say it has changed.
+ return returnType != compiler.dynamicClass
+ && returnType != compiler.nullClass;
+ } else if (existing == giveUpType) {
+ // If we already gave up on the return type, we don't change it.
+ return false;
+ } else if (existing != returnType) {
+ // The method is returning two different types. Give up for now.
+ // TODO(ngeoffray): Compute LUB.
+ returnTypeOf[analyzedElement] = giveUpType;
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns the return type of [element]. Returns [:Dynamic:] if
+ * [element] has not been analyzed yet.
+ */
+ ClassElement returnTypeOfElement(Element element) {
+ element = element.implementation;
+ if (element.isGenerativeConstructor()) return element.getEnclosingClass();
+ Element returnType = returnTypeOf[element];
+ if (returnType == null || returnType == giveUpType) {
+ return compiler.dynamicClass;
+ }
+ return returnType;
+ }
+
+ /**
+ * Returns the union of the return types of all elements that match
+ * the called [selector].
+ */
+ ClassElement returnTypeOfSelector(Selector selector) {
+ ClassElement result;
+ iterateOverElements(selector, (Element element) {
+ assert(element.isImplementation);
+ Element cls;
+ if (element.isFunction() && selector.isGetter()) {
+ cls = compiler.functionClass;
+ } else {
+ cls = returnTypeOf[element];
+ }
+ if (cls == null
+ || cls == compiler.dynamicClass
+ || cls == giveUpType
+ || (cls != result && result != null)) {
+ result = compiler.dynamicClass;
+ return false;
+ } else {
+ result = cls;
+ return true;
+ }
+ });
+ return result;
+ }
+
+ /**
+ * Registers that [caller] calls [callee] with the given
+ * [arguments].
+ */
+ void registerCalledElement(Element caller,
+ Element callee,
+ ArgumentsTypes arguments) {
+ if (analyzeCount.containsKey(caller)) return;
+ callee = callee.implementation;
+ Set<FunctionElement> callers = callersOf.putIfAbsent(
+ callee, () => new Set<FunctionElement>());
+ callers.add(caller);
+ }
+
+ /**
+ * Registers that [caller] accesses [callee] through a property
+ * access.
+ */
+ void registerGetterOnElement(Element caller,
+ Element callee) {
+ if (analyzeCount.containsKey(caller)) return;
+ callee = callee.implementation;
+ Set<FunctionElement> callers = callersOf.putIfAbsent(
+ callee, () => new Set<FunctionElement>());
+ callers.add(caller);
+ }
+
+ /**
+ * Registers that [caller] calls an element matching [selector]
+ * with the given [arguments].
+ */
+ void registerCalledSelector(Element caller,
+ Selector selector,
+ ArgumentsTypes arguments) {
+ if (analyzeCount.containsKey(caller)) return;
+ iterateOverElements(selector, (Element element) {
+ assert(element.isImplementation);
+ Set<FunctionElement> callers = callersOf.putIfAbsent(
+ element, () => new Set<FunctionElement>());
+ callers.add(caller);
+ return true;
+ });
+ }
+
+ /**
+ * Registers that [caller] accesses an element matching [selector]
+ * through a property access.
+ */
+ void registerGetterOnSelector(Element caller, Selector selector) {
+ if (analyzeCount.containsKey(caller)) return;
+ iterateOverElements(selector, (Element element) {
+ assert(element.isImplementation);
+ Set<FunctionElement> callers = callersOf.putIfAbsent(
+ element, () => new Set<FunctionElement>());
+ callers.add(caller);
+ return true;
+ });
+ }
+
+ /**
+ * Registers that [caller] closurizes [function].
+ */
+ void registerGetFunction(Element caller, Element function) {
+ assert(caller.isImplementation);
+ if (analyzeCount.containsKey(caller)) return;
+ // We don't register that [caller] calls [function] because we
+ // don't know if the code is going to call it, and if it is, then
+ // the inferrer has lost track of its identity anyway.
+ }
+
+ /**
+ * Applies [f] to all elements in the universe that match
+ * [selector]. If [f] returns false, aborts the iteration.
+ */
+ void iterateOverElements(Selector selector, bool f(Element element)) {
+ SourceString name = selector.name;
+
+ // The following is already computed by the resolver, but it does
+ // not save it yet.
+ Set<Element> methods = methodCache[name];
+ if (methods == null) {
+ memberWatch.start();
+ methods = new Set<Element>();
+ void add(element) {
+ if (!element.isInstanceMember()) return;
+ if (element.isAbstract(compiler)) return;
+ if (!compiler.enqueuer.resolution.isProcessed(element)) return;
+ methods.add(element.implementation);
+ }
+ for (ClassElement cls in compiler.enqueuer.resolution.seenClasses) {
+ var element = cls.lookupLocalMember(name);
+ if (element != null) {
+ if (element.isAbstractField()) {
+ if (element.getter != null) add(element.getter);
+ if (element.setter != null) add(element.setter);
+ } else {
+ add(element);
+ }
+ }
+ }
+ methodCache[name] = methods;
+ memberWatch.stop();
+ }
+
+ for (Element element in methods) {
+ if (selector.appliesUnnamed(element, compiler)) {
+ if (!f(element)) return;
+ }
+ }
+ }
+}
+
+/**
+ * Placeholder for inferred arguments types on sends.
+ */
+class ArgumentsTypes {
+ final List<Element> positional;
+ final Map<Identifier, Element> named;
+ ArgumentsTypes(this.positional, this.named);
+ int get length => positional.length + named.length;
+ toString() => "{ positional = $positional, named = $named }";
+}
+
+class SimpleTypeInferrerVisitor extends ResolvedVisitor {
+ final FunctionElement analyzedElement;
+ final SimpleTypesInferrer inferrer;
+ final Compiler compiler;
+ Element returnType;
+
+ SimpleTypeInferrerVisitor(FunctionElement element,
+ Compiler compiler,
+ this.inferrer)
+ : super(compiler.enqueuer.resolution.resolvedElements[element.declaration]),
+ analyzedElement = element,
+ compiler = compiler {
+ assert(elements != null);
+ }
+
+ bool run() {
+ FunctionExpression node =
+ analyzedElement.implementation.parseNode(compiler);
+ bool changed;
+ if (analyzedElement.isGenerativeConstructor()) {
+ FunctionSignature signature = analyzedElement.computeSignature(compiler);
+ // TODO(ngeoffray): handle initializing formals.
+ // TODO(ngeoffray): handle initializers.
+ node.body.accept(this);
+ // We always know the return type of a generative constructor.
+ changed = false;
+ } else if (analyzedElement.isNative()) {
+ // Native methods do not have a body, and we currently just say
+ // they return dynamic.
+ inferrer.recordReturnType(analyzedElement, compiler.dynamicClass);
+ changed = false;
+ } else {
+ node.body.accept(this);
+ if (returnType == null) {
+ // No return in the body.
+ returnType = compiler.nullClass;
+ }
+ changed = inferrer.recordReturnType(analyzedElement, returnType);
+ }
+ if (inferrer.analyzeCount.containsKey(analyzedElement)) {
+ inferrer.analyzeCount[analyzedElement]++;
+ } else {
+ inferrer.analyzeCount[analyzedElement] = 1;
+ }
+ return changed;
+ }
+
+ recordReturnType(ClassElement cls) {
+ if (returnType == null) {
+ returnType = cls;
+ } else if (returnType != inferrer.giveUpType
+ && cls == compiler.dynamicClass) {
+ returnType = cls;
+ } else if (returnType == compiler.dynamicClass) {
+ // Nothing to do. Stay dynamic.
+ } else if (leastUpperBound(cls, returnType) == compiler.dynamicClass) {
+ returnType = inferrer.giveUpType;
+ }
+ }
+
+ visitNode(Node node) {
+ node.visitChildren(this);
+ return compiler.dynamicClass;
+ }
+
+ visitNewExpression(NewExpression node) {
+ return node.send.accept(this);
+ }
+
+ visitFunctionExpression(FunctionExpression node) {
+ // We don't put the closure in the work queue of the
+ // inferrer, because it will share information with its enclosing
+ // method, like for example the types of local variables.
+ SimpleTypeInferrerVisitor visitor =
+ new SimpleTypeInferrerVisitor(elements[node], compiler, inferrer);
+ visitor.run();
+ return compiler.functionClass;
+ }
+
+ visitLiteralString(LiteralString node) {
+ return compiler.stringClass;
+ }
+
+ visitStringInterpolation(StringInterpolation node) {
+ return compiler.stringClass;
+ }
+
+ visitStringJuxtaposition(StringJuxtaposition node) {
+ return compiler.stringClass;
+ }
+
+ visitLiteralBool(LiteralBool node) {
+ return compiler.boolClass;
+ }
+
+ visitLiteralDouble(LiteralDouble node) {
+ return compiler.doubleClass;
+ }
+
+ visitLiteralInt(LiteralInt node) {
+ return compiler.intClass;
+ }
+
+ visitLiteralList(LiteralList node) {
+ return compiler.listClass;
+ }
+
+ visitLiteralMap(LiteralMap node) {
+ return compiler.mapClass;
+ }
+
+ visitLiteralNull(LiteralNull node) {
+ return compiler.nullClass;
+ }
+
+ visitTypeReferenceSend(Send node) {
+ return compiler.typeClass;
+ }
+
+ visitSendSet(SendSet node) {
+ // TODO(ngeoffray): return the right hand side's type.
+ node.visitChildren(this);
+ return compiler.dynamicClass;
+ }
+
+ visitIdentifier(Identifier node) {
+ if (node.isThis() || node.isSuper()) {
+ // TODO(ngeoffray): Represent subclasses.
+ return compiler.dynamicClass;
+ }
+ return compiler.dynamicClass;
+ }
+
+ visitSuperSend(Send node) {
+ Element element = elements[node];
+ if (Elements.isUnresolved(element)) {
+ return compiler.dynamicClass;
+ }
+ Selector selector = elements.getSelector(node);
+ if (node.isPropertyAccess) {
+ inferrer.registerGetterOnElement(analyzedElement, element);
+ return inferrer.returnTypeOfElement(element);
+ } else if (element.isFunction()) {
+ ArgumentsTypes arguments = analyzeArguments(node.arguments);
+ inferrer.registerCalledElement(analyzedElement, element, arguments);
+ return inferrer.returnTypeOfElement(element);
+ } else {
+ // Closure call on a getter. We don't have function types yet,
+ // so we just return [:Dynamic:].
+ return compiler.dynamicClass;
+ }
+ }
+
+ visitStaticSend(Send node) {
+ Element element = elements[node];
+ if (Elements.isUnresolved(element)) {
+ return compiler.dynamicClass;
+ }
+ if (element.isForeign(compiler)) {
+ return handleForeignSend(node);
+ }
+ ArgumentsTypes arguments = analyzeArguments(node.arguments);
+ inferrer.registerCalledElement(analyzedElement, element, arguments);
+ return inferrer.returnTypeOfElement(element);
+ }
+
+ handleForeignSend(Send node) {
+ node.visitChildren(this);
+ Selector selector = elements.getSelector(node);
+ SourceString name = selector.name;
+ if (name == const SourceString('JS')) {
+ native.NativeBehavior nativeBehavior =
+ compiler.enqueuer.resolution.nativeEnqueuer.getNativeBehaviorOf(node);
+ if (nativeBehavior == null) return compiler.dynamicClass;
+ List typesReturned = nativeBehavior.typesReturned;
+ if (typesReturned.isEmpty) return compiler.dynamicClass;
+ ClassElement returnType;
+ for (var type in typesReturned) {
+ ClassElement mappedType;
+ if (type == native.SpecialType.JsObject) {
+ mappedType = compiler.objectClass;
+ } else if (type == native.SpecialType.JsArray) {
+ mappedType = compiler.listClass;
+ } else {
+ mappedType = type.element;
+ // For primitive types, we know how to handle them here and
+ // in the backend.
+ if (mappedType != compiler.stringClass
+ && mappedType != compiler.intClass
+ && mappedType != compiler.doubleClass
+ && mappedType != compiler.boolClass
+ && mappedType != compiler.numClass) {
+ Set<ClassElement> subtypes = compiler.world.subtypes[mappedType];
+ // TODO(ngeoffray): Handle subtypes and subclasses.
+ if (subtypes != null && !subtypes.isEmpty) {
+ return compiler.dynamicClass;
+ }
+ }
+ }
+ if (returnType == null) {
+ returnType = mappedType;
+ } else {
+ return compiler.dynamicClass;
+ }
+ }
+ return returnType;
+ } else if (name == const SourceString('JS_OPERATOR_IS_PREFIX')) {
+ return compiler.stringClass;
+ } else {
+ return compiler.dynamicClass;
+ }
+ }
+
+ analyzeArguments(Link<Node> arguments) {
+ List<ClassElement> positional = [];
+ Map<Identifier, ClassElement> named = new Map<Identifier, ClassElement>();
+ for (Node argument in arguments) {
+ NamedArgument namedArgument = argument.asNamedArgument();
+ if (namedArgument != null) {
+ named[namedArgument.name] = namedArgument.expression.accept(this);
+ } else {
+ positional.add(argument.accept(this));
+ }
+ }
+ return new ArgumentsTypes(positional, named);
+ }
+
+ visitOperatorSend(Send node) {
+ Operator op = node.selector;
+ if (const SourceString("[]") == op.source) {
+ return visitDynamicSend(node);
+ } else if (const SourceString("&&") == op.source ||
+ const SourceString("||") == op.source) {
+ node.visitChildren(this);
+ return compiler.boolClass;
+ } else if (const SourceString("!") == op.source) {
+ node.visitChildren(this);
+ return compiler.boolClass;
+ } else if (const SourceString("is") == op.source) {
+ node.visitChildren(this);
+ return compiler.boolClass;
+ } else if (const SourceString("as") == op.source) {
+ node.visitChildren(this);
+ return compiler.dynamicClass;
+ } else if (node.isParameterCheck) {
+ node.visitChildren(this);
+ return compiler.boolClass;
+ } else if (node.argumentsNode is Prefix) {
+ // Unary operator.
+ return visitDynamicSend(node);
+ } else if (const SourceString('===') == op.source
+ || const SourceString('!==') == op.source) {
+ node.visitChildren(this);
+ return compiler.boolClass;
+ } else {
+ // Binary operator.
+ return visitDynamicSend(node);
+ }
+ }
+
+ // Because some nodes just visit their children, we may end up
+ // visiting a type annotation, that may contain a send in case of a
+ // prefixed type. Therefore we explicitly visit the type annotation
+ // to avoid confusing the [ResolvedVisitor].
+ visitTypeAnnotation(TypeAnnotation node) {}
+
+ visitGetterSend(Send node) {
+ Element element = elements[node];
+ if (Elements.isStaticOrTopLevelField(element)) {
+ if (element.isGetter()) {
+ inferrer.registerGetterOnElement(analyzedElement, element);
+ return inferrer.returnTypeOfElement(element);
+ } else {
+ // Nothing yet.
+ // TODO: Analyze initializer of element.
+ return compiler.dynamicClass;
+ }
+ } else if (Elements.isInstanceSend(node, elements)) {
+ ClassElement receiverType;
+ if (node.receiver == null) {
+ receiverType = analyzedElement.getEnclosingClass();
+ } else {
+ receiverType = node.receiver.accept(this);
+ }
+ Selector selector = elements.getSelector(node);
+ inferrer.registerGetterOnSelector(analyzedElement, selector);
+ return inferrer.returnTypeOfSelector(selector);
+ } else if (Elements.isStaticOrTopLevelFunction(element)) {
+ inferrer.registerGetFunction(analyzedElement, element);
+ return compiler.functionClass;
+ } else {
+ // TODO: Analyze variable.
+ return compiler.dynamicClass;
+ }
+ }
+
+ visitClosureSend(Send node) {
+ node.visitChildren(this);
+ return compiler.dynamicClass;
+ }
+
+ visitDynamicSend(Send node) {
+ ClassElement receiverType;
+ if (node.receiver == null) {
+ receiverType = analyzedElement.getEnclosingClass();
+ } else {
+ receiverType = node.receiver.accept(this);
+ }
+ ArgumentsTypes arguments = analyzeArguments(node.arguments);
+ Selector selector = elements.getSelector(node);
+ inferrer.registerCalledSelector(analyzedElement, selector, arguments);
+ return inferrer.returnTypeOfSelector(selector);
+ }
+
+ visitReturn(Return node) {
+ Node expression = node.expression;
+ recordReturnType(expression == null
+ ? compiler.nullClass
+ : expression.accept(this));
+ }
+
+ visitConditional(Conditional node) {
+ node.condition.accept(this);
+ Element firstType = node.thenExpression.accept(this);
+ Element secondType = node.elseExpression.accept(this);
+ return leastUpperBound(firstType, secondType);
+ }
+
+ leastUpperBound(Element firstType, Element secondType) {
+ if (firstType == secondType) return firstType;
+ return compiler.dynamicClass;
+ }
+
+ internalError(String reason, {Node node}) {
+ compiler.internalError(reason, node: node);
+ }
+}
diff --git a/sdk/lib/_internal/compiler/implementation/types/types.dart b/sdk/lib/_internal/compiler/implementation/types/types.dart
index fdce427..345f0be 100644
--- a/sdk/lib/_internal/compiler/implementation/types/types.dart
+++ b/sdk/lib/_internal/compiler/implementation/types/types.dart
@@ -12,23 +12,36 @@
import '../elements/elements.dart';
import '../util/util.dart';
import '../universe/universe.dart';
+import 'simple_types_inferrer.dart' show SimpleTypesInferrer;
part 'concrete_types_inferrer.dart';
/**
+ * Common super class for our type inferrers. Currently, its query methods
+ * return instances of [ConcreteType], but that may change in the
+ * future.
+ */
+abstract class TypesInferrer {
+ analyzeMain(Element element);
+ getConcreteTypeOfElement(Element element);
+ getConcreteTypeOfNode(Element owner, Node node);
+}
+
+/**
* The types task infers guaranteed types globally.
*/
class TypesTask extends CompilerTask {
final String name = 'Type inference';
final Set<Element> untypedElements;
final Map<Element, Link<Element>> typedSends;
- ConcreteTypesInferrer concreteTypesInferrer;
+ TypesInferrer typesInferrer;
TypesTask(Compiler compiler)
: untypedElements = new Set<Element>(),
typedSends = new Map<Element, Link<Element>>(),
- concreteTypesInferrer = compiler.enableConcreteTypeInference
- ? new ConcreteTypesInferrer(compiler) : null,
+ typesInferrer = compiler.enableConcreteTypeInference
+ ? new ConcreteTypesInferrer(compiler)
+ : new SimpleTypesInferrer(compiler),
super(compiler);
/**
@@ -46,13 +59,13 @@
*/
void onResolutionComplete(Element mainElement) {
measure(() {
- if (concreteTypesInferrer != null) {
- bool success = concreteTypesInferrer.analyzeMain(mainElement);
+ if (typesInferrer != null) {
+ bool success = typesInferrer.analyzeMain(mainElement);
if (!success) {
// If the concrete type inference bailed out, we pretend it didn't
// happen. In the future we might want to record that it failed but
// use the partial results as hints.
- concreteTypesInferrer = null;
+ typesInferrer = null;
}
}
});
@@ -63,12 +76,12 @@
*/
ConcreteType getGuaranteedTypeOfElement(Element element) {
return measure(() {
- if (!element.isParameter()) return null;
- if (concreteTypesInferrer != null) {
- ConcreteType guaranteedType = concreteTypesInferrer
- .getConcreteTypeOfParameter(element);
+ if (typesInferrer != null) {
+ ConcreteType guaranteedType = typesInferrer
+ .getConcreteTypeOfElement(element);
if (guaranteedType != null) return guaranteedType;
}
+ if (!element.isParameter()) return null;
Element holder = element.enclosingElement;
Link<Element> types = typedSends[holder];
if (types == null) return null;
@@ -92,10 +105,10 @@
* Return the (inferred) guaranteed concrete type of [node] or null.
* [node] must be an AST node of [owner].
*/
- ConcreteType getGuaranteedTypeOfNode(Node node, Element owner) {
+ ConcreteType getGuaranteedTypeOfNode(owner, node) {
return measure(() {
- if (concreteTypesInferrer != null) {
- return concreteTypesInferrer.getConcreteTypeOfNode(node);
+ if (typesInferrer != null) {
+ return typesInferrer.getConcreteTypeOfNode(owner, node);
}
return null;
});
diff --git a/sdk/lib/_internal/compiler/implementation/universe/function_set.dart b/sdk/lib/_internal/compiler/implementation/universe/function_set.dart
index 6afdf09..b6c6a53 100644
--- a/sdk/lib/_internal/compiler/implementation/universe/function_set.dart
+++ b/sdk/lib/_internal/compiler/implementation/universe/function_set.dart
@@ -89,7 +89,7 @@
isList = false;
}
elements.add(element);
- cache.clear();
+ if (!cache.isEmpty) cache.clear();
}
}
@@ -103,14 +103,14 @@
if (index != list.length) {
list[index] = last;
}
- cache.clear();
+ if (!cache.isEmpty) cache.clear();
} else {
Set set = elements;
if (set.remove(element)) {
// To avoid wobbling between the two representations, we do
// not transition back to the list representation even if we
// end up with few enough elements at this point.
- cache.clear();
+ if (!cache.isEmpty) cache.clear();
}
}
}
diff --git a/sdk/lib/_internal/compiler/implementation/universe/partial_type_tree.dart b/sdk/lib/_internal/compiler/implementation/universe/partial_type_tree.dart
deleted file mode 100644
index b0ed8dc..0000000
--- a/sdk/lib/_internal/compiler/implementation/universe/partial_type_tree.dart
+++ /dev/null
@@ -1,141 +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 universe;
-
-abstract class PartialTypeTree {
- final Compiler compiler;
- PartialTypeTreeNode root;
-
- PartialTypeTree(this.compiler);
-
- PartialTypeTreeNode newNode(ClassElement type);
-
- /**
- * Returns a [ClassElement] that is an upper bound of the receiver type on
- * [selector].
- */
- // TODO(kasperl): Move this to the Selector class?
- ClassElement selectorType(Selector selector) {
- // TODO(ngeoffray): Should the tree be specialized with DartType?
- DartType type = selector.receiverType;
- if (type == null) return compiler.objectClass;
- // TODO(kasperl): Should [dynamic] return Object?
- if (identical(type.kind, TypeKind.MALFORMED_TYPE))
- return compiler.objectClass;
- // TODO(johnniwinther): Change to use [DartType.unalias].
- if (type.element.isTypedef()) return compiler.functionClass;
- return type.element;
- }
-
- /**
- * Finds the tree node corresponding to the given [type]. If [insert]
- * is true, we always return a node that matches the type by
- * inserting a new node if necessary. If [insert] is false, we
- * return null if we cannot find a node that matches the [type].
- */
- PartialTypeTreeNode findNode(ClassElement type, bool insert) {
- if (root == null) {
- if (!insert) return null;
- root = newNode(compiler.objectClass);
- }
-
- PartialTypeTreeNode current = root;
- L: while (!identical(current.type, type)) {
- assert(type.isSubclassOf(current.type));
-
- // Run through the children. If we find a subtype of the type
- // we are looking for we go that way. If not, we keep track of
- // the subtypes so we can move them from being children of the
- // current node to being children of a new node if we need
- // to insert that.
- Link<PartialTypeTreeNode> subtypes = const Link();
- for (Link link = current.children; !link.isEmpty; link = link.tail) {
- PartialTypeTreeNode child = link.head;
- ClassElement childType = child.type;
- if (type.isSubclassOf(childType)) {
- assert(subtypes.isEmpty);
- current = child;
- continue L;
- } else if (childType.isSubclassOf(type)) {
- if (insert) subtypes = subtypes.prepend(child);
- }
- }
-
- // If we are not inserting any nodes, we are done.
- if (!insert) return null;
-
- // Create a new node and move the children of the current node
- // that are subtypes of the type of the new node below the new
- // node in the hierarchy.
- PartialTypeTreeNode node = newNode(type);
- if (!subtypes.isEmpty) {
- node.children = subtypes;
- Link<PartialTypeTreeNode> remaining = const Link();
- for (Link link = current.children; !link.isEmpty; link = link.tail) {
- PartialTypeTreeNode child = link.head;
- if (!child.type.isSubclassOf(type)) {
- remaining = remaining.prepend(child);
- }
- }
- current.children = remaining;
- }
-
- // Add the new node as a child node of the current node and return it.
- current.children = current.children.prepend(node);
- return node;
- }
-
- // We found an exact match. No need to insert new nodes.
- assert(identical(current.type, type));
- return current;
- }
-
- /**
- * Visits all superclass and subclass nodes for the given [type]. If
- * the [visit] function ever returns false, we abort the traversal.
- */
- void visitHierarchy(ClassElement type, bool visit(PartialTypeTreeNode node)) {
- PartialTypeTreeNode current = root;
- L: while (!identical(current.type, type)) {
- assert(type.isSubclassOf(current.type));
- if (!visit(current)) return;
- for (Link link = current.children; !link.isEmpty; link = link.tail) {
- PartialTypeTreeNode child = link.head;
- ClassElement childType = child.type;
- if (type.isSubclassOf(childType)) {
- current = child;
- continue L;
- } else if (childType.isSubclassOf(type)) {
- if (!child.visitRecursively(visit)) return;
- }
- }
- return;
- }
- current.visitRecursively(visit);
- }
-
-}
-
-class PartialTypeTreeNode {
-
- final ClassElement type;
- Link<PartialTypeTreeNode> children;
-
- PartialTypeTreeNode(this.type) : children = const Link();
-
- /**
- * Visits this node and its children recursively. If the visit
- * callback ever returns false, the visiting stops early.
- */
- bool visitRecursively(bool visit(PartialTypeTreeNode node)) {
- if (!visit(this)) return false;
- for (Link link = children; !link.isEmpty; link = link.tail) {
- PartialTypeTreeNode child = link.head;
- if (!child.visitRecursively(visit)) return false;
- }
- return true;
- }
-
-}
diff --git a/sdk/lib/_internal/compiler/implementation/universe/selector_map.dart b/sdk/lib/_internal/compiler/implementation/universe/selector_map.dart
index 36b51399..29e705c 100644
--- a/sdk/lib/_internal/compiler/implementation/universe/selector_map.dart
+++ b/sdk/lib/_internal/compiler/implementation/universe/selector_map.dart
@@ -4,62 +4,41 @@
part of universe;
-// TODO(kasperl): It seems possible to rewrite this class to be more
-// like the FunctionSet abstraction which is a lot simpler.
-class SelectorMap<T> extends PartialTypeTree {
-
- SelectorMap(Compiler compiler) : super(compiler);
-
- SelectorMapNode<T> newNode(ClassElement type) => new SelectorMapNode<T>(type);
+class SelectorMap<T> {
+ final Compiler compiler;
+ final Map<SourceString, SelectorMapNode<T>> nodes =
+ new Map<SourceString, SelectorMapNode<T>>();
+ SelectorMap(this.compiler);
T operator [](Selector selector) {
- SelectorMapNode<T> node = findNode(selectorType(selector), false);
- if (node == null) return null;
- Link<SelectorValue<T>> selectors = node.selectorsByName[selector.name];
- if (selectors == null) return null;
- for (Link link = selectors; !link.isEmpty; link = link.tail) {
- SelectorValue<T> existing = link.head;
- if (existing.selector.equalsUntyped(selector)) return existing.value;
- }
- return null;
- }
-
- // TODO(kasperl): Do we need to support removing selectors by
- // passing null as the value?
- void operator []=(Selector selector, T value) {
- ClassElement type = selectorType(selector);
- SelectorMapNode<T> node = findNode(type, true);
SourceString name = selector.name;
- Link<SelectorValue<T>> selectors = node.selectorsByName.putIfAbsent(
- name, () => const Link());
- // Run through the linked list of selectors with the same name. If
- // we find one that matches, we update the value in the mapping.
- for (Link link = selectors; !link.isEmpty; link = link.tail) {
- SelectorValue<T> existing = link.head;
- // It is safe to ignore the type here, because all selector
- // mappings that are stored in a single node have the same type.
- if (existing.selector.equalsUntyped(selector)) {
- existing.value = value;
- return;
- }
- }
- // We could not find an existing mapping for the selector, so
- // we add a new one to the existing linked list.
- SelectorValue<T> head = new SelectorValue<T>(selector, value);
- node.selectorsByName[name] = selectors.prepend(head);
+ SelectorMapNode node = nodes[name];
+ return (node != null)
+ ? node.lookup(selector)
+ : null;
}
- // TODO(kasperl): Share code with the [] operator?
+ void operator []=(Selector selector, T value) {
+ SourceString name = selector.name;
+ SelectorMapNode node = nodes.putIfAbsent(
+ name, () => new SelectorMapNode(name));
+ node.update(selector, value);
+ }
+
bool containsKey(Selector selector) {
- SelectorMapNode<T> node = findNode(selectorType(selector), false);
- if (node == null) return false;
- Link<SelectorValue<T>> selectors = node.selectorsByName[selector.name];
- if (selectors == null) return false;
- for (Link link = selectors; !link.isEmpty; link = link.tail) {
- SelectorValue<T> existing = link.head;
- if (existing.selector.equalsUntyped(selector)) return true;
- }
- return false;
+ SourceString name = selector.name;
+ SelectorMapNode node = nodes[name];
+ return (node != null)
+ ? node.containsKey(selector)
+ : false;
+ }
+
+ T remove(Selector selector) {
+ SourceString name = selector.name;
+ SelectorMapNode node = nodes[name];
+ return (node != null)
+ ? node.remove(selector)
+ : null;
}
/**
@@ -69,56 +48,82 @@
*/
void visitMatching(Element member, bool visit(Selector selector, T value)) {
assert(member.isMember());
- if (root == null) return;
- // TODO(kasperl): Use visitHierachyMatching when possible. It is
- // currently broken in subtle ways when it comes to finding typed
- // selectors where we only know the interface of the receiver.
- visitAllMatching(member, visit);
+ SourceString name = member.name;
+ SelectorMapNode node = nodes[name];
+ if (node != null) {
+ node.visitMatching(member, compiler, visit);
+ }
}
-
- void visitAllMatching(Element member, bool visit(selector, value)) {
- root.visitRecursively((SelectorMapNode<T> node) {
- Link<SelectorValue<T>> selectors = node.selectorsByName[member.name];
- if (selectors == null) return true;
- for (Link link = selectors; !link.isEmpty; link = link.tail) {
- SelectorValue<T> existing = link.head;
- 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.appliesUnnamed(member, compiler)) {
- if (!visit(selector, existing.value)) return false;
- }
- }
- return true;
- });
- }
-
- void visitHierarchyMatching(Element member, bool visit(selector, value)) {
- visitHierarchy(member.getEnclosingClass(), (SelectorMapNode<T> node) {
- Link<SelectorValue<T>> selectors = node.selectorsByName[member.name];
- if (selectors == null) return true;
- for (Link link = selectors; !link.isEmpty; link = link.tail) {
- SelectorValue<T> existing = link.head;
- Selector selector = existing.selector;
- if (selector.appliesUntyped(member, compiler)) {
- if (!visit(selector, existing.value)) return false;
- }
- }
- return true;
- });
- }
-
}
-class SelectorMapNode<T> extends PartialTypeTreeNode {
- final Map<SourceString, Link<SelectorValue<T>>> selectorsByName =
- new Map<SourceString, Link<SelectorValue<T>>>();
- SelectorMapNode(ClassElement type) : super(type);
-}
+class SelectorMapNode<T> {
+ final SourceString name;
+ final Map<Selector, T> selectors = new Map<Selector, T>();
-class SelectorValue<T> {
- final Selector selector;
- T value;
- SelectorValue(this.selector, this.value);
- toString() => "$selector -> $value";
+ // We start caching which selectors match which elements when the
+ // number of different selectors exceed a threshold. This way we
+ // avoid lots of repeated calls to the Selector.applies method.
+ static const int MAX_SELECTORS_NO_CACHE = 8;
+ Map<Element, List<Selector>> cache;
+
+ SelectorMapNode(this.name);
+
+ T lookup(Selector selector) {
+ assert(selector.name == name);
+ return selectors[selector];
+ }
+
+ void update(Selector selector, T value) {
+ assert(selector.name == name);
+ bool existing = selectors.containsKey(selector);
+ selectors[selector] = value;
+ if (existing) return;
+ // The update has introduced a new selector in the map, so we need
+ // to consider if we should start caching. At the very least, we
+ // have to clear the cache because the new element may invalidate
+ // existing cache entries.
+ if (cache == null) {
+ if (selectors.length > MAX_SELECTORS_NO_CACHE) {
+ cache = new Map<Element, List<Selector>>();
+ }
+ } else if (!cache.isEmpty) {
+ cache.clear();
+ }
+ }
+
+ bool containsKey(Selector selector) {
+ assert(selector.name == name);
+ return selectors.containsKey(selector);
+ }
+
+ T remove(Selector selector) {
+ assert(selector.name == name);
+ if (!selectors.containsKey(selector)) return null;
+ if (cache != null && !cache.isEmpty) cache.clear();
+ return selectors.remove(selector);
+ }
+
+ void visitMatching(Element member, Compiler compiler,
+ bool visit(Selector selector, T value)) {
+ assert(member.name == name);
+ Iterable<Selector> matching = computeMatching(member, compiler);
+ for (Selector selector in matching) {
+ if (!visit(selector, selectors[selector])) return;
+ }
+ }
+
+ Iterable<Selector> computeMatching(Element member, Compiler compiler) {
+ // Probe the cache if it exists. Do this before creating the
+ // matching iterable to cut down on the overhead for cache hits.
+ if (cache != null) {
+ List<Selector> cached = cache[member];
+ if (cached != null) return cached;
+ }
+ // Filter the selectors keys so we only have the ones that apply
+ // to the given member element.
+ Iterable<Selector> matching = selectors.keys.where(
+ (Selector selector) => selector.appliesUnnamed(member, compiler));
+ if (cache == null) return matching;
+ return cache[member] = matching.toList();
+ }
}
diff --git a/sdk/lib/_internal/compiler/implementation/universe/universe.dart b/sdk/lib/_internal/compiler/implementation/universe/universe.dart
index 3840965..8f57035 100644
--- a/sdk/lib/_internal/compiler/implementation/universe/universe.dart
+++ b/sdk/lib/_internal/compiler/implementation/universe/universe.dart
@@ -13,7 +13,6 @@
import '../js/js.dart' as js;
part 'function_set.dart';
-part 'partial_type_tree.dart';
part 'selector_map.dart';
class Universe {
diff --git a/sdk/lib/_internal/dartdoc/lib/dartdoc.dart b/sdk/lib/_internal/dartdoc/lib/dartdoc.dart
index 7163496..59ab485 100644
--- a/sdk/lib/_internal/dartdoc/lib/dartdoc.dart
+++ b/sdk/lib/_internal/dartdoc/lib/dartdoc.dart
@@ -157,7 +157,7 @@
/** Package description */
final description;
/** Libraries contained in this package. */
- final List<String> libraries = <String>[];
+ final List<Reference> libraries = <Reference>[];
/**
* Descriptive string describing the version# of the package.
*
@@ -419,11 +419,10 @@
version, revision);
for (final lib in _sortedLibraries) {
- var libraryElement = new LibraryElement(lib.qualifiedName, lib)
+ var libraryElement = new LibraryElement(lib.qualifiedName, lib, lookupMdnComment)
..stripDuplicateUris(null, null);
- packageManifest.libraries.add(libraryElement.id);
+ packageManifest.libraries.add(new Reference.fromElement(libraryElement));
startFile("$revision/${libraryElement.id}.json");
-
write(json_serializer.serialize(libraryElement));
endFile();
}
@@ -439,6 +438,8 @@
write(json_serializer.serialize(packageManifest));
endFile();
}
+
+ MdnComment lookupMdnComment(Mirror mirror) => null;
void startFile(String path) {
_filePath = new Path(path);
@@ -1986,3 +1987,27 @@
String toString() => text;
}
+
+class MdnComment implements DocComment {
+ final String mdnComment;
+ final String mdnUrl;
+
+ MdnComment(String this.mdnComment, String this.mdnUrl);
+
+ String get text => mdnComment;
+
+ ClassMirror get inheritedFrom => null;
+
+ String get html {
+ // Wrap the mdn comment so we can highlight it and so we handle MDN scraped
+ // content that lacks a top-level block tag.
+ return '''
+ <div class="mdn">
+ $mdnComment
+ <div class="mdn-note"><a href="$mdnUrl">from MDN</a></div>
+ </div>
+ ''';
+ }
+
+ String toString() => mdnComment;
+}
diff --git a/sdk/lib/_internal/dartdoc/lib/universe_serializer.dart b/sdk/lib/_internal/dartdoc/lib/universe_serializer.dart
index f2ffbcf..53da583 100755
--- a/sdk/lib/_internal/dartdoc/lib/universe_serializer.dart
+++ b/sdk/lib/_internal/dartdoc/lib/universe_serializer.dart
@@ -24,6 +24,10 @@
}
}
+String _escapeId(String id) {
+ return id.replaceAll(new RegExp('[/]'), '#slash');
+}
+
/**
* Base class for all elements in the AST.
*/
@@ -36,6 +40,14 @@
final String id;
/** Raw text of the comment associated with the Element if any. */
final String comment;
+ /** Raw html comment for the Element from MDN. */
+ String mdnCommentHtml;
+ /**
+ * The URL to the page on MDN that content was pulled from for the current
+ * type being documented. Will be `null` if the type doesn't use any MDN
+ * content.
+ */
+ String mdnUrl;
/** Children of the node. */
List<Element> children;
/** Whether the element is private. */
@@ -50,10 +62,20 @@
*/
String line;
- Element(Mirror mirror, this.kind, this.name, this.id, this.comment)
+ Element(Mirror mirror, this.kind, this.name, String id, this.comment,
+ MdnComment lookupMdnComment(Mirror))
: line = mirror.location.line.toString(),
+ id = _escapeId(id),
isPrivate = _optionalBool(mirror.isPrivate),
- uri = _stripUri(mirror.location.sourceUri.toString());
+ uri = _stripUri(mirror.location.sourceUri.toString()) {
+ if (lookupMdnComment != null) {
+ var mdnComment = lookupMdnComment(mirror);
+ if (mdnComment != null) {
+ mdnCommentHtml = mdnComment.mdnComment;
+ mdnUrl = mdnComment.mdnUrl;
+ }
+ }
+ }
void addChild(Element child) {
if (children == null) {
@@ -97,31 +119,69 @@
* [Element] describing a Dart library.
*/
class LibraryElement extends Element {
- LibraryElement(String name, LibraryMirror mirror)
- : super(mirror, 'library', name, name, computeComment(mirror)) {
-
+ LibraryElement(String name, LibraryMirror mirror,
+ MdnComment lookupMdnComment(Mirror))
+ : super(mirror, 'library', _libraryName(mirror), name,
+ computeComment(mirror), lookupMdnComment) {
+
mirror.functions.forEach((childName, childMirror) {
- addChild(new MethodElement(childName, childMirror));
+ addChild(new MethodElement(childName, childMirror, lookupMdnComment));
});
mirror.getters.forEach((childName, childMirror) {
- addChild(new GetterElement(childName, childMirror));
+ addChild(new GetterElement(childName, childMirror, lookupMdnComment));
});
mirror.variables.forEach((childName, childMirror) {
- addChild(new VariableElement(childName, childMirror));
+ addChild(new VariableElement(childName, childMirror, lookupMdnComment));
});
mirror.classes.forEach((className, classMirror) {
- if (!classMirror.isPrivate) {
- if (classMirror is TypedefMirror) {
- addChild(new TypedefElement(className, classMirror));
- } else {
- addChild(new ClassElement(className, classMirror));
- }
+ if (classMirror is TypedefMirror) {
+ addChild(new TypedefElement(className, classMirror));
+ } else {
+ addChild(new ClassElement(className, classMirror, lookupMdnComment));
}
});
}
+
+ static String _libraryName(LibraryMirror mirror) {
+ if (mirror.uri.scheme == 'file') {
+ // TODO(jacobr): this is a hack. Remove once these libraries are removed
+ // from the sdk.
+ var uri = mirror.uri;
+ var path = uri.path;
+ var pattern = new RegExp(r'[\\/]dart[\\/]pkg[\\/]([^\\/]+)[\\/]lib[\\/](.+)$');
+ var match = pattern.firstMatch(path);
+ var package;
+ if (match != null) {
+ package = match.group(1);
+ path = match.group(2);
+ }
+ // TODO(jacobr): add a second pattern for a more typical pub environment.
+ if (package != null) {
+ return 'package:$package/$path';
+ } else {
+ // TODO(jacobr): this is a lousy fallback.
+ print("Unable to determine package for $path.");
+ return mirror.uri.toString();
+ }
+ } else {
+ return mirror.uri.toString();
+ }
+ }
+}
+
+/**
+ * Returns whether the class implements or extends [Error] or [Exception].
+ */
+bool _isThrowable(ClassMirror mirror) {
+ if (mirror.library.uri.toString() == 'dart:core' &&
+ mirror.simpleName == 'Error' || mirror.simpleName == 'Exception')
+ return true;
+ if (mirror.superclass != null && _isThrowable(mirror.superclass))
+ return true;
+ return mirror.superinterfaces.any(_isThrowable);
}
/**
@@ -134,11 +194,16 @@
final bool isAbstract;
/** Interfaces the class implements. */
List<Reference> interfaces;
+ /** Whether the class implements or extends [Error] or [Exception]. */
+ bool isThrowable;
- ClassElement(String name, ClassMirror mirror)
- : super(mirror, 'class', mirror.simpleName, name, computeComment(mirror)),
+ ClassElement(String name, ClassMirror mirror,
+ MdnComment lookupMdnComment(Mirror))
+ : super(mirror, 'class', mirror.simpleName, name, computeComment(mirror),
+ lookupMdnComment),
superclass = _optionalReference(mirror.superclass),
isAbstract = _optionalBool(mirror.isAbstract) {
+ isThrowable = _optionalBool(_isThrowable(mirror));
for (var interface in mirror.superinterfaces) {
if (this.interfaces == null) {
this.interfaces = <Reference>[];
@@ -148,20 +213,22 @@
mirror.methods.forEach((childName, childMirror) {
if (!childMirror.isConstructor && !childMirror.isGetter) {
- addChild(new MethodElement(childName, childMirror));
+ addChild(new MethodElement(childName, childMirror, lookupMdnComment));
}
});
mirror.getters.forEach((childName, childMirror) {
- addChild(new GetterElement(childName, childMirror));
+ addChild(new GetterElement(childName, childMirror, lookupMdnComment));
});
mirror.variables.forEach((childName, childMirror) {
- addChild(new VariableElement(childName, childMirror));
+ addChild(new VariableElement(childName, childMirror,
+ lookupMdnComment));
});
mirror.constructors.forEach((constructorName, methodMirror) {
- addChild(new MethodElement(constructorName, methodMirror, 'constructor'));
+ addChild(new MethodElement(constructorName, methodMirror,
+ lookupMdnComment, 'constructor'));
});
for (var typeVariable in mirror.originalDeclaration.typeVariables) {
@@ -178,8 +245,10 @@
final Reference ref;
final bool isStatic;
- GetterElement(String name, MethodMirror mirror)
- : super(mirror, 'property', mirror.simpleName, name, computeComment(mirror)),
+ GetterElement(String name, MethodMirror mirror,
+ MdnComment lookupMdnComment(Mirror))
+ : super(mirror, 'property', mirror.simpleName, name, computeComment(mirror),
+ lookupMdnComment),
ref = _optionalReference(mirror.returnType),
isStatic = _optionalBool(mirror.isStatic);
}
@@ -194,9 +263,10 @@
final bool isOperator;
final bool isStatic;
- MethodElement(String name, MethodMirror mirror, [String kind = 'method'])
+ MethodElement(String name, MethodMirror mirror,
+ MdnComment lookupMdnComment(Mirror), [String kind = 'method'])
: super(mirror, kind, name, '$name${mirror.parameters.length}()',
- computeComment(mirror)),
+ computeComment(mirror), lookupMdnComment),
returnType = _optionalReference(mirror.returnType),
isSetter = _optionalBool(mirror.isSetter),
isOperator = _optionalBool(mirror.isOperator),
@@ -214,13 +284,55 @@
class ParameterElement extends Element {
/** Type of the parameter. */
final Reference ref;
- /** Whether the parameter is optional. */
+
+ /**
+ * Returns the default value for this parameter.
+ */
+ final String defaultValue;
+
+ /**
+ * Is this parameter optional?
+ */
final bool isOptional;
+ /**
+ * Is this parameter named?
+ */
+ final bool isNamed;
+
+ /**
+ * Returns the initialized field, if this parameter is an initializing formal.
+ */
+ final Reference initializedField;
+
ParameterElement(ParameterMirror mirror)
- : super(mirror, 'param', mirror.simpleName, mirror.simpleName, null),
+ : super(mirror, 'param', mirror.simpleName, mirror.simpleName, null,
+ null),
ref = _optionalReference(mirror.type),
- isOptional = _optionalBool(mirror.isOptional) {
+ isOptional = _optionalBool(mirror.isOptional),
+ defaultValue = mirror.defaultValue,
+ isNamed = _optionalBool(mirror.isNamed),
+ initializedField = _optionalReference(mirror.initializedField) {
+
+ if (mirror.type is FunctionTypeMirror) {
+ addChild(new FunctionTypeElement(mirror.type));
+ }
+ }
+}
+
+class FunctionTypeElement extends Element {
+ final Reference returnType;
+
+ FunctionTypeElement(FunctionTypeMirror mirror)
+ : super(mirror, 'functiontype', mirror.simpleName, mirror.simpleName, null, null),
+ returnType = _optionalReference(mirror.returnType) {
+ for (var param in mirror.parameters) {
+ addChild(new ParameterElement(param));
+ }
+ // TODO(jacobr): can a FunctionTypeElement really have type variables?
+ for (var typeVariable in mirror.originalDeclaration.typeVariables) {
+ addChild(new TypeParameterElement(typeVariable));
+ }
}
}
@@ -234,10 +346,11 @@
* In the following code sample, [:Bar:] is an upper bound:
* [: class Bar<T extends Foo> { } :]
*/
- Reference upperBound;
+ final Reference upperBound;
TypeParameterElement(TypeMirror mirror)
- : super(mirror, 'typeparam', mirror.simpleName, mirror.simpleName, null),
+ : super(mirror, 'typeparam', mirror.simpleName, mirror.simpleName, null,
+ null),
upperBound = mirror.upperBound != null && !mirror.upperBound.isObject ?
new Reference(mirror.upperBound) : null;
}
@@ -253,8 +366,10 @@
/** Whether the variable is final. */
final bool isFinal;
- VariableElement(String name, VariableMirror mirror)
- : super(mirror, 'variable', mirror.simpleName, name, null),
+ VariableElement(String name, VariableMirror mirror,
+ MdnComment lookupMdnComment(Mirror))
+ : super(mirror, 'variable', mirror.simpleName, name,
+ computeComment(mirror), lookupMdnComment),
ref = _optionalReference(mirror.type),
isStatic = _optionalBool(mirror.isStatic),
isFinal = _optionalBool(mirror.isFinal);
@@ -270,7 +385,7 @@
TypedefElement(String name, TypedefMirror mirror)
: super(mirror, 'typedef', mirror.simpleName, name,
- computeComment(mirror)),
+ computeComment(mirror), null),
returnType = _optionalReference(mirror.value.returnType) {
for (var param in mirror.value.parameters) {
addChild(new ParameterElement(param));
@@ -301,9 +416,13 @@
}
}
}
+
+ // TODO(jacobr): compute the referenceId correctly for the general case so
+ // that this method can work with all element types not just LibraryElements.
+ Reference.fromElement(LibraryElement e) : name = e.name, refId = e.id;
static String getId(Mirror mirror) {
- String id = mirror.simpleName;
+ String id = _escapeId(mirror.simpleName);
if (mirror.owner != null) {
id = '${getId(mirror.owner)}/$id';
}
diff --git a/sdk/lib/async/future.dart b/sdk/lib/async/future.dart
index efa4144..820ba00 100644
--- a/sdk/lib/async/future.dart
+++ b/sdk/lib/async/future.dart
@@ -137,19 +137,29 @@
/**
* Creates a future that completes after a delay.
*
- * The future will be completed after [milliseconds] have passed with
- * the result of calling [value]. If [milliseconds] is 0, it completes at the
- * earliest in the next event-loop iteration.
+ * The future will be completed after the given [duration] has passed with
+ * the result of calling [computation]. If the duration is 0 or less, it
+ * completes no sooner than in the next event-loop iteration.
*
- * If calling [value] throws, the created future will complete with the
+ * If [computation] is not given or [:null:] then it will behave as if
+ * [computation] was set to [:() => null:]. That is, it will complete with
+ * [:null:].
+ *
+ * If calling [computation] throws, the created future will complete with the
* error.
*
* See [Completer]s, for futures with values that are computed asynchronously.
+ *
+ * *Deprecation note*: this method initially took an [int] as argument (the
+ * milliseconds to wait). It is now a [Duration].
*/
- factory Future.delayed(int milliseconds, T value()) {
+ factory Future.delayed(var duration, [T computation()]) {
+ // TODO(floitsch): no need to allocate a ThenFuture when the computation is
+ // null.
+ if (computation == null) computation = (() => null);
_ThenFuture<dynamic, T> future =
- new _ThenFuture<dynamic, T>((_) => value());
- new Timer(milliseconds, (_) => future._sendValue(null));
+ new _ThenFuture<dynamic, T>((_) => computation());
+ new Timer(duration, () => future._sendValue(null));
return future;
}
diff --git a/sdk/lib/core/duration.dart b/sdk/lib/core/duration.dart
index af79aeb..9e7cdd8 100644
--- a/sdk/lib/core/duration.dart
+++ b/sdk/lib/core/duration.dart
@@ -25,6 +25,8 @@
static const int MINUTES_PER_DAY = MINUTES_PER_HOUR * HOURS_PER_DAY;
+ static const Duration ZERO = const Duration(seconds: 0);
+
/**
* This [Duration] in milliseconds.
*/
diff --git a/sdk/lib/core/string.dart b/sdk/lib/core/string.dart
index 3584db5..4e5b950 100644
--- a/sdk/lib/core/string.dart
+++ b/sdk/lib/core/string.dart
@@ -449,7 +449,6 @@
return string.substring(_position, _nextPosition);
}
-
bool moveNext() {
_position = _nextPosition;
if (_position == string.length) {
@@ -492,3 +491,16 @@
return true;
}
}
+
+/**
+ * An [Iterable] of the UTF-16 code units of a [String] in index order.
+ */
+class CodeUnits extends ListIterable<int> {
+ /** The string that this is the code units of. */
+ String string;
+
+ CodeUnits(this.string);
+
+ int get length => string.length;
+ int elementAt(int i) => string.codeUnitAt(i);
+}
diff --git a/sdk/lib/html/dart2js/html_dart2js.dart b/sdk/lib/html/dart2js/html_dart2js.dart
index 2faa94c..71f7cce 100644
--- a/sdk/lib/html/dart2js/html_dart2js.dart
+++ b/sdk/lib/html/dart2js/html_dart2js.dart
@@ -72,12 +72,6 @@
@DocsEditable
static const EventStreamProvider<Event> errorEvent = const EventStreamProvider<Event>('error');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- AbstractWorkerEvents get on =>
- new AbstractWorkerEvents(this);
-
@JSName('addEventListener')
@DomName('AbstractWorker.addEventListener')
@DocsEditable
@@ -96,16 +90,6 @@
@DocsEditable
Stream<Event> get onError => errorEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class AbstractWorkerEvents extends Events {
- @DocsEditable
- AbstractWorkerEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get error => this['error'];
-}
// 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.
@@ -257,12 +241,6 @@
/// Checks if this type is supported on the current platform.
static bool get supported => JS('bool', '!!(window.applicationCache)');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- ApplicationCacheEvents get on =>
- new ApplicationCacheEvents(this);
-
static const int CHECKING = 2;
static const int DOWNLOADING = 3;
@@ -337,37 +315,6 @@
@DocsEditable
Stream<Event> get onUpdateReady => updateReadyEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class ApplicationCacheEvents extends Events {
- @DocsEditable
- ApplicationCacheEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get cached => this['cached'];
-
- @DocsEditable
- EventListenerList get checking => this['checking'];
-
- @DocsEditable
- EventListenerList get downloading => this['downloading'];
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get noUpdate => this['noupdate'];
-
- @DocsEditable
- EventListenerList get obsolete => this['obsolete'];
-
- @DocsEditable
- EventListenerList get progress => this['progress'];
-
- @DocsEditable
- EventListenerList get updateReady => this['updateready'];
-}
// 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.
@@ -624,12 +571,6 @@
@DocsEditable
static const EventStreamProvider<Event> levelChangeEvent = const EventStreamProvider<Event>('levelchange');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- BatteryManagerEvents get on =>
- new BatteryManagerEvents(this);
-
@DomName('BatteryManager.charging')
@DocsEditable
final bool charging;
@@ -676,25 +617,6 @@
@DocsEditable
Stream<Event> get onLevelChange => levelChangeEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class BatteryManagerEvents extends Events {
- @DocsEditable
- BatteryManagerEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get chargingChange => this['chargingchange'];
-
- @DocsEditable
- EventListenerList get chargingTimeChange => this['chargingtimechange'];
-
- @DocsEditable
- EventListenerList get dischargingTimeChange => this['dischargingtimechange'];
-
- @DocsEditable
- EventListenerList get levelChange => this['levelchange'];
-}
// 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.
@@ -813,12 +735,6 @@
@DocsEditable
factory BodyElement() => document.$dom_createElement("body");
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- BodyElementEvents get on =>
- new BodyElementEvents(this);
-
@DomName('HTMLBodyElement.onbeforeunload')
@DocsEditable
Stream<Event> get onBeforeUnload => beforeUnloadEvent.forTarget(this);
@@ -871,52 +787,6 @@
@DocsEditable
Stream<Event> get onUnload => unloadEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class BodyElementEvents extends ElementEvents {
- @DocsEditable
- BodyElementEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get beforeUnload => this['beforeunload'];
-
- @DocsEditable
- EventListenerList get blur => this['blur'];
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get focus => this['focus'];
-
- @DocsEditable
- EventListenerList get hashChange => this['hashchange'];
-
- @DocsEditable
- EventListenerList get load => this['load'];
-
- @DocsEditable
- EventListenerList get message => this['message'];
-
- @DocsEditable
- EventListenerList get offline => this['offline'];
-
- @DocsEditable
- EventListenerList get online => this['online'];
-
- @DocsEditable
- EventListenerList get popState => this['popstate'];
-
- @DocsEditable
- EventListenerList get resize => this['resize'];
-
- @DocsEditable
- EventListenerList get storage => this['storage'];
-
- @DocsEditable
- EventListenerList get unload => this['unload'];
-}
// 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.
@@ -6169,12 +6039,6 @@
@DocsEditable
static const EventStreamProvider<MessageEvent> messageEvent = const EventStreamProvider<MessageEvent>('message');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- DedicatedWorkerContextEvents get on =>
- new DedicatedWorkerContextEvents(this);
-
@DomName('DedicatedWorkerContext.postMessage')
@DocsEditable
void postMessage(/*any*/ message, [List messagePorts]) {
@@ -6200,16 +6064,6 @@
@DocsEditable
Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class DedicatedWorkerContextEvents extends WorkerContextEvents {
- @DocsEditable
- DedicatedWorkerContextEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get message => this['message'];
-}
// 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.
@@ -6521,12 +6375,6 @@
@Experimental
static const EventStreamProvider<Event> pointerLockErrorEvent = const EventStreamProvider<Event>('webkitpointerlockerror');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- DocumentEvents get on =>
- new DocumentEvents(this);
-
@JSName('body')
/// Moved to [HtmlDocument].
@DomName('Document.body')
@@ -7079,25 +6927,6 @@
}
}
}
-
-@DocsEditable
-@deprecated
-class DocumentEvents extends ElementEvents {
- @DocsEditable
- DocumentEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get readyStateChange => this['readystatechange'];
-
- @DocsEditable
- EventListenerList get selectionChange => this['selectionchange'];
-
- @DocsEditable
- EventListenerList get pointerLockChange => this['webkitpointerlockchange'];
-
- @DocsEditable
- EventListenerList get pointerLockError => this['webkitpointerlockerror'];
-}
// 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.
@@ -7183,12 +7012,6 @@
}
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- ElementEvents get on =>
- new ElementEvents(this);
-
@JSName('querySelector')
@DomName('DocumentFragment.querySelector')
@DocsEditable
@@ -8967,6 +8790,42 @@
@Creates('Null') // Set from Dart code; does not instantiate a native type.
var xtag;
+ /**
+ * Scrolls this element into view.
+ *
+ * Only one of of the alignment options may be specified at a time.
+ *
+ * If no options are specified then this will attempt to scroll the minimum
+ * amount needed to bring the element into view.
+ *
+ * Note that alignCenter is currently only supported on WebKit platforms. If
+ * alignCenter is specified but not supported then this will fall back to
+ * alignTop.
+ *
+ * See also:
+ *
+ * * [scrollIntoView](http://docs.webplatform.org/wiki/dom/methods/scrollIntoView)
+ * * [scrollIntoViewIfNeeded](http://docs.webplatform.org/wiki/dom/methods/scrollIntoViewIfNeeded)
+ */
+ void scrollIntoView([ScrollAlignment alignment]) {
+ var hasScrollIntoViewIfNeeded = false;
+ hasScrollIntoViewIfNeeded =
+ JS('bool', '!!(#.scrollIntoViewIfNeeded)', this);
+ if (alignment == ScrollAlignment.TOP) {
+ this.$dom_scrollIntoView(true);
+ } else if (alignment == ScrollAlignment.BOTTOM) {
+ this.$dom_scrollIntoView(false);
+ } else if (hasScrollIntoViewIfNeeded) {
+ if (alignment == ScrollAlignment.CENTER) {
+ this.$dom_scrollIntoViewIfNeeded(true);
+ } else {
+ this.$dom_scrollIntoViewIfNeeded();
+ }
+ } else {
+ this.$dom_scrollIntoView();
+ }
+ }
+
@DomName('Element.mouseWheelEvent')
static const EventStreamProvider<WheelEvent> mouseWheelEvent =
const _CustomEventStreamProvider<WheelEvent>(
@@ -9303,12 +9162,6 @@
@Experimental
static const EventStreamProvider<Event> fullscreenErrorEvent = const EventStreamProvider<Event>('webkitfullscreenerror');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- ElementEvents get on =>
- new ElementEvents(this);
-
@JSName('children')
@DomName('Element.children')
@DocsEditable
@@ -9572,10 +9425,15 @@
@DocsEditable
void scrollByPages(int pages) native;
+ @JSName('scrollIntoView')
+ @DomName('Element.scrollIntoView')
+ @DocsEditable
+ void $dom_scrollIntoView([bool alignWithTop]) native;
+
@JSName('scrollIntoViewIfNeeded')
@DomName('Element.scrollIntoViewIfNeeded')
@DocsEditable
- void scrollIntoView([bool centerIfNeeded]) native;
+ void $dom_scrollIntoViewIfNeeded([bool centerIfNeeded]) native;
@JSName('setAttribute')
@DomName('Element.setAttribute')
@@ -9949,165 +9807,22 @@
// Firefox may return a JS function for some types (Embed, Object).
JS('Element|=Object', 'document.createElement(#)', tag);
}
-// 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.
-@deprecated
-class ElementEvents extends Events {
- ElementEvents(EventTarget _ptr) : super(_ptr);
+/**
+ * Options for Element.scrollIntoView.
+ */
+class ScrollAlignment {
+ final _value;
+ const ScrollAlignment._internal(this._value);
+ toString() => 'ScrollAlignment.$_value';
- @DocsEditable
- EventListenerList get abort => this['abort'];
-
- @DocsEditable
- EventListenerList get beforeCopy => this['beforecopy'];
-
- @DocsEditable
- EventListenerList get beforeCut => this['beforecut'];
-
- @DocsEditable
- EventListenerList get beforePaste => this['beforepaste'];
-
- @DocsEditable
- EventListenerList get blur => this['blur'];
-
- @DocsEditable
- EventListenerList get change => this['change'];
-
- @DocsEditable
- EventListenerList get click => this['click'];
-
- @DocsEditable
- EventListenerList get contextMenu => this['contextmenu'];
-
- @DocsEditable
- EventListenerList get copy => this['copy'];
-
- @DocsEditable
- EventListenerList get cut => this['cut'];
-
- @DocsEditable
- EventListenerList get doubleClick => this['dblclick'];
-
- @DocsEditable
- EventListenerList get drag => this['drag'];
-
- @DocsEditable
- EventListenerList get dragEnd => this['dragend'];
-
- @DocsEditable
- EventListenerList get dragEnter => this['dragenter'];
-
- @DocsEditable
- EventListenerList get dragLeave => this['dragleave'];
-
- @DocsEditable
- EventListenerList get dragOver => this['dragover'];
-
- @DocsEditable
- EventListenerList get dragStart => this['dragstart'];
-
- @DocsEditable
- EventListenerList get drop => this['drop'];
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get focus => this['focus'];
-
- @DocsEditable
- EventListenerList get input => this['input'];
-
- @DocsEditable
- EventListenerList get invalid => this['invalid'];
-
- @DocsEditable
- EventListenerList get keyDown => this['keydown'];
-
- @DocsEditable
- EventListenerList get keyPress => this['keypress'];
-
- @DocsEditable
- EventListenerList get keyUp => this['keyup'];
-
- @DocsEditable
- EventListenerList get load => this['load'];
-
- @DocsEditable
- EventListenerList get mouseDown => this['mousedown'];
-
- @DocsEditable
- EventListenerList get mouseMove => this['mousemove'];
-
- @DocsEditable
- EventListenerList get mouseOut => this['mouseout'];
-
- @DocsEditable
- EventListenerList get mouseOver => this['mouseover'];
-
- @DocsEditable
- EventListenerList get mouseUp => this['mouseup'];
-
- @DocsEditable
- EventListenerList get paste => this['paste'];
-
- @DocsEditable
- EventListenerList get reset => this['reset'];
-
- @DocsEditable
- EventListenerList get scroll => this['scroll'];
-
- @DocsEditable
- EventListenerList get search => this['search'];
-
- @DocsEditable
- EventListenerList get select => this['select'];
-
- @DocsEditable
- EventListenerList get selectStart => this['selectstart'];
-
- @DocsEditable
- EventListenerList get submit => this['submit'];
-
- @DocsEditable
- EventListenerList get touchCancel => this['touchcancel'];
-
- @DocsEditable
- EventListenerList get touchEnd => this['touchend'];
-
- @DocsEditable
- EventListenerList get touchEnter => this['touchenter'];
-
- @DocsEditable
- EventListenerList get touchLeave => this['touchleave'];
-
- @DocsEditable
- EventListenerList get touchMove => this['touchmove'];
-
- @DocsEditable
- EventListenerList get touchStart => this['touchstart'];
-
- @DocsEditable
- EventListenerList get fullscreenChange => this['webkitfullscreenchange'];
-
- @DocsEditable
- EventListenerList get fullscreenError => this['webkitfullscreenerror'];
-
- EventListenerList get mouseWheel {
- if (JS('bool', '#.onwheel !== undefined', _ptr)) {
- // W3C spec, and should be IE9+, but IE has a bug exposing onwheel.
- return this['wheel'];
- } else if (JS('bool', '#.onmousewheel !== undefined', _ptr)) {
- // Chrome & IE
- return this['mousewheel'];
- } else {
- // Firefox
- return this['DOMMouseScroll'];
- }
- }
+ /// Attempt to align the element to the top of the scrollable area.
+ static const TOP = const ScrollAlignment._internal('TOP');
+ /// Attempt to center the element in the scrollable area.
+ static const CENTER = const ScrollAlignment._internal('CENTER');
+ /// Attempt to align the element to the bottom of the scrollable area.
+ static const BOTTOM = const ScrollAlignment._internal('BOTTOM');
}
// 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
@@ -10551,12 +10266,6 @@
static EventSource _create_1(url, eventSourceInit) => JS('EventSource', 'new EventSource(#,#)', url, eventSourceInit);
static EventSource _create_2(url) => JS('EventSource', 'new EventSource(#)', url);
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- EventSourceEvents get on =>
- new EventSourceEvents(this);
-
static const int CLOSED = 2;
static const int CONNECTING = 0;
@@ -10605,22 +10314,6 @@
@DocsEditable
Stream<Event> get onOpen => openEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class EventSourceEvents extends Events {
- @DocsEditable
- EventSourceEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get message => this['message'];
-
- @DocsEditable
- EventListenerList get open => this['open'];
-}
// 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.
@@ -10629,15 +10322,38 @@
/**
* Base class that supports listening for and dispatching browser events.
*
- * Events can either be accessed by string name (using the indexed getter) or by
- * getters exposed by subclasses. Use the getters exposed by subclasses when
- * possible for better compile-time type checks.
+ * Normally events are accessed via the Stream getter:
*
- * Using an indexed getter:
- * events['mouseover'].add((e) => print("Mouse over!"));
+ * element.onMouseOver.listen((e) => print('Mouse over!'));
*
- * Using a getter provided by a subclass:
- * elementEvents.mouseOver.add((e) => print("Mouse over!"));
+ * To access bubbling events which are declared on one element, but may bubble
+ * up to another element type (common for MediaElement events):
+ *
+ * MediaElement.pauseEvent.forTarget(document.body).listen(...);
+ *
+ * To useCapture on events:
+ *
+ * Element.keyDownEvent.forTarget(element, useCapture: true).listen(...);
+ *
+ * Custom events can be declared as:
+ *
+ * class DataGenerator {
+ * static EventStreamProvider<Event> dataEvent =
+ * new EventStreamProvider('data');
+ * }
+ *
+ * Then listeners should access the event with:
+ *
+ * DataGenerator.dataEvent.forTarget(element).listen(...);
+ *
+ * Custom events can also be accessed as:
+ *
+ * element.on['some_event'].listen(...);
+ *
+ * This approach is generally discouraged as it loses the event typing and
+ * some DOM events may have multiple platform-dependent event names under the
+ * covers. By using the standard Stream getters you will get the platform
+ * specific event name automatically.
*/
class Events {
/* Raw event target. */
@@ -10645,60 +10361,25 @@
Events(this._ptr);
- EventListenerList operator [](String type) {
- return new EventListenerList(_ptr, type);
- }
-}
-
-/**
- * Supports adding, removing, and dispatching events for a specific event type.
- */
-class EventListenerList {
-
- final EventTarget _ptr;
- final String _type;
-
- EventListenerList(this._ptr, this._type);
-
- // TODO(jacobr): implement equals.
-
- EventListenerList add(EventListener listener,
- [bool useCapture = false]) {
- _add(listener, useCapture);
- return this;
- }
-
- EventListenerList remove(EventListener listener,
- [bool useCapture = false]) {
- _remove(listener, useCapture);
- return this;
- }
-
- bool dispatch(Event evt) {
- return _ptr.dispatchEvent(evt);
- }
-
- void _add(EventListener listener, bool useCapture) {
- _ptr.$dom_addEventListener(_type, listener, useCapture);
- }
-
- void _remove(EventListener listener, bool useCapture) {
- _ptr.$dom_removeEventListener(_type, listener, useCapture);
+ Stream operator [](String type) {
+ return new _EventStream(_ptr, type, false);
}
}
/**
* Base class for all browser objects that support events.
*
- * Use the [on] property to add, remove, and dispatch events (rather than
- * [$dom_addEventListener], [$dom_dispatchEvent], and
- * [$dom_removeEventListener]) for compile-time type checks and a more concise
- * API.
+ * Use the [on] property to add, and remove events (rather than
+ * [$dom_addEventListener] and [$dom_removeEventListener]
+ * for compile-time type checks and a more concise API.
*/
@DomName('EventTarget')
class EventTarget native "*EventTarget" {
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
+ /**
+ * This is an ease-of-use accessor for event streams which should only be
+ * used when an explicit accessor is not available.
+ */
Events get on => new Events(this);
@JSName('addEventListener')
@@ -11175,12 +10856,6 @@
}
static FileReader _create_1() => JS('FileReader', 'new FileReader()');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- FileReaderEvents get on =>
- new FileReaderEvents(this);
-
static const int DONE = 2;
static const int EMPTY = 0;
@@ -11259,31 +10934,6 @@
@DocsEditable
Stream<ProgressEvent> get onProgress => progressEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class FileReaderEvents extends Events {
- @DocsEditable
- FileReaderEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get abort => this['abort'];
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get load => this['load'];
-
- @DocsEditable
- EventListenerList get loadEnd => this['loadend'];
-
- @DocsEditable
- EventListenerList get loadStart => this['loadstart'];
-
- @DocsEditable
- EventListenerList get progress => this['progress'];
-}
// 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.
@@ -11324,6 +10974,8 @@
@DocsEditable
@DomName('DOMFileSystem')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@Experimental
class FileSystem native "*DOMFileSystem" {
/// Checks if this type is supported on the current platform.
@@ -11352,6 +11004,8 @@
@DocsEditable
@DomName('DOMFileSystemSync')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@Experimental
class FileSystemSync native "*DOMFileSystemSync" {
@DomName('DOMFileSystemSync.name')
@@ -11395,12 +11049,6 @@
@DocsEditable
static const EventStreamProvider<ProgressEvent> writeStartEvent = const EventStreamProvider<ProgressEvent>('writestart');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- FileWriterEvents get on =>
- new FileWriterEvents(this);
-
static const int DONE = 2;
static const int INIT = 0;
@@ -11477,31 +11125,6 @@
@DocsEditable
Stream<ProgressEvent> get onWriteStart => writeStartEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class FileWriterEvents extends Events {
- @DocsEditable
- FileWriterEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get abort => this['abort'];
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get progress => this['progress'];
-
- @DocsEditable
- EventListenerList get write => this['write'];
-
- @DocsEditable
- EventListenerList get writeEnd => this['writeend'];
-
- @DocsEditable
- EventListenerList get writeStart => this['writestart'];
-}
// 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.
@@ -13062,12 +12685,6 @@
}
static HttpRequest _create_1() => JS('HttpRequest', 'new XMLHttpRequest()');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- HttpRequestEvents get on =>
- new HttpRequestEvents(this);
-
static const int DONE = 4;
static const int HEADERS_RECEIVED = 2;
@@ -13342,34 +12959,6 @@
Stream<ProgressEvent> get onReadyStateChange => readyStateChangeEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class HttpRequestEvents extends Events {
- @DocsEditable
- HttpRequestEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get abort => this['abort'];
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get load => this['load'];
-
- @DocsEditable
- EventListenerList get loadEnd => this['loadend'];
-
- @DocsEditable
- EventListenerList get loadStart => this['loadstart'];
-
- @DocsEditable
- EventListenerList get progress => this['progress'];
-
- @DocsEditable
- EventListenerList get readyStateChange => this['readystatechange'];
-}
// 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.
@@ -13455,12 +13044,6 @@
@DocsEditable
static const EventStreamProvider<ProgressEvent> progressEvent = const EventStreamProvider<ProgressEvent>('progress');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- HttpRequestUploadEvents get on =>
- new HttpRequestUploadEvents(this);
-
@JSName('addEventListener')
@DomName('XMLHttpRequestUpload.addEventListener')
@DocsEditable
@@ -13499,31 +13082,6 @@
@DocsEditable
Stream<ProgressEvent> get onProgress => progressEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class HttpRequestUploadEvents extends Events {
- @DocsEditable
- HttpRequestUploadEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get abort => this['abort'];
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get load => this['load'];
-
- @DocsEditable
- EventListenerList get loadEnd => this['loadend'];
-
- @DocsEditable
- EventListenerList get loadStart => this['loadstart'];
-
- @DocsEditable
- EventListenerList get progress => this['progress'];
-}
// 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.
@@ -13715,12 +13273,6 @@
@Experimental
static const EventStreamProvider<Event> speechChangeEvent = const EventStreamProvider<Event>('webkitSpeechChange');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- InputElementEvents get on =>
- new InputElementEvents(this);
-
@DomName('HTMLInputElement.accept')
@DocsEditable
String accept;
@@ -14554,16 +14106,6 @@
factory ButtonInputElement() => new InputElement(type: 'button');
}
-
-@DocsEditable
-@deprecated
-class InputElementEvents extends ElementEvents {
- @DocsEditable
- InputElementEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get speechChange => this['webkitSpeechChange'];
-}
// 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.
@@ -15853,12 +15395,6 @@
@Experimental
static const EventStreamProvider<MediaKeyEvent> needKeyEvent = const EventStreamProvider<MediaKeyEvent>('webkitneedkey');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- MediaElementEvents get on =>
- new MediaElementEvents(this);
-
static const int HAVE_CURRENT_DATA = 2;
static const int HAVE_ENOUGH_DATA = 4;
@@ -16169,88 +15705,6 @@
@DocsEditable
Stream<MediaKeyEvent> get onNeedKey => needKeyEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class MediaElementEvents extends ElementEvents {
- @DocsEditable
- MediaElementEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get canPlay => this['canplay'];
-
- @DocsEditable
- EventListenerList get canPlayThrough => this['canplaythrough'];
-
- @DocsEditable
- EventListenerList get durationChange => this['durationchange'];
-
- @DocsEditable
- EventListenerList get emptied => this['emptied'];
-
- @DocsEditable
- EventListenerList get ended => this['ended'];
-
- @DocsEditable
- EventListenerList get loadedData => this['loadeddata'];
-
- @DocsEditable
- EventListenerList get loadedMetadata => this['loadedmetadata'];
-
- @DocsEditable
- EventListenerList get loadStart => this['loadstart'];
-
- @DocsEditable
- EventListenerList get pause => this['pause'];
-
- @DocsEditable
- EventListenerList get play => this['play'];
-
- @DocsEditable
- EventListenerList get playing => this['playing'];
-
- @DocsEditable
- EventListenerList get progress => this['progress'];
-
- @DocsEditable
- EventListenerList get rateChange => this['ratechange'];
-
- @DocsEditable
- EventListenerList get seeked => this['seeked'];
-
- @DocsEditable
- EventListenerList get seeking => this['seeking'];
-
- @DocsEditable
- EventListenerList get show => this['show'];
-
- @DocsEditable
- EventListenerList get stalled => this['stalled'];
-
- @DocsEditable
- EventListenerList get suspend => this['suspend'];
-
- @DocsEditable
- EventListenerList get timeUpdate => this['timeupdate'];
-
- @DocsEditable
- EventListenerList get volumeChange => this['volumechange'];
-
- @DocsEditable
- EventListenerList get waiting => this['waiting'];
-
- @DocsEditable
- EventListenerList get keyAdded => this['webkitkeyadded'];
-
- @DocsEditable
- EventListenerList get keyError => this['webkitkeyerror'];
-
- @DocsEditable
- EventListenerList get keyMessage => this['webkitkeymessage'];
-
- @DocsEditable
- EventListenerList get needKey => this['webkitneedkey'];
-}
// 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.
@@ -16469,10 +15923,18 @@
@Experimental
class MediaStream extends EventTarget native "*MediaStream" {
+ @DomName('MediaStream.addtrackEvent')
+ @DocsEditable
+ static const EventStreamProvider<Event> addTrackEvent = const EventStreamProvider<Event>('addtrack');
+
@DomName('MediaStream.endedEvent')
@DocsEditable
static const EventStreamProvider<Event> endedEvent = const EventStreamProvider<Event>('ended');
+ @DomName('MediaStream.removetrackEvent')
+ @DocsEditable
+ static const EventStreamProvider<Event> removeTrackEvent = const EventStreamProvider<Event>('removetrack');
+
@DomName('MediaStream.MediaStream')
@DocsEditable
factory MediaStream([stream_OR_tracks]) {
@@ -16491,12 +15953,6 @@
static MediaStream _create_2(stream_OR_tracks) => JS('MediaStream', 'new MediaStream(#)', stream_OR_tracks);
static MediaStream _create_3(stream_OR_tracks) => JS('MediaStream', 'new MediaStream(#)', stream_OR_tracks);
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- MediaStreamEvents get on =>
- new MediaStreamEvents(this);
-
@DomName('MediaStream.ended')
@DocsEditable
final bool ended;
@@ -16543,10 +15999,18 @@
@DocsEditable
void removeTrack(MediaStreamTrack track) native;
+ @DomName('MediaStream.onaddtrack')
+ @DocsEditable
+ Stream<Event> get onAddTrack => addTrackEvent.forTarget(this);
+
@DomName('MediaStream.onended')
@DocsEditable
Stream<Event> get onEnded => endedEvent.forTarget(this);
+ @DomName('MediaStream.onremovetrack')
+ @DocsEditable
+ Stream<Event> get onRemoveTrack => removeTrackEvent.forTarget(this);
+
/**
* Checks if the MediaStream APIs are supported on the current platform.
@@ -16563,22 +16027,6 @@
window.navigator,
window.navigator);
}
-
-@DocsEditable
-@deprecated
-class MediaStreamEvents extends Events {
- @DocsEditable
- MediaStreamEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get addTrack => this['addtrack'];
-
- @DocsEditable
- EventListenerList get ended => this['ended'];
-
- @DocsEditable
- EventListenerList get removeTrack => this['removetrack'];
-}
// 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.
@@ -16620,12 +16068,6 @@
@DocsEditable
static const EventStreamProvider<Event> unmuteEvent = const EventStreamProvider<Event>('unmute');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- MediaStreamTrackEvents get on =>
- new MediaStreamTrackEvents(this);
-
@DomName('MediaStreamTrack.enabled')
@DocsEditable
bool enabled;
@@ -16672,22 +16114,6 @@
@DocsEditable
Stream<Event> get onUnmute => unmuteEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class MediaStreamTrackEvents extends Events {
- @DocsEditable
- MediaStreamTrackEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get ended => this['ended'];
-
- @DocsEditable
- EventListenerList get mute => this['mute'];
-
- @DocsEditable
- EventListenerList get unmute => this['unmute'];
-}
// 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.
@@ -16844,12 +16270,6 @@
@DocsEditable
static const EventStreamProvider<MessageEvent> messageEvent = const EventStreamProvider<MessageEvent>('message');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- MessagePortEvents get on =>
- new MessagePortEvents(this);
-
@JSName('addEventListener')
@DomName('MessagePort.addEventListener')
@DocsEditable
@@ -16897,16 +16317,6 @@
@DocsEditable
Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class MessagePortEvents extends Events {
- @DocsEditable
- MessagePortEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get message => this['message'];
-}
// 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.
@@ -18300,12 +17710,6 @@
@DocsEditable
static const EventStreamProvider<Event> showEvent = const EventStreamProvider<Event>('show');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- NotificationEvents get on =>
- new NotificationEvents(this);
-
@DomName('Notification.dir')
@DocsEditable
String dir;
@@ -18373,28 +17777,6 @@
Stream<Event> get onShow => showEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class NotificationEvents extends Events {
- @DocsEditable
- NotificationEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get click => this['click'];
-
- @DocsEditable
- EventListenerList get close => this['close'];
-
- @DocsEditable
- EventListenerList get display => this['display'];
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get show => this['show'];
-}
// 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.
@@ -19459,12 +18841,6 @@
@DocsEditable
static const EventStreamProvider<Event> openEvent = const EventStreamProvider<Event>('open');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- RtcDataChannelEvents get on =>
- new RtcDataChannelEvents(this);
-
@DomName('RTCDataChannel.binaryType')
@DocsEditable
String binaryType;
@@ -19523,25 +18899,6 @@
@DocsEditable
Stream<Event> get onOpen => openEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class RtcDataChannelEvents extends Events {
- @DocsEditable
- RtcDataChannelEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get close => this['close'];
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get message => this['message'];
-
- @DocsEditable
- EventListenerList get open => this['open'];
-}
// 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.
@@ -19641,6 +18998,10 @@
@DocsEditable
static const EventStreamProvider<RtcDataChannelEvent> dataChannelEvent = const EventStreamProvider<RtcDataChannelEvent>('datachannel');
+ @DomName('RTCPeerConnection.gatheringchangeEvent')
+ @DocsEditable
+ static const EventStreamProvider<Event> gatheringChangeEvent = const EventStreamProvider<Event>('gatheringchange');
+
@DomName('RTCPeerConnection.icecandidateEvent')
@DocsEditable
static const EventStreamProvider<RtcIceCandidateEvent> iceCandidateEvent = const EventStreamProvider<RtcIceCandidateEvent>('icecandidate');
@@ -19661,12 +19022,6 @@
@DocsEditable
static const EventStreamProvider<Event> stateChangeEvent = const EventStreamProvider<Event>('statechange');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- RtcPeerConnectionEvents get on =>
- new RtcPeerConnectionEvents(this);
-
@DomName('RTCPeerConnection.iceConnectionState')
@DocsEditable
final String iceConnectionState;
@@ -19857,6 +19212,10 @@
@DocsEditable
Stream<RtcDataChannelEvent> get onDataChannel => dataChannelEvent.forTarget(this);
+ @DomName('RTCPeerConnection.ongatheringchange')
+ @DocsEditable
+ Stream<Event> get onGatheringChange => gatheringChangeEvent.forTarget(this);
+
@DomName('RTCPeerConnection.onicecandidate')
@DocsEditable
Stream<RtcIceCandidateEvent> get onIceCandidate => iceCandidateEvent.forTarget(this);
@@ -19880,31 +19239,6 @@
}
-
-@DocsEditable
-@deprecated
-class RtcPeerConnectionEvents extends Events {
- @DocsEditable
- RtcPeerConnectionEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get addStream => this['addstream'];
-
- @DocsEditable
- EventListenerList get iceCandidate => this['icecandidate'];
-
- @DocsEditable
- EventListenerList get iceChange => this['icechange'];
-
- @DocsEditable
- EventListenerList get negotiationNeeded => this['negotiationneeded'];
-
- @DocsEditable
- EventListenerList get removeStream => this['removestream'];
-
- @DocsEditable
- EventListenerList get stateChange => this['statechange'];
-}
// 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.
@@ -20409,12 +19743,6 @@
@DocsEditable
static const EventStreamProvider<Event> connectEvent = const EventStreamProvider<Event>('connect');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- SharedWorkerContextEvents get on =>
- new SharedWorkerContextEvents(this);
-
@DomName('SharedWorkerContext.name')
@DocsEditable
final String name;
@@ -20423,16 +19751,6 @@
@DocsEditable
Stream<Event> get onConnect => connectEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class SharedWorkerContextEvents extends WorkerContextEvents {
- @DocsEditable
- SharedWorkerContextEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get connect => this['connect'];
-}
// 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.
@@ -21038,12 +20356,6 @@
/// Checks if this type is supported on the current platform.
static bool get supported => JS('bool', '!!(window.SpeechRecognition || window.webkitSpeechRecognition)');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- SpeechRecognitionEvents get on =>
- new SpeechRecognitionEvents(this);
-
@DomName('SpeechRecognition.continuous')
@DocsEditable
bool continuous;
@@ -21139,46 +20451,6 @@
'new (window.SpeechRecognition || window.webkitSpeechRecognition)()');
}
}
-
-@DocsEditable
-@deprecated
-class SpeechRecognitionEvents extends Events {
- @DocsEditable
- SpeechRecognitionEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get audioEnd => this['audioend'];
-
- @DocsEditable
- EventListenerList get audioStart => this['audiostart'];
-
- @DocsEditable
- EventListenerList get end => this['end'];
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get noMatch => this['nomatch'];
-
- @DocsEditable
- EventListenerList get result => this['result'];
-
- @DocsEditable
- EventListenerList get soundEnd => this['soundend'];
-
- @DocsEditable
- EventListenerList get soundStart => this['soundstart'];
-
- @DocsEditable
- EventListenerList get speechEnd => this['speechend'];
-
- @DocsEditable
- EventListenerList get speechStart => this['speechstart'];
-
- @DocsEditable
- EventListenerList get start => this['start'];
-}
// 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.
@@ -22295,12 +21567,6 @@
@DocsEditable
static const EventStreamProvider<Event> cueChangeEvent = const EventStreamProvider<Event>('cuechange');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- TextTrackEvents get on =>
- new TextTrackEvents(this);
-
@DomName('TextTrack.activeCues')
@DocsEditable
final TextTrackCueList activeCues;
@@ -22351,16 +21617,6 @@
@DocsEditable
Stream<Event> get onCueChange => cueChangeEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class TextTrackEvents extends Events {
- @DocsEditable
- TextTrackEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get cueChange => this['cuechange'];
-}
// 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.
@@ -22385,12 +21641,6 @@
}
static TextTrackCue _create_1(startTime, endTime, text) => JS('TextTrackCue', 'new TextTrackCue(#,#,#)', startTime, endTime, text);
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- TextTrackCueEvents get on =>
- new TextTrackCueEvents(this);
-
@DomName('TextTrackCue.align')
@DocsEditable
String align;
@@ -22466,19 +21716,6 @@
@DocsEditable
Stream<Event> get onExit => exitEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class TextTrackCueEvents extends Events {
- @DocsEditable
- TextTrackCueEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get enter => this['enter'];
-
- @DocsEditable
- EventListenerList get exit => this['exit'];
-}
// 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.
@@ -22696,12 +21933,6 @@
@DocsEditable
static const EventStreamProvider<TrackEvent> addTrackEvent = const EventStreamProvider<TrackEvent>('addtrack');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- TextTrackListEvents get on =>
- new TextTrackListEvents(this);
-
@DomName('TextTrackList.length')
@DocsEditable
int get length => JS("int", "#.length", this);
@@ -22911,16 +22142,6 @@
@DocsEditable
Stream<TrackEvent> get onAddTrack => addTrackEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class TextTrackListEvents extends Events {
- @DocsEditable
- TextTrackListEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get addTrack => this['addtrack'];
-}
// 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.
@@ -26281,12 +25502,6 @@
/// Checks if this type is supported on the current platform.
static bool get supported => JS('bool', 'typeof window.WebSocket != "undefined"');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- WebSocketEvents get on =>
- new WebSocketEvents(this);
-
static const int CLOSED = 3;
static const int CLOSING = 2;
@@ -26362,25 +25577,6 @@
@DocsEditable
Stream<Event> get onOpen => openEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class WebSocketEvents extends Events {
- @DocsEditable
- WebSocketEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get close => this['close'];
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get message => this['message'];
-
- @DocsEditable
- EventListenerList get open => this['open'];
-}
// 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.
@@ -26833,12 +26029,6 @@
@Experimental
static const EventStreamProvider<AnimationEvent> animationStartEvent = const EventStreamProvider<AnimationEvent>('webkitAnimationStart');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- WindowEvents get on =>
- new WindowEvents(this);
-
static const int PERSISTENT = 1;
static const int TEMPORARY = 0;
@@ -27204,11 +26394,17 @@
@JSName('webkitConvertPointFromNodeToPage')
@DomName('DOMWindow.webkitConvertPointFromNodeToPage')
@DocsEditable
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ @Experimental
DomPoint convertPointFromNodeToPage(Node node, DomPoint p) native;
@JSName('webkitConvertPointFromPageToNode')
@DomName('DOMWindow.webkitConvertPointFromPageToNode')
@DocsEditable
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ @Experimental
DomPoint convertPointFromPageToNode(Node node, DomPoint p) native;
@JSName('webkitRequestFileSystem')
@@ -27442,235 +26638,6 @@
Stream<TransitionEvent> get onTransitionEnd => Element.transitionEndEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class WindowEvents extends Events {
- @DocsEditable
- WindowEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get contentLoaded => this['DOMContentLoaded'];
-
- @DocsEditable
- EventListenerList get abort => this['abort'];
-
- @DocsEditable
- EventListenerList get beforeUnload => this['beforeunload'];
-
- @DocsEditable
- EventListenerList get blur => this['blur'];
-
- @DocsEditable
- EventListenerList get canPlay => this['canplay'];
-
- @DocsEditable
- EventListenerList get canPlayThrough => this['canplaythrough'];
-
- @DocsEditable
- EventListenerList get change => this['change'];
-
- @DocsEditable
- EventListenerList get click => this['click'];
-
- @DocsEditable
- EventListenerList get contextMenu => this['contextmenu'];
-
- @DocsEditable
- EventListenerList get doubleClick => this['dblclick'];
-
- @DocsEditable
- EventListenerList get deviceMotion => this['devicemotion'];
-
- @DocsEditable
- EventListenerList get deviceOrientation => this['deviceorientation'];
-
- @DocsEditable
- EventListenerList get drag => this['drag'];
-
- @DocsEditable
- EventListenerList get dragEnd => this['dragend'];
-
- @DocsEditable
- EventListenerList get dragEnter => this['dragenter'];
-
- @DocsEditable
- EventListenerList get dragLeave => this['dragleave'];
-
- @DocsEditable
- EventListenerList get dragOver => this['dragover'];
-
- @DocsEditable
- EventListenerList get dragStart => this['dragstart'];
-
- @DocsEditable
- EventListenerList get drop => this['drop'];
-
- @DocsEditable
- EventListenerList get durationChange => this['durationchange'];
-
- @DocsEditable
- EventListenerList get emptied => this['emptied'];
-
- @DocsEditable
- EventListenerList get ended => this['ended'];
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get focus => this['focus'];
-
- @DocsEditable
- EventListenerList get hashChange => this['hashchange'];
-
- @DocsEditable
- EventListenerList get input => this['input'];
-
- @DocsEditable
- EventListenerList get invalid => this['invalid'];
-
- @DocsEditable
- EventListenerList get keyDown => this['keydown'];
-
- @DocsEditable
- EventListenerList get keyPress => this['keypress'];
-
- @DocsEditable
- EventListenerList get keyUp => this['keyup'];
-
- @DocsEditable
- EventListenerList get load => this['load'];
-
- @DocsEditable
- EventListenerList get loadedData => this['loadeddata'];
-
- @DocsEditable
- EventListenerList get loadedMetadata => this['loadedmetadata'];
-
- @DocsEditable
- EventListenerList get loadStart => this['loadstart'];
-
- @DocsEditable
- EventListenerList get message => this['message'];
-
- @DocsEditable
- EventListenerList get mouseDown => this['mousedown'];
-
- @DocsEditable
- EventListenerList get mouseMove => this['mousemove'];
-
- @DocsEditable
- EventListenerList get mouseOut => this['mouseout'];
-
- @DocsEditable
- EventListenerList get mouseOver => this['mouseover'];
-
- @DocsEditable
- EventListenerList get mouseUp => this['mouseup'];
-
- @DocsEditable
- EventListenerList get mouseWheel => this['mousewheel'];
-
- @DocsEditable
- EventListenerList get offline => this['offline'];
-
- @DocsEditable
- EventListenerList get online => this['online'];
-
- @DocsEditable
- EventListenerList get pageHide => this['pagehide'];
-
- @DocsEditable
- EventListenerList get pageShow => this['pageshow'];
-
- @DocsEditable
- EventListenerList get pause => this['pause'];
-
- @DocsEditable
- EventListenerList get play => this['play'];
-
- @DocsEditable
- EventListenerList get playing => this['playing'];
-
- @DocsEditable
- EventListenerList get popState => this['popstate'];
-
- @DocsEditable
- EventListenerList get progress => this['progress'];
-
- @DocsEditable
- EventListenerList get rateChange => this['ratechange'];
-
- @DocsEditable
- EventListenerList get reset => this['reset'];
-
- @DocsEditable
- EventListenerList get resize => this['resize'];
-
- @DocsEditable
- EventListenerList get scroll => this['scroll'];
-
- @DocsEditable
- EventListenerList get search => this['search'];
-
- @DocsEditable
- EventListenerList get seeked => this['seeked'];
-
- @DocsEditable
- EventListenerList get seeking => this['seeking'];
-
- @DocsEditable
- EventListenerList get select => this['select'];
-
- @DocsEditable
- EventListenerList get stalled => this['stalled'];
-
- @DocsEditable
- EventListenerList get storage => this['storage'];
-
- @DocsEditable
- EventListenerList get submit => this['submit'];
-
- @DocsEditable
- EventListenerList get suspend => this['suspend'];
-
- @DocsEditable
- EventListenerList get timeUpdate => this['timeupdate'];
-
- @DocsEditable
- EventListenerList get touchCancel => this['touchcancel'];
-
- @DocsEditable
- EventListenerList get touchEnd => this['touchend'];
-
- @DocsEditable
- EventListenerList get touchMove => this['touchmove'];
-
- @DocsEditable
- EventListenerList get touchStart => this['touchstart'];
-
- @DocsEditable
- EventListenerList get unload => this['unload'];
-
- @DocsEditable
- EventListenerList get volumeChange => this['volumechange'];
-
- @DocsEditable
- EventListenerList get waiting => this['waiting'];
-
- @DocsEditable
- EventListenerList get animationEnd => this['webkitAnimationEnd'];
-
- @DocsEditable
- EventListenerList get animationIteration => this['webkitAnimationIteration'];
-
- @DocsEditable
- EventListenerList get animationStart => this['webkitAnimationStart'];
-
- @DocsEditable
- EventListenerList get transitionEnd => this['webkitTransitionEnd'];
-}
// 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.
@@ -27691,12 +26658,6 @@
}
static Worker _create_1(scriptUrl) => JS('Worker', 'new Worker(#)', scriptUrl);
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- WorkerEvents get on =>
- new WorkerEvents(this);
-
@DomName('Worker.postMessage')
@DocsEditable
void postMessage(/*SerializedScriptValue*/ message, [List messagePorts]) {
@@ -27726,16 +26687,6 @@
@DocsEditable
Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class WorkerEvents extends AbstractWorkerEvents {
- @DocsEditable
- WorkerEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get message => this['message'];
-}
// 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.
@@ -27748,12 +26699,6 @@
@DocsEditable
static const EventStreamProvider<Event> errorEvent = const EventStreamProvider<Event>('error');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- WorkerContextEvents get on =>
- new WorkerContextEvents(this);
-
static const int PERSISTENT = 1;
static const int TEMPORARY = 0;
@@ -27878,16 +26823,6 @@
'#.indexedDB || #.webkitIndexedDB || #.mozIndexedDB',
this, this, this);
}
-
-@DocsEditable
-@deprecated
-class WorkerContextEvents extends Events {
- @DocsEditable
- WorkerContextEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get error => this['error'];
-}
// 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.
@@ -29438,58 +28373,6 @@
@DocsEditable
@DomName('HTMLFrameSetElement')
class _HTMLFrameSetElement extends Element native "*HTMLFrameSetElement" {
-
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- _HTMLFrameSetElementEvents get on =>
- new _HTMLFrameSetElementEvents(this);
-}
-
-@DocsEditable
-@deprecated
-class _HTMLFrameSetElementEvents extends ElementEvents {
- @DocsEditable
- _HTMLFrameSetElementEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get beforeUnload => this['beforeunload'];
-
- @DocsEditable
- EventListenerList get blur => this['blur'];
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get focus => this['focus'];
-
- @DocsEditable
- EventListenerList get hashChange => this['hashchange'];
-
- @DocsEditable
- EventListenerList get load => this['load'];
-
- @DocsEditable
- EventListenerList get message => this['message'];
-
- @DocsEditable
- EventListenerList get offline => this['offline'];
-
- @DocsEditable
- EventListenerList get online => this['online'];
-
- @DocsEditable
- EventListenerList get popState => this['popstate'];
-
- @DocsEditable
- EventListenerList get resize => this['resize'];
-
- @DocsEditable
- EventListenerList get storage => this['storage'];
-
- @DocsEditable
- EventListenerList get unload => this['unload'];
}
// 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
@@ -32632,12 +31515,10 @@
// TODO(vsm): Set this up set once, on the first call.
var source = '$target-result';
var result = null;
- var listener = (Event e) {
+ window.on[source].first.then((Event e) {
result = json.parse(_getPortSyncEventData(e));
- };
- window.on[source].add(listener);
+ });
_dispatchEvent(target, [source, message]);
- window.on[source].remove(listener);
return result;
}
@@ -32692,7 +31573,7 @@
num _portId;
Function _callback;
- EventListener _listener;
+ StreamSubscription _portSubscription;
ReceivePortSync() {
if (_portIdCount == null) {
@@ -32717,21 +31598,20 @@
void receive(callback(var message)) {
_callback = callback;
- if (_listener == null) {
- _listener = (Event e) {
+ if (_portSubscription == null) {
+ _portSubscription = window.on[_listenerName].listen((Event e) {
var data = json.parse(_getPortSyncEventData(e));
var replyTo = data[0];
var message = _deserialize(data[1]);
var result = _callback(message);
_dispatchEvent(replyTo, _serialize(result));
- };
- window.on[_listenerName].add(_listener);
+ });
}
}
void close() {
_portMap.remove(_portId);
- if (_listener != null) window.on[_listenerName].remove(_listener);
+ if (_portSubscription != null) _portSubscription.cancel();
}
SendPortSync toSendPort() {
diff --git a/sdk/lib/html/dartium/html_dartium.dart b/sdk/lib/html/dartium/html_dartium.dart
index c5cd920..dfe5485 100644
--- a/sdk/lib/html/dartium/html_dartium.dart
+++ b/sdk/lib/html/dartium/html_dartium.dart
@@ -54,9 +54,9 @@
_callPortSync(num id, var message) {
if (!_callPortInitialized) {
- window.on['js-result'].add((event) {
+ window.on['js-result'].listen((event) {
_callPortLastResult = json.parse(_getPortSyncEventData(event));
- }, false);
+ });
_callPortInitialized = true;
}
assert(_callPortLastResult == null);
@@ -81,12 +81,6 @@
@DocsEditable
static const EventStreamProvider<Event> errorEvent = const EventStreamProvider<Event>('error');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- AbstractWorkerEvents get on =>
- new AbstractWorkerEvents(this);
-
@DomName('AbstractWorker.addEventListener')
@DocsEditable
void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native "AbstractWorker_addEventListener_Callback";
@@ -104,16 +98,6 @@
Stream<Event> get onError => errorEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class AbstractWorkerEvents extends Events {
- @DocsEditable
- AbstractWorkerEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get error => this['error'];
-}
// 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.
@@ -336,12 +320,6 @@
/// Checks if this type is supported on the current platform.
static bool get supported => true;
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- ApplicationCacheEvents get on =>
- new ApplicationCacheEvents(this);
-
static const int CHECKING = 2;
static const int DOWNLOADING = 3;
@@ -415,37 +393,6 @@
Stream<Event> get onUpdateReady => updateReadyEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class ApplicationCacheEvents extends Events {
- @DocsEditable
- ApplicationCacheEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get cached => this['cached'];
-
- @DocsEditable
- EventListenerList get checking => this['checking'];
-
- @DocsEditable
- EventListenerList get downloading => this['downloading'];
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get noUpdate => this['noupdate'];
-
- @DocsEditable
- EventListenerList get obsolete => this['obsolete'];
-
- @DocsEditable
- EventListenerList get progress => this['progress'];
-
- @DocsEditable
- EventListenerList get updateReady => this['updateready'];
-}
// 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.
@@ -751,12 +698,6 @@
@DocsEditable
static const EventStreamProvider<Event> levelChangeEvent = const EventStreamProvider<Event>('levelchange');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- BatteryManagerEvents get on =>
- new BatteryManagerEvents(this);
-
@DomName('BatteryManager.charging')
@DocsEditable
bool get charging native "BatteryManager_charging_Getter";
@@ -802,25 +743,6 @@
Stream<Event> get onLevelChange => levelChangeEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class BatteryManagerEvents extends Events {
- @DocsEditable
- BatteryManagerEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get chargingChange => this['chargingchange'];
-
- @DocsEditable
- EventListenerList get chargingTimeChange => this['chargingtimechange'];
-
- @DocsEditable
- EventListenerList get dischargingTimeChange => this['dischargingtimechange'];
-
- @DocsEditable
- EventListenerList get levelChange => this['levelchange'];
-}
// 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.
@@ -958,12 +880,6 @@
@DocsEditable
factory BodyElement() => document.$dom_createElement("body");
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- BodyElementEvents get on =>
- new BodyElementEvents(this);
-
@DomName('HTMLBodyElement.onbeforeunload')
@DocsEditable
Stream<Event> get onBeforeUnload => beforeUnloadEvent.forTarget(this);
@@ -1017,52 +933,6 @@
Stream<Event> get onUnload => unloadEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class BodyElementEvents extends ElementEvents {
- @DocsEditable
- BodyElementEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get beforeUnload => this['beforeunload'];
-
- @DocsEditable
- EventListenerList get blur => this['blur'];
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get focus => this['focus'];
-
- @DocsEditable
- EventListenerList get hashChange => this['hashchange'];
-
- @DocsEditable
- EventListenerList get load => this['load'];
-
- @DocsEditable
- EventListenerList get message => this['message'];
-
- @DocsEditable
- EventListenerList get offline => this['offline'];
-
- @DocsEditable
- EventListenerList get online => this['online'];
-
- @DocsEditable
- EventListenerList get popState => this['popstate'];
-
- @DocsEditable
- EventListenerList get resize => this['resize'];
-
- @DocsEditable
- EventListenerList get storage => this['storage'];
-
- @DocsEditable
- EventListenerList get unload => this['unload'];
-}
// 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.
@@ -6963,12 +6833,6 @@
@DocsEditable
static const EventStreamProvider<MessageEvent> messageEvent = const EventStreamProvider<MessageEvent>('message');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- DedicatedWorkerContextEvents get on =>
- new DedicatedWorkerContextEvents(this);
-
@DomName('DedicatedWorkerContext.postMessage')
@DocsEditable
void postMessage(Object message, [List messagePorts]) native "DedicatedWorkerContext_postMessage_Callback";
@@ -6978,16 +6842,6 @@
Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class DedicatedWorkerContextEvents extends WorkerContextEvents {
- @DocsEditable
- DedicatedWorkerContextEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get message => this['message'];
-}
// 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.
@@ -7248,12 +7102,6 @@
@Experimental
static const EventStreamProvider<Event> pointerLockErrorEvent = const EventStreamProvider<Event>('webkitpointerlockerror');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- DocumentEvents get on =>
- new DocumentEvents(this);
-
/// Moved to [HtmlDocument].
@DomName('Document.body')
@DocsEditable
@@ -7774,25 +7622,6 @@
}
}
}
-
-@DocsEditable
-@deprecated
-class DocumentEvents extends ElementEvents {
- @DocsEditable
- DocumentEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get readyStateChange => this['readystatechange'];
-
- @DocsEditable
- EventListenerList get selectionChange => this['selectionchange'];
-
- @DocsEditable
- EventListenerList get pointerLockChange => this['webkitpointerlockchange'];
-
- @DocsEditable
- EventListenerList get pointerLockError => this['webkitpointerlockerror'];
-}
// 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.
@@ -7876,12 +7705,6 @@
DocumentFragment.internal() : super.internal();
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- ElementEvents get on =>
- new ElementEvents(this);
-
@DomName('DocumentFragment.querySelector')
@DocsEditable
Element $dom_querySelector(String selectors) native "DocumentFragment_querySelector_Callback";
@@ -9727,6 +9550,40 @@
*/
var xtag;
+ /**
+ * Scrolls this element into view.
+ *
+ * Only one of of the alignment options may be specified at a time.
+ *
+ * If no options are specified then this will attempt to scroll the minimum
+ * amount needed to bring the element into view.
+ *
+ * Note that alignCenter is currently only supported on WebKit platforms. If
+ * alignCenter is specified but not supported then this will fall back to
+ * alignTop.
+ *
+ * See also:
+ *
+ * * [scrollIntoView](http://docs.webplatform.org/wiki/dom/methods/scrollIntoView)
+ * * [scrollIntoViewIfNeeded](http://docs.webplatform.org/wiki/dom/methods/scrollIntoViewIfNeeded)
+ */
+ void scrollIntoView([ScrollAlignment alignment]) {
+ var hasScrollIntoViewIfNeeded = false;
+ if (alignment == ScrollAlignment.TOP) {
+ this.$dom_scrollIntoView(true);
+ } else if (alignment == ScrollAlignment.BOTTOM) {
+ this.$dom_scrollIntoView(false);
+ } else if (hasScrollIntoViewIfNeeded) {
+ if (alignment == ScrollAlignment.CENTER) {
+ this.$dom_scrollIntoViewIfNeeded(true);
+ } else {
+ this.$dom_scrollIntoViewIfNeeded();
+ }
+ } else {
+ this.$dom_scrollIntoView();
+ }
+ }
+
Element.internal() : super.internal();
@@ -9931,12 +9788,6 @@
@Experimental
static const EventStreamProvider<Event> fullscreenErrorEvent = const EventStreamProvider<Event>('webkitfullscreenerror');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- ElementEvents get on =>
- new ElementEvents(this);
-
HtmlCollection get $dom_children;
String contentEditable;
@@ -10166,7 +10017,24 @@
@DocsEditable
void scrollByPages(int pages) native "Element_scrollByPages_Callback";
- void scrollIntoView([bool centerIfNeeded]) {
+ void $dom_scrollIntoView([bool alignWithTop]) {
+ if (?alignWithTop) {
+ _scrollIntoView_1(alignWithTop);
+ return;
+ }
+ _scrollIntoView_2();
+ return;
+ }
+
+ @DomName('Element._scrollIntoView_1')
+ @DocsEditable
+ void _scrollIntoView_1(alignWithTop) native "Element__scrollIntoView_1_Callback";
+
+ @DomName('Element._scrollIntoView_2')
+ @DocsEditable
+ void _scrollIntoView_2() native "Element__scrollIntoView_2_Callback";
+
+ void $dom_scrollIntoViewIfNeeded([bool centerIfNeeded]) {
if (?centerIfNeeded) {
_scrollIntoViewIfNeeded_1(centerIfNeeded);
return;
@@ -10552,155 +10420,21 @@
document.$dom_createElement(tag);
}
-@DocsEditable
-@deprecated
-class ElementEvents extends Events {
- @DocsEditable
- ElementEvents(EventTarget _ptr) : super(_ptr);
- @DocsEditable
- EventListenerList get abort => this['abort'];
+/**
+ * Options for Element.scrollIntoView.
+ */
+class ScrollAlignment {
+ final _value;
+ const ScrollAlignment._internal(this._value);
+ toString() => 'ScrollAlignment.$_value';
- @DocsEditable
- EventListenerList get beforeCopy => this['beforecopy'];
-
- @DocsEditable
- EventListenerList get beforeCut => this['beforecut'];
-
- @DocsEditable
- EventListenerList get beforePaste => this['beforepaste'];
-
- @DocsEditable
- EventListenerList get blur => this['blur'];
-
- @DocsEditable
- EventListenerList get change => this['change'];
-
- @DocsEditable
- EventListenerList get click => this['click'];
-
- @DocsEditable
- EventListenerList get contextMenu => this['contextmenu'];
-
- @DocsEditable
- EventListenerList get copy => this['copy'];
-
- @DocsEditable
- EventListenerList get cut => this['cut'];
-
- @DocsEditable
- EventListenerList get doubleClick => this['dblclick'];
-
- @DocsEditable
- EventListenerList get drag => this['drag'];
-
- @DocsEditable
- EventListenerList get dragEnd => this['dragend'];
-
- @DocsEditable
- EventListenerList get dragEnter => this['dragenter'];
-
- @DocsEditable
- EventListenerList get dragLeave => this['dragleave'];
-
- @DocsEditable
- EventListenerList get dragOver => this['dragover'];
-
- @DocsEditable
- EventListenerList get dragStart => this['dragstart'];
-
- @DocsEditable
- EventListenerList get drop => this['drop'];
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get focus => this['focus'];
-
- @DocsEditable
- EventListenerList get input => this['input'];
-
- @DocsEditable
- EventListenerList get invalid => this['invalid'];
-
- @DocsEditable
- EventListenerList get keyDown => this['keydown'];
-
- @DocsEditable
- EventListenerList get keyPress => this['keypress'];
-
- @DocsEditable
- EventListenerList get keyUp => this['keyup'];
-
- @DocsEditable
- EventListenerList get load => this['load'];
-
- @DocsEditable
- EventListenerList get mouseDown => this['mousedown'];
-
- @DocsEditable
- EventListenerList get mouseMove => this['mousemove'];
-
- @DocsEditable
- EventListenerList get mouseOut => this['mouseout'];
-
- @DocsEditable
- EventListenerList get mouseOver => this['mouseover'];
-
- @DocsEditable
- EventListenerList get mouseUp => this['mouseup'];
-
- @DocsEditable
- EventListenerList get mouseWheel => this['mousewheel'];
-
- @DocsEditable
- EventListenerList get paste => this['paste'];
-
- @DocsEditable
- EventListenerList get reset => this['reset'];
-
- @DocsEditable
- EventListenerList get scroll => this['scroll'];
-
- @DocsEditable
- EventListenerList get search => this['search'];
-
- @DocsEditable
- EventListenerList get select => this['select'];
-
- @DocsEditable
- EventListenerList get selectStart => this['selectstart'];
-
- @DocsEditable
- EventListenerList get submit => this['submit'];
-
- @DocsEditable
- EventListenerList get touchCancel => this['touchcancel'];
-
- @DocsEditable
- EventListenerList get touchEnd => this['touchend'];
-
- @DocsEditable
- EventListenerList get touchEnter => this['touchenter'];
-
- @DocsEditable
- EventListenerList get touchLeave => this['touchleave'];
-
- @DocsEditable
- EventListenerList get touchMove => this['touchmove'];
-
- @DocsEditable
- EventListenerList get touchStart => this['touchstart'];
-
- @DocsEditable
- EventListenerList get transitionEnd => this['webkitTransitionEnd'];
-
- @DocsEditable
- EventListenerList get fullscreenChange => this['webkitfullscreenchange'];
-
- @DocsEditable
- EventListenerList get fullscreenError => this['webkitfullscreenerror'];
+ /// Attempt to align the element to the top of the scrollable area.
+ static const TOP = const ScrollAlignment._internal('TOP');
+ /// Attempt to center the element in the scrollable area.
+ static const CENTER = const ScrollAlignment._internal('CENTER');
+ /// Attempt to align the element to the bottom of the scrollable area.
+ static const BOTTOM = const ScrollAlignment._internal('BOTTOM');
}
// 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
@@ -11232,12 +10966,6 @@
@DocsEditable
static EventSource _create_1(url, eventSourceInit) native "EventSource__create_1constructorCallback";
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- EventSourceEvents get on =>
- new EventSourceEvents(this);
-
static const int CLOSED = 2;
static const int CONNECTING = 0;
@@ -11285,22 +11013,6 @@
Stream<Event> get onOpen => openEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class EventSourceEvents extends Events {
- @DocsEditable
- EventSourceEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get message => this['message'];
-
- @DocsEditable
- EventListenerList get open => this['open'];
-}
// 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.
@@ -11309,15 +11021,38 @@
/**
* Base class that supports listening for and dispatching browser events.
*
- * Events can either be accessed by string name (using the indexed getter) or by
- * getters exposed by subclasses. Use the getters exposed by subclasses when
- * possible for better compile-time type checks.
+ * Normally events are accessed via the Stream getter:
*
- * Using an indexed getter:
- * events['mouseover'].add((e) => print("Mouse over!"));
+ * element.onMouseOver.listen((e) => print('Mouse over!'));
*
- * Using a getter provided by a subclass:
- * elementEvents.mouseOver.add((e) => print("Mouse over!"));
+ * To access bubbling events which are declared on one element, but may bubble
+ * up to another element type (common for MediaElement events):
+ *
+ * MediaElement.pauseEvent.forTarget(document.body).listen(...);
+ *
+ * To useCapture on events:
+ *
+ * Element.keyDownEvent.forTarget(element, useCapture: true).listen(...);
+ *
+ * Custom events can be declared as:
+ *
+ * class DataGenerator {
+ * static EventStreamProvider<Event> dataEvent =
+ * new EventStreamProvider('data');
+ * }
+ *
+ * Then listeners should access the event with:
+ *
+ * DataGenerator.dataEvent.forTarget(element).listen(...);
+ *
+ * Custom events can also be accessed as:
+ *
+ * element.on['some_event'].listen(...);
+ *
+ * This approach is generally discouraged as it loses the event typing and
+ * some DOM events may have multiple platform-dependent event names under the
+ * covers. By using the standard Stream getters you will get the platform
+ * specific event name automatically.
*/
class Events {
/* Raw event target. */
@@ -11325,60 +11060,25 @@
Events(this._ptr);
- EventListenerList operator [](String type) {
- return new EventListenerList(_ptr, type);
- }
-}
-
-/**
- * Supports adding, removing, and dispatching events for a specific event type.
- */
-class EventListenerList {
-
- final EventTarget _ptr;
- final String _type;
-
- EventListenerList(this._ptr, this._type);
-
- // TODO(jacobr): implement equals.
-
- EventListenerList add(EventListener listener,
- [bool useCapture = false]) {
- _add(listener, useCapture);
- return this;
- }
-
- EventListenerList remove(EventListener listener,
- [bool useCapture = false]) {
- _remove(listener, useCapture);
- return this;
- }
-
- bool dispatch(Event evt) {
- return _ptr.dispatchEvent(evt);
- }
-
- void _add(EventListener listener, bool useCapture) {
- _ptr.$dom_addEventListener(_type, listener, useCapture);
- }
-
- void _remove(EventListener listener, bool useCapture) {
- _ptr.$dom_removeEventListener(_type, listener, useCapture);
+ Stream operator [](String type) {
+ return new _EventStream(_ptr, type, false);
}
}
/**
* Base class for all browser objects that support events.
*
- * Use the [on] property to add, remove, and dispatch events (rather than
- * [$dom_addEventListener], [$dom_dispatchEvent], and
- * [$dom_removeEventListener]) for compile-time type checks and a more concise
- * API.
+ * Use the [on] property to add, and remove events (rather than
+ * [$dom_addEventListener] and [$dom_removeEventListener]
+ * for compile-time type checks and a more concise API.
*/
@DomName('EventTarget')
class EventTarget extends NativeFieldWrapperClass1 {
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
+ /**
+ * This is an ease-of-use accessor for event streams which should only be
+ * used when an explicit accessor is not available.
+ */
Events get on => new Events(this);
EventTarget.internal();
@@ -11898,12 +11598,6 @@
@DocsEditable
static FileReader _create_1() native "FileReader__create_1constructorCallback";
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- FileReaderEvents get on =>
- new FileReaderEvents(this);
-
static const int DONE = 2;
static const int EMPTY = 0;
@@ -11992,31 +11686,6 @@
Stream<ProgressEvent> get onProgress => progressEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class FileReaderEvents extends Events {
- @DocsEditable
- FileReaderEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get abort => this['abort'];
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get load => this['load'];
-
- @DocsEditable
- EventListenerList get loadEnd => this['loadend'];
-
- @DocsEditable
- EventListenerList get loadStart => this['loadstart'];
-
- @DocsEditable
- EventListenerList get progress => this['progress'];
-}
// 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.
@@ -12075,6 +11744,8 @@
@DocsEditable
@DomName('DOMFileSystem')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@Experimental
class FileSystem extends NativeFieldWrapperClass1 {
FileSystem.internal();
@@ -12107,6 +11778,8 @@
@DocsEditable
@DomName('DOMFileSystemSync')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@Experimental
class FileSystemSync extends NativeFieldWrapperClass1 {
FileSystemSync.internal();
@@ -12155,12 +11828,6 @@
@DocsEditable
static const EventStreamProvider<ProgressEvent> writeStartEvent = const EventStreamProvider<ProgressEvent>('writestart');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- FileWriterEvents get on =>
- new FileWriterEvents(this);
-
static const int DONE = 2;
static const int INIT = 0;
@@ -12236,31 +11903,6 @@
Stream<ProgressEvent> get onWriteStart => writeStartEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class FileWriterEvents extends Events {
- @DocsEditable
- FileWriterEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get abort => this['abort'];
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get progress => this['progress'];
-
- @DocsEditable
- EventListenerList get write => this['write'];
-
- @DocsEditable
- EventListenerList get writeEnd => this['writeend'];
-
- @DocsEditable
- EventListenerList get writeStart => this['writestart'];
-}
// 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.
@@ -13944,12 +13586,6 @@
@DocsEditable
static HttpRequest _create_1() native "XMLHttpRequest__create_1constructorCallback";
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- HttpRequestEvents get on =>
- new HttpRequestEvents(this);
-
static const int DONE = 4;
static const int HEADERS_RECEIVED = 2;
@@ -14244,34 +13880,6 @@
Stream<ProgressEvent> get onReadyStateChange => readyStateChangeEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class HttpRequestEvents extends Events {
- @DocsEditable
- HttpRequestEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get abort => this['abort'];
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get load => this['load'];
-
- @DocsEditable
- EventListenerList get loadEnd => this['loadend'];
-
- @DocsEditable
- EventListenerList get loadStart => this['loadstart'];
-
- @DocsEditable
- EventListenerList get progress => this['progress'];
-
- @DocsEditable
- EventListenerList get readyStateChange => this['readystatechange'];
-}
// 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.
@@ -14368,12 +13976,6 @@
@DocsEditable
static const EventStreamProvider<ProgressEvent> progressEvent = const EventStreamProvider<ProgressEvent>('progress');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- HttpRequestUploadEvents get on =>
- new HttpRequestUploadEvents(this);
-
@DomName('XMLHttpRequestUpload.addEventListener')
@DocsEditable
void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native "XMLHttpRequestUpload_addEventListener_Callback";
@@ -14411,31 +14013,6 @@
Stream<ProgressEvent> get onProgress => progressEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class HttpRequestUploadEvents extends Events {
- @DocsEditable
- HttpRequestUploadEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get abort => this['abort'];
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get load => this['load'];
-
- @DocsEditable
- EventListenerList get loadEnd => this['loadend'];
-
- @DocsEditable
- EventListenerList get loadStart => this['loadstart'];
-
- @DocsEditable
- EventListenerList get progress => this['progress'];
-}
// 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.
@@ -14701,12 +14278,6 @@
@Experimental
static const EventStreamProvider<Event> speechChangeEvent = const EventStreamProvider<Event>('webkitSpeechChange');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- InputElementEvents get on =>
- new InputElementEvents(this);
-
@DomName('HTMLInputElement.accept')
@DocsEditable
String get accept native "HTMLInputElement_accept_Getter";
@@ -15749,16 +15320,6 @@
factory ButtonInputElement() => new InputElement(type: 'button');
}
-
-@DocsEditable
-@deprecated
-class InputElementEvents extends ElementEvents {
- @DocsEditable
- InputElementEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get speechChange => this['webkitSpeechChange'];
-}
// 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.
@@ -17244,12 +16805,6 @@
@Experimental
static const EventStreamProvider<MediaKeyEvent> needKeyEvent = const EventStreamProvider<MediaKeyEvent>('webkitneedkey');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- MediaElementEvents get on =>
- new MediaElementEvents(this);
-
static const int HAVE_CURRENT_DATA = 2;
static const int HAVE_ENOUGH_DATA = 4;
@@ -17657,88 +17212,6 @@
Stream<MediaKeyEvent> get onNeedKey => needKeyEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class MediaElementEvents extends ElementEvents {
- @DocsEditable
- MediaElementEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get canPlay => this['canplay'];
-
- @DocsEditable
- EventListenerList get canPlayThrough => this['canplaythrough'];
-
- @DocsEditable
- EventListenerList get durationChange => this['durationchange'];
-
- @DocsEditable
- EventListenerList get emptied => this['emptied'];
-
- @DocsEditable
- EventListenerList get ended => this['ended'];
-
- @DocsEditable
- EventListenerList get loadedData => this['loadeddata'];
-
- @DocsEditable
- EventListenerList get loadedMetadata => this['loadedmetadata'];
-
- @DocsEditable
- EventListenerList get loadStart => this['loadstart'];
-
- @DocsEditable
- EventListenerList get pause => this['pause'];
-
- @DocsEditable
- EventListenerList get play => this['play'];
-
- @DocsEditable
- EventListenerList get playing => this['playing'];
-
- @DocsEditable
- EventListenerList get progress => this['progress'];
-
- @DocsEditable
- EventListenerList get rateChange => this['ratechange'];
-
- @DocsEditable
- EventListenerList get seeked => this['seeked'];
-
- @DocsEditable
- EventListenerList get seeking => this['seeking'];
-
- @DocsEditable
- EventListenerList get show => this['show'];
-
- @DocsEditable
- EventListenerList get stalled => this['stalled'];
-
- @DocsEditable
- EventListenerList get suspend => this['suspend'];
-
- @DocsEditable
- EventListenerList get timeUpdate => this['timeupdate'];
-
- @DocsEditable
- EventListenerList get volumeChange => this['volumechange'];
-
- @DocsEditable
- EventListenerList get waiting => this['waiting'];
-
- @DocsEditable
- EventListenerList get keyAdded => this['webkitkeyadded'];
-
- @DocsEditable
- EventListenerList get keyError => this['webkitkeyerror'];
-
- @DocsEditable
- EventListenerList get keyMessage => this['webkitkeymessage'];
-
- @DocsEditable
- EventListenerList get needKey => this['webkitneedkey'];
-}
// 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.
@@ -17996,10 +17469,18 @@
class MediaStream extends EventTarget {
MediaStream.internal() : super.internal();
+ @DomName('MediaStream.addtrackEvent')
+ @DocsEditable
+ static const EventStreamProvider<Event> addTrackEvent = const EventStreamProvider<Event>('addtrack');
+
@DomName('MediaStream.endedEvent')
@DocsEditable
static const EventStreamProvider<Event> endedEvent = const EventStreamProvider<Event>('ended');
+ @DomName('MediaStream.removetrackEvent')
+ @DocsEditable
+ static const EventStreamProvider<Event> removeTrackEvent = const EventStreamProvider<Event>('removetrack');
+
@DomName('MediaStream.MediaStream')
@DocsEditable
factory MediaStream([stream_OR_tracks]) {
@@ -18024,12 +17505,6 @@
@DocsEditable
static MediaStream _create_3(stream_OR_tracks) native "MediaStream__create_3constructorCallback";
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- MediaStreamEvents get on =>
- new MediaStreamEvents(this);
-
@DomName('MediaStream.ended')
@DocsEditable
bool get ended native "MediaStream_ended_Getter";
@@ -18074,10 +17549,18 @@
@DocsEditable
void removeTrack(MediaStreamTrack track) native "MediaStream_removeTrack_Callback";
+ @DomName('MediaStream.onaddtrack')
+ @DocsEditable
+ Stream<Event> get onAddTrack => addTrackEvent.forTarget(this);
+
@DomName('MediaStream.onended')
@DocsEditable
Stream<Event> get onEnded => endedEvent.forTarget(this);
+ @DomName('MediaStream.onremovetrack')
+ @DocsEditable
+ Stream<Event> get onRemoveTrack => removeTrackEvent.forTarget(this);
+
/**
* Checks if the MediaStream APIs are supported on the current platform.
@@ -18088,22 +17571,6 @@
*/
static bool get supported => true;
}
-
-@DocsEditable
-@deprecated
-class MediaStreamEvents extends Events {
- @DocsEditable
- MediaStreamEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get addTrack => this['addtrack'];
-
- @DocsEditable
- EventListenerList get ended => this['ended'];
-
- @DocsEditable
- EventListenerList get removeTrack => this['removetrack'];
-}
// 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.
@@ -18152,12 +17619,6 @@
@DocsEditable
static const EventStreamProvider<Event> unmuteEvent = const EventStreamProvider<Event>('unmute');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- MediaStreamTrackEvents get on =>
- new MediaStreamTrackEvents(this);
-
@DomName('MediaStreamTrack.enabled')
@DocsEditable
bool get enabled native "MediaStreamTrack_enabled_Getter";
@@ -18207,22 +17668,6 @@
Stream<Event> get onUnmute => unmuteEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class MediaStreamTrackEvents extends Events {
- @DocsEditable
- MediaStreamTrackEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get ended => this['ended'];
-
- @DocsEditable
- EventListenerList get mute => this['mute'];
-
- @DocsEditable
- EventListenerList get unmute => this['unmute'];
-}
// 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.
@@ -18391,12 +17836,6 @@
@DocsEditable
static const EventStreamProvider<MessageEvent> messageEvent = const EventStreamProvider<MessageEvent>('message');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- MessagePortEvents get on =>
- new MessagePortEvents(this);
-
@DomName('MessagePort.addEventListener')
@DocsEditable
void $dom_addEventListener(String type, EventListener listener, [bool useCapture]) native "MessagePort_addEventListener_Callback";
@@ -18426,16 +17865,6 @@
Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class MessagePortEvents extends Events {
- @DocsEditable
- MessagePortEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get message => this['message'];
-}
// 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.
@@ -19826,12 +19255,6 @@
@DocsEditable
static Notification _create_1(title, options) native "Notification__create_1constructorCallback";
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- NotificationEvents get on =>
- new NotificationEvents(this);
-
@DomName('Notification.dir')
@DocsEditable
String get dir native "Notification_dir_Getter";
@@ -19909,28 +19332,6 @@
Stream<Event> get onShow => showEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class NotificationEvents extends Events {
- @DocsEditable
- NotificationEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get click => this['click'];
-
- @DocsEditable
- EventListenerList get close => this['close'];
-
- @DocsEditable
- EventListenerList get display => this['display'];
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get show => this['show'];
-}
// 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.
@@ -21198,12 +20599,6 @@
@DocsEditable
static const EventStreamProvider<Event> openEvent = const EventStreamProvider<Event>('open');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- RtcDataChannelEvents get on =>
- new RtcDataChannelEvents(this);
-
@DomName('RTCDataChannel.binaryType')
@DocsEditable
String get binaryType native "RTCDataChannel_binaryType_Getter";
@@ -21297,25 +20692,6 @@
Stream<Event> get onOpen => openEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class RtcDataChannelEvents extends Events {
- @DocsEditable
- RtcDataChannelEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get close => this['close'];
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get message => this['message'];
-
- @DocsEditable
- EventListenerList get open => this['open'];
-}
// 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.
@@ -21411,6 +20787,10 @@
@DocsEditable
static const EventStreamProvider<RtcDataChannelEvent> dataChannelEvent = const EventStreamProvider<RtcDataChannelEvent>('datachannel');
+ @DomName('RTCPeerConnection.gatheringchangeEvent')
+ @DocsEditable
+ static const EventStreamProvider<Event> gatheringChangeEvent = const EventStreamProvider<Event>('gatheringchange');
+
@DomName('RTCPeerConnection.icecandidateEvent')
@DocsEditable
static const EventStreamProvider<RtcIceCandidateEvent> iceCandidateEvent = const EventStreamProvider<RtcIceCandidateEvent>('icecandidate');
@@ -21440,12 +20820,6 @@
@DocsEditable
static RtcPeerConnection _create_1(rtcIceServers, mediaConstraints) native "RTCPeerConnection__create_1constructorCallback";
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- RtcPeerConnectionEvents get on =>
- new RtcPeerConnectionEvents(this);
-
@DomName('RTCPeerConnection.iceConnectionState')
@DocsEditable
String get iceConnectionState native "RTCPeerConnection_iceConnectionState_Getter";
@@ -21542,6 +20916,10 @@
@DocsEditable
Stream<RtcDataChannelEvent> get onDataChannel => dataChannelEvent.forTarget(this);
+ @DomName('RTCPeerConnection.ongatheringchange')
+ @DocsEditable
+ Stream<Event> get onGatheringChange => gatheringChangeEvent.forTarget(this);
+
@DomName('RTCPeerConnection.onicecandidate')
@DocsEditable
Stream<RtcIceCandidateEvent> get onIceCandidate => iceCandidateEvent.forTarget(this);
@@ -21565,31 +20943,6 @@
}
-
-@DocsEditable
-@deprecated
-class RtcPeerConnectionEvents extends Events {
- @DocsEditable
- RtcPeerConnectionEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get addStream => this['addstream'];
-
- @DocsEditable
- EventListenerList get iceCandidate => this['icecandidate'];
-
- @DocsEditable
- EventListenerList get iceChange => this['icechange'];
-
- @DocsEditable
- EventListenerList get negotiationNeeded => this['negotiationneeded'];
-
- @DocsEditable
- EventListenerList get removeStream => this['removestream'];
-
- @DocsEditable
- EventListenerList get stateChange => this['statechange'];
-}
// 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.
@@ -22221,12 +21574,6 @@
@DocsEditable
static const EventStreamProvider<Event> connectEvent = const EventStreamProvider<Event>('connect');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- SharedWorkerContextEvents get on =>
- new SharedWorkerContextEvents(this);
-
@DomName('SharedWorkerContext.name')
@DocsEditable
String get name native "SharedWorkerContext_name_Getter";
@@ -22236,16 +21583,6 @@
Stream<Event> get onConnect => connectEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class SharedWorkerContextEvents extends WorkerContextEvents {
- @DocsEditable
- SharedWorkerContextEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get connect => this['connect'];
-}
// 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.
@@ -22946,12 +22283,6 @@
/// Checks if this type is supported on the current platform.
static bool get supported => true;
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- SpeechRecognitionEvents get on =>
- new SpeechRecognitionEvents(this);
-
@DomName('SpeechRecognition.continuous')
@DocsEditable
bool get continuous native "SpeechRecognition_continuous_Getter";
@@ -23061,46 +22392,6 @@
Stream<Event> get onStart => startEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class SpeechRecognitionEvents extends Events {
- @DocsEditable
- SpeechRecognitionEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get audioEnd => this['audioend'];
-
- @DocsEditable
- EventListenerList get audioStart => this['audiostart'];
-
- @DocsEditable
- EventListenerList get end => this['end'];
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get noMatch => this['nomatch'];
-
- @DocsEditable
- EventListenerList get result => this['result'];
-
- @DocsEditable
- EventListenerList get soundEnd => this['soundend'];
-
- @DocsEditable
- EventListenerList get soundStart => this['soundstart'];
-
- @DocsEditable
- EventListenerList get speechEnd => this['speechend'];
-
- @DocsEditable
- EventListenerList get speechStart => this['speechstart'];
-
- @DocsEditable
- EventListenerList get start => this['start'];
-}
// 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.
@@ -24427,12 +23718,6 @@
@DocsEditable
static const EventStreamProvider<Event> cueChangeEvent = const EventStreamProvider<Event>('cuechange');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- TextTrackEvents get on =>
- new TextTrackEvents(this);
-
@DomName('TextTrack.activeCues')
@DocsEditable
TextTrackCueList get activeCues native "TextTrack_activeCues_Getter";
@@ -24486,16 +23771,6 @@
Stream<Event> get onCueChange => cueChangeEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class TextTrackEvents extends Events {
- @DocsEditable
- TextTrackEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get cueChange => this['cuechange'];
-}
// 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.
@@ -24525,12 +23800,6 @@
@DocsEditable
static TextTrackCue _create_1(startTime, endTime, text) native "TextTrackCue__create_1constructorCallback";
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- TextTrackCueEvents get on =>
- new TextTrackCueEvents(this);
-
@DomName('TextTrackCue.align')
@DocsEditable
String get align native "TextTrackCue_align_Getter";
@@ -24648,19 +23917,6 @@
Stream<Event> get onExit => exitEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class TextTrackCueEvents extends Events {
- @DocsEditable
- TextTrackCueEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get enter => this['enter'];
-
- @DocsEditable
- EventListenerList get exit => this['exit'];
-}
// 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.
@@ -24885,12 +24141,6 @@
@DocsEditable
static const EventStreamProvider<TrackEvent> addTrackEvent = const EventStreamProvider<TrackEvent>('addtrack');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- TextTrackListEvents get on =>
- new TextTrackListEvents(this);
-
@DomName('TextTrackList.length')
@DocsEditable
int get length native "TextTrackList_length_Getter";
@@ -25099,16 +24349,6 @@
Stream<TrackEvent> get onAddTrack => addTrackEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class TextTrackListEvents extends Events {
- @DocsEditable
- TextTrackListEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get addTrack => this['addtrack'];
-}
// 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.
@@ -28775,12 +28015,6 @@
/// Checks if this type is supported on the current platform.
static bool get supported => true;
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- WebSocketEvents get on =>
- new WebSocketEvents(this);
-
static const int CLOSED = 3;
static const int CLOSING = 2;
@@ -28879,25 +28113,6 @@
Stream<Event> get onOpen => openEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class WebSocketEvents extends Events {
- @DocsEditable
- WebSocketEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get close => this['close'];
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get message => this['message'];
-
- @DocsEditable
- EventListenerList get open => this['open'];
-}
// 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.
@@ -29087,12 +28302,6 @@
@Experimental
static const EventStreamProvider<AnimationEvent> animationStartEvent = const EventStreamProvider<AnimationEvent>('webkitAnimationStart');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- WindowEvents get on =>
- new WindowEvents(this);
-
static const int PERSISTENT = 1;
static const int TEMPORARY = 0;
@@ -29459,10 +28668,16 @@
@DomName('DOMWindow.webkitConvertPointFromNodeToPage')
@DocsEditable
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ @Experimental
DomPoint convertPointFromNodeToPage(Node node, DomPoint p) native "DOMWindow_webkitConvertPointFromNodeToPage_Callback";
@DomName('DOMWindow.webkitConvertPointFromPageToNode')
@DocsEditable
+ @SupportedBrowser(SupportedBrowser.CHROME)
+ @SupportedBrowser(SupportedBrowser.SAFARI)
+ @Experimental
DomPoint convertPointFromPageToNode(Node node, DomPoint p) native "DOMWindow_webkitConvertPointFromPageToNode_Callback";
@DomName('DOMWindow.webkitRequestFileSystem')
@@ -29694,235 +28909,6 @@
Stream<TransitionEvent> get onTransitionEnd => Element.transitionEndEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class WindowEvents extends Events {
- @DocsEditable
- WindowEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get contentLoaded => this['DOMContentLoaded'];
-
- @DocsEditable
- EventListenerList get abort => this['abort'];
-
- @DocsEditable
- EventListenerList get beforeUnload => this['beforeunload'];
-
- @DocsEditable
- EventListenerList get blur => this['blur'];
-
- @DocsEditable
- EventListenerList get canPlay => this['canplay'];
-
- @DocsEditable
- EventListenerList get canPlayThrough => this['canplaythrough'];
-
- @DocsEditable
- EventListenerList get change => this['change'];
-
- @DocsEditable
- EventListenerList get click => this['click'];
-
- @DocsEditable
- EventListenerList get contextMenu => this['contextmenu'];
-
- @DocsEditable
- EventListenerList get doubleClick => this['dblclick'];
-
- @DocsEditable
- EventListenerList get deviceMotion => this['devicemotion'];
-
- @DocsEditable
- EventListenerList get deviceOrientation => this['deviceorientation'];
-
- @DocsEditable
- EventListenerList get drag => this['drag'];
-
- @DocsEditable
- EventListenerList get dragEnd => this['dragend'];
-
- @DocsEditable
- EventListenerList get dragEnter => this['dragenter'];
-
- @DocsEditable
- EventListenerList get dragLeave => this['dragleave'];
-
- @DocsEditable
- EventListenerList get dragOver => this['dragover'];
-
- @DocsEditable
- EventListenerList get dragStart => this['dragstart'];
-
- @DocsEditable
- EventListenerList get drop => this['drop'];
-
- @DocsEditable
- EventListenerList get durationChange => this['durationchange'];
-
- @DocsEditable
- EventListenerList get emptied => this['emptied'];
-
- @DocsEditable
- EventListenerList get ended => this['ended'];
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get focus => this['focus'];
-
- @DocsEditable
- EventListenerList get hashChange => this['hashchange'];
-
- @DocsEditable
- EventListenerList get input => this['input'];
-
- @DocsEditable
- EventListenerList get invalid => this['invalid'];
-
- @DocsEditable
- EventListenerList get keyDown => this['keydown'];
-
- @DocsEditable
- EventListenerList get keyPress => this['keypress'];
-
- @DocsEditable
- EventListenerList get keyUp => this['keyup'];
-
- @DocsEditable
- EventListenerList get load => this['load'];
-
- @DocsEditable
- EventListenerList get loadedData => this['loadeddata'];
-
- @DocsEditable
- EventListenerList get loadedMetadata => this['loadedmetadata'];
-
- @DocsEditable
- EventListenerList get loadStart => this['loadstart'];
-
- @DocsEditable
- EventListenerList get message => this['message'];
-
- @DocsEditable
- EventListenerList get mouseDown => this['mousedown'];
-
- @DocsEditable
- EventListenerList get mouseMove => this['mousemove'];
-
- @DocsEditable
- EventListenerList get mouseOut => this['mouseout'];
-
- @DocsEditable
- EventListenerList get mouseOver => this['mouseover'];
-
- @DocsEditable
- EventListenerList get mouseUp => this['mouseup'];
-
- @DocsEditable
- EventListenerList get mouseWheel => this['mousewheel'];
-
- @DocsEditable
- EventListenerList get offline => this['offline'];
-
- @DocsEditable
- EventListenerList get online => this['online'];
-
- @DocsEditable
- EventListenerList get pageHide => this['pagehide'];
-
- @DocsEditable
- EventListenerList get pageShow => this['pageshow'];
-
- @DocsEditable
- EventListenerList get pause => this['pause'];
-
- @DocsEditable
- EventListenerList get play => this['play'];
-
- @DocsEditable
- EventListenerList get playing => this['playing'];
-
- @DocsEditable
- EventListenerList get popState => this['popstate'];
-
- @DocsEditable
- EventListenerList get progress => this['progress'];
-
- @DocsEditable
- EventListenerList get rateChange => this['ratechange'];
-
- @DocsEditable
- EventListenerList get reset => this['reset'];
-
- @DocsEditable
- EventListenerList get resize => this['resize'];
-
- @DocsEditable
- EventListenerList get scroll => this['scroll'];
-
- @DocsEditable
- EventListenerList get search => this['search'];
-
- @DocsEditable
- EventListenerList get seeked => this['seeked'];
-
- @DocsEditable
- EventListenerList get seeking => this['seeking'];
-
- @DocsEditable
- EventListenerList get select => this['select'];
-
- @DocsEditable
- EventListenerList get stalled => this['stalled'];
-
- @DocsEditable
- EventListenerList get storage => this['storage'];
-
- @DocsEditable
- EventListenerList get submit => this['submit'];
-
- @DocsEditable
- EventListenerList get suspend => this['suspend'];
-
- @DocsEditable
- EventListenerList get timeUpdate => this['timeupdate'];
-
- @DocsEditable
- EventListenerList get touchCancel => this['touchcancel'];
-
- @DocsEditable
- EventListenerList get touchEnd => this['touchend'];
-
- @DocsEditable
- EventListenerList get touchMove => this['touchmove'];
-
- @DocsEditable
- EventListenerList get touchStart => this['touchstart'];
-
- @DocsEditable
- EventListenerList get unload => this['unload'];
-
- @DocsEditable
- EventListenerList get volumeChange => this['volumechange'];
-
- @DocsEditable
- EventListenerList get waiting => this['waiting'];
-
- @DocsEditable
- EventListenerList get animationEnd => this['webkitAnimationEnd'];
-
- @DocsEditable
- EventListenerList get animationIteration => this['webkitAnimationIteration'];
-
- @DocsEditable
- EventListenerList get animationStart => this['webkitAnimationStart'];
-
- @DocsEditable
- EventListenerList get transitionEnd => this['webkitTransitionEnd'];
-}
// 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.
@@ -29948,12 +28934,6 @@
@DocsEditable
static Worker _create_1(scriptUrl) native "Worker__create_1constructorCallback";
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- WorkerEvents get on =>
- new WorkerEvents(this);
-
@DomName('Worker.postMessage')
@DocsEditable
void postMessage(/*SerializedScriptValue*/ message, [List messagePorts]) native "Worker_postMessage_Callback";
@@ -29967,16 +28947,6 @@
Stream<MessageEvent> get onMessage => messageEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class WorkerEvents extends AbstractWorkerEvents {
- @DocsEditable
- WorkerEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get message => this['message'];
-}
// 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.
@@ -29993,12 +28963,6 @@
@DocsEditable
static const EventStreamProvider<Event> errorEvent = const EventStreamProvider<Event>('error');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- WorkerContextEvents get on =>
- new WorkerContextEvents(this);
-
static const int PERSISTENT = 1;
static const int TEMPORARY = 0;
@@ -30109,16 +29073,6 @@
Stream<Event> get onError => errorEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class WorkerContextEvents extends Events {
- @DocsEditable
- WorkerContextEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get error => this['error'];
-}
// 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.
@@ -31901,58 +30855,6 @@
class _HTMLFrameSetElement extends _Element_Merged {
_HTMLFrameSetElement.internal() : super.internal();
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- _HTMLFrameSetElementEvents get on =>
- new _HTMLFrameSetElementEvents(this);
-
-}
-
-@DocsEditable
-@deprecated
-class _HTMLFrameSetElementEvents extends ElementEvents {
- @DocsEditable
- _HTMLFrameSetElementEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get beforeUnload => this['beforeunload'];
-
- @DocsEditable
- EventListenerList get blur => this['blur'];
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get focus => this['focus'];
-
- @DocsEditable
- EventListenerList get hashChange => this['hashchange'];
-
- @DocsEditable
- EventListenerList get load => this['load'];
-
- @DocsEditable
- EventListenerList get message => this['message'];
-
- @DocsEditable
- EventListenerList get offline => this['offline'];
-
- @DocsEditable
- EventListenerList get online => this['online'];
-
- @DocsEditable
- EventListenerList get popState => this['popstate'];
-
- @DocsEditable
- EventListenerList get resize => this['resize'];
-
- @DocsEditable
- EventListenerList get storage => this['storage'];
-
- @DocsEditable
- EventListenerList get unload => this['unload'];
}
// 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
@@ -35368,12 +34270,10 @@
// TODO(vsm): Set this up set once, on the first call.
var source = '$target-result';
var result = null;
- var listener = (Event e) {
+ window.on[source].first.then((Event e) {
result = json.parse(_getPortSyncEventData(e));
- };
- window.on[source].add(listener);
+ });
_dispatchEvent(target, [source, message]);
- window.on[source].remove(listener);
return result;
}
@@ -35428,7 +34328,7 @@
num _portId;
Function _callback;
- EventListener _listener;
+ StreamSubscription _portSubscription;
ReceivePortSync() {
if (_portIdCount == null) {
@@ -35453,21 +34353,20 @@
void receive(callback(var message)) {
_callback = callback;
- if (_listener == null) {
- _listener = (Event e) {
+ if (_portSubscription == null) {
+ _portSubscription = window.on[_listenerName].listen((Event e) {
var data = json.parse(_getPortSyncEventData(e));
var replyTo = data[0];
var message = _deserialize(data[1]);
var result = _callback(message);
_dispatchEvent(replyTo, _serialize(result));
- };
- window.on[_listenerName].add(_listener);
+ });
}
}
void close() {
_portMap.remove(_portId);
- if (_listener != null) window.on[_listenerName].remove(_listener);
+ if (_portSubscription != null) _portSubscription.cancel();
}
SendPortSync toSendPort() {
diff --git a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
index 318b36b..76547dd 100644
--- a/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
+++ b/sdk/lib/indexed_db/dart2js/indexed_db_dart2js.dart
@@ -190,11 +190,13 @@
@DomName('IDBCursorWithValue')
class CursorWithValue extends Cursor native "*IDBCursorWithValue" {
+ dynamic get value => _convertNativeToDart_IDBAny(this._value);
+ @JSName('value')
@DomName('IDBCursorWithValue.value')
@DocsEditable
@annotation_Creates_SerializedScriptValue
@annotation_Returns_SerializedScriptValue
- final Object value;
+ final dynamic _value;
}
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
@@ -238,12 +240,6 @@
@DocsEditable
static const EventStreamProvider<VersionChangeEvent> versionChangeEvent = const EventStreamProvider<VersionChangeEvent>('versionchange');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- DatabaseEvents get on =>
- new DatabaseEvents(this);
-
@DomName('IDBDatabase.name')
@DocsEditable
final String name;
@@ -310,22 +306,6 @@
@DocsEditable
Stream<VersionChangeEvent> get onVersionChange => versionChangeEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class DatabaseEvents extends Events {
- @DocsEditable
- DatabaseEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get abort => this['abort'];
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get versionChange => this['versionchange'];
-}
// 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.
@@ -616,7 +596,7 @@
* the current transaction.
*/
@DomName('IDBObjectStore.openCursor')
- Stream<Cursor> openCursor({key, KeyRange range, String direction,
+ Stream<CursorWithValue> openCursor({key, KeyRange range, String direction,
bool autoAdvance}) {
var key_OR_range = null;
if (key != null) {
@@ -702,29 +682,31 @@
@DocsEditable
Index createIndex(String name, keyPath, [Map options]) {
if ((keyPath is List<String> || keyPath == null) && !?options) {
- return _createIndex_1(name, keyPath);
+ List keyPath_1 = convertDartToNative_StringArray(keyPath);
+ return _createIndex_1(name, keyPath_1);
}
if ((keyPath is List<String> || keyPath == null)) {
- var options_1 = convertDartToNative_Dictionary(options);
- return _createIndex_2(name, keyPath, options_1);
+ List keyPath_2 = convertDartToNative_StringArray(keyPath);
+ var options_3 = convertDartToNative_Dictionary(options);
+ return _createIndex_2(name, keyPath_2, options_3);
}
if ((keyPath is String || keyPath == null) && !?options) {
return _createIndex_3(name, keyPath);
}
if ((keyPath is String || keyPath == null)) {
- var options_2 = convertDartToNative_Dictionary(options);
- return _createIndex_4(name, keyPath, options_2);
+ var options_4 = convertDartToNative_Dictionary(options);
+ return _createIndex_4(name, keyPath, options_4);
}
throw new ArgumentError("Incorrect number or type of arguments");
}
@JSName('createIndex')
@DomName('IDBObjectStore.createIndex')
@DocsEditable
- Index _createIndex_1(name, List<String> keyPath) native;
+ Index _createIndex_1(name, List keyPath) native;
@JSName('createIndex')
@DomName('IDBObjectStore.createIndex')
@DocsEditable
- Index _createIndex_2(name, List<String> keyPath, options) native;
+ Index _createIndex_2(name, List keyPath, options) native;
@JSName('createIndex')
@DomName('IDBObjectStore.createIndex')
@DocsEditable
@@ -800,7 +782,7 @@
// TODO: need to guarantee that the controller provides the values
// immediately as waiting until the next tick will cause the transaction to
// close.
- var controller = new StreamController<Cursor>();
+ var controller = new StreamController();
request.onError.listen((e) {
//TODO: Report stacktrace once issue 4061 is resolved.
@@ -838,12 +820,6 @@
@DocsEditable
static const EventStreamProvider<VersionChangeEvent> upgradeNeededEvent = const EventStreamProvider<VersionChangeEvent>('upgradeneeded');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- OpenDBRequestEvents get on =>
- new OpenDBRequestEvents(this);
-
@DomName('IDBOpenDBRequest.onblocked')
@DocsEditable
Stream<Event> get onBlocked => blockedEvent.forTarget(this);
@@ -852,19 +828,6 @@
@DocsEditable
Stream<VersionChangeEvent> get onUpgradeNeeded => upgradeNeededEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class OpenDBRequestEvents extends RequestEvents {
- @DocsEditable
- OpenDBRequestEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get blocked => this['blocked'];
-
- @DocsEditable
- EventListenerList get upgradeNeeded => this['upgradeneeded'];
-}
// 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.
@@ -882,12 +845,6 @@
@DocsEditable
static const EventStreamProvider<Event> successEvent = const EventStreamProvider<Event>('success');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- RequestEvents get on =>
- new RequestEvents(this);
-
@DomName('IDBRequest.error')
@DocsEditable
final DomError error;
@@ -942,19 +899,6 @@
@DocsEditable
Stream<Event> get onSuccess => successEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class RequestEvents extends Events {
- @DocsEditable
- RequestEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get success => this['success'];
-}
// 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.
@@ -1001,12 +945,6 @@
@DocsEditable
static const EventStreamProvider<Event> errorEvent = const EventStreamProvider<Event>('error');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- TransactionEvents get on =>
- new TransactionEvents(this);
-
@DomName('IDBTransaction.db')
@DocsEditable
final Database db;
@@ -1062,22 +1000,6 @@
Stream<Event> get onError => errorEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class TransactionEvents extends Events {
- @DocsEditable
- TransactionEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get abort => this['abort'];
-
- @DocsEditable
- EventListenerList get complete => this['complete'];
-
- @DocsEditable
- EventListenerList get error => this['error'];
-}
// 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.
diff --git a/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart b/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
index a19e78f..5aa80a1a 100644
--- a/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
+++ b/sdk/lib/indexed_db/dartium/indexed_db_dartium.dart
@@ -136,12 +136,6 @@
@DocsEditable
static const EventStreamProvider<VersionChangeEvent> versionChangeEvent = const EventStreamProvider<VersionChangeEvent>('versionchange');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- DatabaseEvents get on =>
- new DatabaseEvents(this);
-
@DomName('IDBDatabase.name')
@DocsEditable
String get name native "IDBDatabase_name_Getter";
@@ -216,22 +210,6 @@
Stream<VersionChangeEvent> get onVersionChange => versionChangeEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class DatabaseEvents extends Events {
- @DocsEditable
- DatabaseEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get abort => this['abort'];
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get versionChange => this['versionchange'];
-}
// 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.
@@ -672,7 +650,7 @@
* the current transaction.
*/
@DomName('IDBObjectStore.openCursor')
- Stream<Cursor> openCursor({key, KeyRange range, String direction,
+ Stream<CursorWithValue> openCursor({key, KeyRange range, String direction,
bool autoAdvance}) {
var key_OR_range = null;
if (key != null) {
@@ -885,7 +863,7 @@
// TODO: need to guarantee that the controller provides the values
// immediately as waiting until the next tick will cause the transaction to
// close.
- var controller = new StreamController<Cursor>();
+ var controller = new StreamController();
request.onError.listen((e) {
//TODO: Report stacktrace once issue 4061 is resolved.
@@ -926,12 +904,6 @@
@DocsEditable
static const EventStreamProvider<VersionChangeEvent> upgradeNeededEvent = const EventStreamProvider<VersionChangeEvent>('upgradeneeded');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- OpenDBRequestEvents get on =>
- new OpenDBRequestEvents(this);
-
@DomName('IDBOpenDBRequest.onblocked')
@DocsEditable
Stream<Event> get onBlocked => blockedEvent.forTarget(this);
@@ -941,19 +913,6 @@
Stream<VersionChangeEvent> get onUpgradeNeeded => upgradeNeededEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class OpenDBRequestEvents extends RequestEvents {
- @DocsEditable
- OpenDBRequestEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get blocked => this['blocked'];
-
- @DocsEditable
- EventListenerList get upgradeNeeded => this['upgradeneeded'];
-}
// 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.
@@ -974,12 +933,6 @@
@DocsEditable
static const EventStreamProvider<Event> successEvent = const EventStreamProvider<Event>('success');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- RequestEvents get on =>
- new RequestEvents(this);
-
@DomName('IDBRequest.error')
@DocsEditable
DomError get error native "IDBRequest_error_Getter";
@@ -1028,19 +981,6 @@
Stream<Event> get onSuccess => successEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class RequestEvents extends Events {
- @DocsEditable
- RequestEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get success => this['success'];
-}
// 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.
@@ -1088,12 +1028,6 @@
@DocsEditable
static const EventStreamProvider<Event> errorEvent = const EventStreamProvider<Event>('error');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- TransactionEvents get on =>
- new TransactionEvents(this);
-
@DomName('IDBTransaction.db')
@DocsEditable
Database get db native "IDBTransaction_db_Getter";
@@ -1146,22 +1080,6 @@
Stream<Event> get onError => errorEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class TransactionEvents extends Events {
- @DocsEditable
- TransactionEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get abort => this['abort'];
-
- @DocsEditable
- EventListenerList get complete => this['complete'];
-
- @DocsEditable
- EventListenerList get error => this['error'];
-}
// 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.
diff --git a/sdk/lib/svg/dart2js/svg_dart2js.dart b/sdk/lib/svg/dart2js/svg_dart2js.dart
index 9f47721..09a63ec 100644
--- a/sdk/lib/svg/dart2js/svg_dart2js.dart
+++ b/sdk/lib/svg/dart2js/svg_dart2js.dart
@@ -1043,12 +1043,6 @@
@DocsEditable
static const EventStreamProvider<Event> unloadEvent = const EventStreamProvider<Event>('unload');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- ElementInstanceEvents get on =>
- new ElementInstanceEvents(this);
-
@DomName('SVGElementInstance.childNodes')
@DocsEditable
@Returns('_ElementInstanceList')
@@ -1243,133 +1237,6 @@
@DocsEditable
Stream<Event> get onUnload => unloadEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class ElementInstanceEvents extends Events {
- @DocsEditable
- ElementInstanceEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get abort => this['abort'];
-
- @DocsEditable
- EventListenerList get beforeCopy => this['beforecopy'];
-
- @DocsEditable
- EventListenerList get beforeCut => this['beforecut'];
-
- @DocsEditable
- EventListenerList get beforePaste => this['beforepaste'];
-
- @DocsEditable
- EventListenerList get blur => this['blur'];
-
- @DocsEditable
- EventListenerList get change => this['change'];
-
- @DocsEditable
- EventListenerList get click => this['click'];
-
- @DocsEditable
- EventListenerList get contextMenu => this['contextmenu'];
-
- @DocsEditable
- EventListenerList get copy => this['copy'];
-
- @DocsEditable
- EventListenerList get cut => this['cut'];
-
- @DocsEditable
- EventListenerList get doubleClick => this['dblclick'];
-
- @DocsEditable
- EventListenerList get drag => this['drag'];
-
- @DocsEditable
- EventListenerList get dragEnd => this['dragend'];
-
- @DocsEditable
- EventListenerList get dragEnter => this['dragenter'];
-
- @DocsEditable
- EventListenerList get dragLeave => this['dragleave'];
-
- @DocsEditable
- EventListenerList get dragOver => this['dragover'];
-
- @DocsEditable
- EventListenerList get dragStart => this['dragstart'];
-
- @DocsEditable
- EventListenerList get drop => this['drop'];
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get focus => this['focus'];
-
- @DocsEditable
- EventListenerList get input => this['input'];
-
- @DocsEditable
- EventListenerList get keyDown => this['keydown'];
-
- @DocsEditable
- EventListenerList get keyPress => this['keypress'];
-
- @DocsEditable
- EventListenerList get keyUp => this['keyup'];
-
- @DocsEditable
- EventListenerList get load => this['load'];
-
- @DocsEditable
- EventListenerList get mouseDown => this['mousedown'];
-
- @DocsEditable
- EventListenerList get mouseMove => this['mousemove'];
-
- @DocsEditable
- EventListenerList get mouseOut => this['mouseout'];
-
- @DocsEditable
- EventListenerList get mouseOver => this['mouseover'];
-
- @DocsEditable
- EventListenerList get mouseUp => this['mouseup'];
-
- @DocsEditable
- EventListenerList get mouseWheel => this['mousewheel'];
-
- @DocsEditable
- EventListenerList get paste => this['paste'];
-
- @DocsEditable
- EventListenerList get reset => this['reset'];
-
- @DocsEditable
- EventListenerList get resize => this['resize'];
-
- @DocsEditable
- EventListenerList get scroll => this['scroll'];
-
- @DocsEditable
- EventListenerList get search => this['search'];
-
- @DocsEditable
- EventListenerList get select => this['select'];
-
- @DocsEditable
- EventListenerList get selectStart => this['selectstart'];
-
- @DocsEditable
- EventListenerList get submit => this['submit'];
-
- @DocsEditable
- EventListenerList get unload => this['unload'];
-}
// 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.
@@ -2326,6 +2193,10 @@
@DocsEditable
@DomName('SVGFEMorphologyElement')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
class FEMorphologyElement extends StyledElement implements FilterPrimitiveStandardAttributes native "*SVGFEMorphologyElement" {
static const int SVG_MORPHOLOGY_OPERATOR_DILATE = 2;
diff --git a/sdk/lib/svg/dartium/svg_dartium.dart b/sdk/lib/svg/dartium/svg_dartium.dart
index 70fbe36..debc991 100644
--- a/sdk/lib/svg/dartium/svg_dartium.dart
+++ b/sdk/lib/svg/dartium/svg_dartium.dart
@@ -1158,12 +1158,6 @@
@DocsEditable
static const EventStreamProvider<Event> unloadEvent = const EventStreamProvider<Event>('unload');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- ElementInstanceEvents get on =>
- new ElementInstanceEvents(this);
-
@DomName('SVGElementInstance.childNodes')
@DocsEditable
List<ElementInstance> get childNodes native "SVGElementInstance_childNodes_Getter";
@@ -1357,133 +1351,6 @@
Stream<Event> get onUnload => unloadEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class ElementInstanceEvents extends Events {
- @DocsEditable
- ElementInstanceEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get abort => this['abort'];
-
- @DocsEditable
- EventListenerList get beforeCopy => this['beforecopy'];
-
- @DocsEditable
- EventListenerList get beforeCut => this['beforecut'];
-
- @DocsEditable
- EventListenerList get beforePaste => this['beforepaste'];
-
- @DocsEditable
- EventListenerList get blur => this['blur'];
-
- @DocsEditable
- EventListenerList get change => this['change'];
-
- @DocsEditable
- EventListenerList get click => this['click'];
-
- @DocsEditable
- EventListenerList get contextMenu => this['contextmenu'];
-
- @DocsEditable
- EventListenerList get copy => this['copy'];
-
- @DocsEditable
- EventListenerList get cut => this['cut'];
-
- @DocsEditable
- EventListenerList get doubleClick => this['dblclick'];
-
- @DocsEditable
- EventListenerList get drag => this['drag'];
-
- @DocsEditable
- EventListenerList get dragEnd => this['dragend'];
-
- @DocsEditable
- EventListenerList get dragEnter => this['dragenter'];
-
- @DocsEditable
- EventListenerList get dragLeave => this['dragleave'];
-
- @DocsEditable
- EventListenerList get dragOver => this['dragover'];
-
- @DocsEditable
- EventListenerList get dragStart => this['dragstart'];
-
- @DocsEditable
- EventListenerList get drop => this['drop'];
-
- @DocsEditable
- EventListenerList get error => this['error'];
-
- @DocsEditable
- EventListenerList get focus => this['focus'];
-
- @DocsEditable
- EventListenerList get input => this['input'];
-
- @DocsEditable
- EventListenerList get keyDown => this['keydown'];
-
- @DocsEditable
- EventListenerList get keyPress => this['keypress'];
-
- @DocsEditable
- EventListenerList get keyUp => this['keyup'];
-
- @DocsEditable
- EventListenerList get load => this['load'];
-
- @DocsEditable
- EventListenerList get mouseDown => this['mousedown'];
-
- @DocsEditable
- EventListenerList get mouseMove => this['mousemove'];
-
- @DocsEditable
- EventListenerList get mouseOut => this['mouseout'];
-
- @DocsEditable
- EventListenerList get mouseOver => this['mouseover'];
-
- @DocsEditable
- EventListenerList get mouseUp => this['mouseup'];
-
- @DocsEditable
- EventListenerList get mouseWheel => this['mousewheel'];
-
- @DocsEditable
- EventListenerList get paste => this['paste'];
-
- @DocsEditable
- EventListenerList get reset => this['reset'];
-
- @DocsEditable
- EventListenerList get resize => this['resize'];
-
- @DocsEditable
- EventListenerList get scroll => this['scroll'];
-
- @DocsEditable
- EventListenerList get search => this['search'];
-
- @DocsEditable
- EventListenerList get select => this['select'];
-
- @DocsEditable
- EventListenerList get selectStart => this['selectstart'];
-
- @DocsEditable
- EventListenerList get submit => this['submit'];
-
- @DocsEditable
- EventListenerList get unload => this['unload'];
-}
// 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.
@@ -2510,6 +2377,10 @@
@DocsEditable
@DomName('SVGFEMorphologyElement')
+@SupportedBrowser(SupportedBrowser.CHROME)
+@SupportedBrowser(SupportedBrowser.FIREFOX)
+@SupportedBrowser(SupportedBrowser.IE, '10')
+@SupportedBrowser(SupportedBrowser.SAFARI)
class FEMorphologyElement extends StyledElement implements FilterPrimitiveStandardAttributes {
FEMorphologyElement.internal() : super.internal();
diff --git a/sdk/lib/uri/uri.dart b/sdk/lib/uri/uri.dart
index 3b1af61..abd1223 100644
--- a/sdk/lib/uri/uri.dart
+++ b/sdk/lib/uri/uri.dart
@@ -92,7 +92,7 @@
/**
* Returns `true` if the URI is absolute.
*/
- bool isAbsolute() {
+ bool get isAbsolute {
if ("" == scheme) return false;
if ("" != fragment) return false;
return true;
@@ -143,7 +143,7 @@
targetPath = removeDotSegments(reference.path);
targetQuery = reference.query;
} else {
- if (reference.hasAuthority()) {
+ if (reference.hasAuthority) {
targetUserInfo = reference.userInfo;
targetDomain = reference.domain;
targetPort = reference.port;
@@ -180,7 +180,7 @@
fragment: reference.fragment);
}
- bool hasAuthority() {
+ bool get hasAuthority {
return (userInfo != "") || (domain != "") || (port != 0);
}
@@ -219,7 +219,7 @@
String toString() {
StringBuffer sb = new StringBuffer();
_addIfNonEmpty(sb, scheme, scheme, ':');
- if (hasAuthority() || (scheme == "file")) {
+ if (hasAuthority || (scheme == "file")) {
sb.add("//");
_addIfNonEmpty(sb, userInfo, userInfo, "@");
sb.add(domain == null ? "null" : domain);
diff --git a/sdk/lib/web_audio/dart2js/web_audio_dart2js.dart b/sdk/lib/web_audio/dart2js/web_audio_dart2js.dart
index 6857253..6680a44 100644
--- a/sdk/lib/web_audio/dart2js/web_audio_dart2js.dart
+++ b/sdk/lib/web_audio/dart2js/web_audio_dart2js.dart
@@ -180,12 +180,6 @@
@DocsEditable
static const EventStreamProvider<Event> completeEvent = const EventStreamProvider<Event>('complete');
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- AudioContextEvents get on =>
- new AudioContextEvents(this);
-
@DomName('AudioContext.activeSourceCount')
@DocsEditable
final int activeSourceCount;
@@ -309,16 +303,6 @@
}
}
}
-
-@DocsEditable
-@deprecated
-class AudioContextEvents extends Events {
- @DocsEditable
- AudioContextEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get complete => this['complete'];
-}
// 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.
diff --git a/sdk/lib/web_audio/dartium/web_audio_dartium.dart b/sdk/lib/web_audio/dartium/web_audio_dartium.dart
index 765c957..23ad0a3 100644
--- a/sdk/lib/web_audio/dartium/web_audio_dartium.dart
+++ b/sdk/lib/web_audio/dartium/web_audio_dartium.dart
@@ -235,12 +235,6 @@
@DocsEditable
static AudioContext _create() native "AudioContext_constructorCallback";
- @DocsEditable
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
- @deprecated
- AudioContextEvents get on =>
- new AudioContextEvents(this);
-
@DomName('AudioContext.activeSourceCount')
@DocsEditable
int get activeSourceCount native "AudioContext_activeSourceCount_Getter";
@@ -411,16 +405,6 @@
Stream<Event> get onComplete => completeEvent.forTarget(this);
}
-
-@DocsEditable
-@deprecated
-class AudioContextEvents extends Events {
- @DocsEditable
- AudioContextEvents(EventTarget _ptr) : super(_ptr);
-
- @DocsEditable
- EventListenerList get complete => this['complete'];
-}
// 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.
diff --git a/tests/compiler/dart2js/cpa_inference_test.dart b/tests/compiler/dart2js/cpa_inference_test.dart
index 2e8e529..8aa2bae 100644
--- a/tests/compiler/dart2js/cpa_inference_test.dart
+++ b/tests/compiler/dart2js/cpa_inference_test.dart
@@ -53,7 +53,7 @@
BaseType nullType;
AnalysisResult(MockCompiler compiler) : this.compiler = compiler {
- inferrer = compiler.typesTask.concreteTypesInferrer;
+ inferrer = compiler.typesTask.typesInferrer;
int = inferrer.baseTypes.intBaseType;
double = inferrer.baseTypes.doubleBaseType;
num = inferrer.baseTypes.numBaseType;
@@ -177,7 +177,7 @@
enableConcreteTypeInference: true,
maxConcreteTypeSize: maxConcreteTypeSize);
compiler.sourceFiles[uri.toString()] = new SourceFile(uri.toString(), code);
- compiler.typesTask.concreteTypesInferrer.testMode = true;
+ compiler.typesTask.typesInferrer.testMode = true;
compiler.runCompiler(uri);
return new AnalysisResult(compiler);
}
diff --git a/tests/compiler/dart2js/mock_compiler.dart b/tests/compiler/dart2js/mock_compiler.dart
index 319c028..39ab912 100644
--- a/tests/compiler/dart2js/mock_compiler.dart
+++ b/tests/compiler/dart2js/mock_compiler.dart
@@ -69,23 +69,25 @@
toString() {}
}
class JSNumber {
- operator-() {}
- operator +(other) {}
- operator -(other) {}
- operator ~/(other) {}
- operator /(other) {}
- operator *(other) {}
- operator <<(other) {}
- operator >>(other) {}
- operator |(other) {}
- operator &(other) {}
- operator ^(other) {}
- operator >(other) {}
- operator >=(other) {}
- operator <(other) {}
- operator <=(other) {}
- operator ==(other) {}
- operator %(other) {}
+ // All these methods return a number to please type inferencing.
+ operator-() => (this is JSInt) ? 42 : 42.0;
+ operator +(other) => (this is JSInt) ? 42 : 42.0;
+ operator -(other) => (this is JSInt) ? 42 : 42.0;
+ operator ~/(other) => 42;
+ operator /(other) => (this is JSInt) ? 42 : 42.0;
+ operator *(other) => (this is JSInt) ? 42 : 42.0;
+ operator %(other) => (this is JSInt) ? 42 : 42.0;
+ operator <<(other) => 42;
+ operator >>(other) => 42;
+ operator |(other) => 42;
+ operator &(other) => 42;
+ operator ^(other) => 42;
+
+ operator >(other) => true;
+ operator >=(other) => true;
+ operator <(other) => true;
+ operator <=(other) => true;
+ operator ==(other) => true;
}
class JSInt {
}
diff --git a/tests/compiler/dart2js_extra/typevariable_factory_test.dart b/tests/compiler/dart2js_extra/typevariable_factory_test.dart
new file mode 100644
index 0000000..5618cae
--- /dev/null
+++ b/tests/compiler/dart2js_extra/typevariable_factory_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.
+
+// Regression test to ensure that we can use type variable in factories.
+
+class A<T> {
+ factory A.foo(o) {
+ Expect.isTrue(o is A<T>);
+ return new A();
+ }
+ A();
+}
+
+main() => new A<int>.foo(new A<int>());
diff --git a/tests/compiler/dart2js_extra/typevariable_substitution_test.dart b/tests/compiler/dart2js_extra/typevariable_substitution_test.dart
new file mode 100644
index 0000000..8a40a82
--- /dev/null
+++ b/tests/compiler/dart2js_extra/typevariable_substitution_test.dart
@@ -0,0 +1,18 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Regression test to ensure that we substitute type variables in is-tests.
+
+class A<T> {
+ A.foo(o) {
+ Expect.isTrue(o is A<T>);
+ }
+ A();
+}
+
+class B extends A<int> {
+ B.foo(o) : super.foo(o);
+}
+
+main() => new B.foo(new A<int>());
diff --git a/tests/corelib/string_codeunits_test.dart b/tests/corelib/string_codeunits_test.dart
new file mode 100644
index 0000000..81625c5
--- /dev/null
+++ b/tests/corelib/string_codeunits_test.dart
@@ -0,0 +1,44 @@
+// 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.
+
+main() {
+ test(String s) {
+ Iterable<int> units = s.codeUnits;
+ List<int> expectedUnits = <int>[];
+ for (int i = 0; i < s.length; i++) {
+ expectedUnits.add(s.codeUnitAt(i));
+ }
+
+ Expect.equals(s.length, units.length);
+ for (int i = 0; i < s.length; i++) {
+ Expect.equals(s.codeUnitAt(i), units.elementAt(i));
+ }
+
+ // for-in
+ var res = [];
+ for (int unit in units) {
+ res.add(unit);
+ }
+ Expect.listEquals(expectedUnits, res);
+
+ // .map
+ Expect.listEquals(expectedUnits.map((x) => x.toRadixString(16)).toList(),
+ units.map((x) => x.toRadixString(16)).toList());
+ }
+
+ test("abc");
+ test("\x00\u0000\u{000000}");
+ test("\u{ffff}\u{10000}\u{10ffff}");
+ String string = new String.fromCharCodes(
+ [0xdc00, 0xd800, 61, 0xd800, 0xdc00, 62, 0xdc00, 0xd800]);
+ test(string);
+
+ // Setting position in the middle of a surrogate pair is not allowed.
+ var r = new CodeUnits("\u{10000}");
+ var it = r.iterator;
+ Expect.isTrue(it.moveNext());
+ Expect.equals(0xD800, it.current);
+ Expect.isTrue(it.moveNext());
+ Expect.equals(0xDC00, it.current);
+}
diff --git a/tests/html/element_test.dart b/tests/html/element_test.dart
index 981db6d..d838efa 100644
--- a/tests/html/element_test.dart
+++ b/tests/html/element_test.dart
@@ -618,6 +618,18 @@
testUnsupported('removeLast', () => getQueryAll().removeLast());
});
+ group('functional', () {
+ test('scrollIntoView', () {
+ var child = new DivElement();
+ document.body.append(child);
+
+ child.scrollIntoView(ScrollAlignment.TOP);
+ child.scrollIntoView(ScrollAlignment.BOTTOM);
+ child.scrollIntoView(ScrollAlignment.CENTER);
+ child.scrollIntoView();
+ });
+ });
+
group('_ElementList', () {
List<Element> makeElList() => makeElementWithChildren().children;
diff --git a/tests/html/indexeddb_2_test.dart b/tests/html/indexeddb_2_test.dart
index f762d14..2ec96a5 100644
--- a/tests/html/indexeddb_2_test.dart
+++ b/tests/html/indexeddb_2_test.dart
@@ -24,22 +24,18 @@
var db;
// Delete any existing DBs.
return html.window.indexedDB.deleteDatabase(dbName).then((_) {
- html.window.console.log('open');
return html.window.indexedDB.open(dbName, version: version,
onUpgradeNeeded: createObjectStore);
}).then((result) {
- html.window.console.log('write');
db = result;
var transaction = db.transaction([storeName], 'readwrite');
transaction.objectStore(storeName).put(value, key);
return transaction.completed;
}).then((db) {
- html.window.console.log('read');
var transaction = db.transaction(storeName, 'readonly');
return transaction.objectStore(storeName).getObject(key);
}).then((object) {
- html.window.console.log('got close');
db.close();
check(value, object);
}).catchError((e) {
diff --git a/tests/html/indexeddb_4_test.dart b/tests/html/indexeddb_4_test.dart
index ff2f4b5..e331734 100644
--- a/tests/html/indexeddb_4_test.dart
+++ b/tests/html/indexeddb_4_test.dart
@@ -25,7 +25,8 @@
Future<Database> writeItems(Database db) {
Future<Object> write(index) {
var transaction = db.transaction([STORE_NAME], 'readwrite');
- return transaction.objectStore(STORE_NAME).put('Item $index', index);
+ return transaction.objectStore(STORE_NAME).put(
+ {'content': 'Item $index'}, index);
}
var future = write(0);
@@ -50,6 +51,8 @@
int lastKey;
cursors.listen((cursor) {
lastKey = cursor.key;
+ var value = cursor.value;
+ expect(value['content'], 'Item ${cursor.key}');
});
if (expectedFirst != null) {
diff --git a/tests/language/branch_canonicalization_test.dart b/tests/language/branch_canonicalization_test.dart
index 7e39572..0735076 100644
--- a/tests/language/branch_canonicalization_test.dart
+++ b/tests/language/branch_canonicalization_test.dart
@@ -1,6 +1,7 @@
// 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 branch fusion correctly sets branch environment for comparisons
// that require unboxing and does not fuse branches that can deoptimize.
@@ -60,6 +61,3 @@
Expect.equals(1, fooPoly(z, z));
Expect.isTrue(sideEffect);
}
-
-
-
diff --git a/tests/language/language.status b/tests/language/language.status
index 342fb06..c64f4c5 100644
--- a/tests/language/language.status
+++ b/tests/language/language.status
@@ -56,26 +56,11 @@
type_parameter_literal_test: Fail # Issue 7551
-mixin_field_test: Fail
-mixin_is_test: Fail
-mixin_method_test: Fail
-mixin_naming_test: Fail
-mixin_extends_field_test: Fail
-mixin_extends_is_test: Fail
-mixin_extends_method_test: Fail
-mixin_mixin_test: Fail
mixin_illegal_syntax_test/none: Fail
-mixin_illegal_superclass_test/none: Fail
-mixin_illegal_constructor_test/none: Fail
-mixin_illegal_static_access_test: Fail
-mixin_illegal_super_use_test/none: Fail
-mixin_implements_test: Fail
mixin_type_parameters_mixin_test: Fail
mixin_type_parameters_super_test: Fail
mixin_type_parameters_mixin_extends_test: Fail
mixin_type_parameters_super_extends_test: Fail
-mixin_this_use_test: Fail
-mixin_lib_extends_method_test: Fail
mixin_lib_extends_field_test: Fail
[ $compiler == none && ($system == macos || $system == linux) && $arch == ia32 && $checked ]
@@ -365,26 +350,12 @@
overridden_no_such_method_test: Fail, Pass, OK # Fails in minified mode, test depends on method names.
# Mixins fail on the VM.
-mixin_field_test: Fail # VM issue
-mixin_is_test: Fail # VM issue
-mixin_method_test: Fail # VM issue
-mixin_naming_test: Fail # VM issue
-mixin_extends_field_test: Fail # VM issue
-mixin_extends_is_test: Fail # VM issue
-mixin_extends_method_test: Fail # VM issue
-mixin_mixin_test: Fail # VM issue
mixin_illegal_syntax_test/none: Fail # VM issue
-mixin_illegal_superclass_test/none: Fail # VM issue
mixin_illegal_constructor_test/none: Fail # VM issue
-mixin_illegal_super_use_test/none: Fail # VM issue
-mixin_implements_test: Fail # VM issue
mixin_type_parameters_mixin_test: Fail # VM issue
mixin_type_parameters_super_test: Fail # VM issue
mixin_type_parameters_mixin_extends_test: Fail # VM issue
mixin_type_parameters_super_extends_test: Fail # VM issue
-mixin_this_use_test: Fail # VM issue
-mixin_lib_extends_method_test: Fail # VM issue
-mixin_lib_extends_field_test: Fail # VM issue
# Malformed types not handled as unresolved:
import_core_prefix_test: Fail
@@ -573,6 +544,7 @@
type_parameter_literal_test: Fail
[ $compiler == dart2dart && $minified ]
+
# TODO(tball): Assign proper bug numbers.
class_literal_test/none: Fail
diff --git a/tests/language/language_dart2js.status b/tests/language/language_dart2js.status
index 4ca2c13..14bbc37 100644
--- a/tests/language/language_dart2js.status
+++ b/tests/language/language_dart2js.status
@@ -89,6 +89,7 @@
compile_time_constant_checked3_test/06: Fail, OK
[ $compiler == dart2js ]
+branch_canonicalization_test: Fail # Issue 638.
div_with_power_of_two_test: Fail # Issue 8301.
call_operator_test: Fail # Issue 7622.
class_literal_test: Fail # Issue 7626.
diff --git a/tests/language/large_implicit_getter_test.dart b/tests/language/large_implicit_getter_test.dart
new file mode 100644
index 0000000..2eefe28
--- /dev/null
+++ b/tests/language/large_implicit_getter_test.dart
@@ -0,0 +1,1376 @@
+// 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 compilation of large implicit getters.
+
+List<List> panels = [
+[6853.940039224797,6050.837897021371]
+,[6953.240039224797,6050.837897021371]
+,[7052.5400392247975,5885.237897021371]
+,[7052.5400392247975,5719.637897021372]
+,[7151.840039224798,5885.237897021371]
+,[7052.5400392247975,6050.837897021371]
+,[7052.5400392247975,6216.43789702137]
+,[7052.5400392247975,6382.03789702137]
+,[6953.240039224797,6382.03789702137]
+,[6953.240039224797,6216.43789702137]
+,[6853.940039224797,6216.43789702137]
+,[6853.940039224797,6382.03789702137]
+,[6754.640039224797,6216.43789702137]
+,[6754.640039224797,6382.03789702137]
+,[6754.640039224797,6547.637897021369]
+,[6754.640039224797,6713.237897021369]
+,[6655.340039224797,6713.237897021369]
+,[6754.640039224797,6878.837897021368]
+,[6853.940039224797,6713.237897021369]
+,[6853.940039224797,6878.837897021368]
+,[6953.240039224797,6713.237897021369]
+,[7052.5400392247975,6547.637897021369]
+,[7151.840039224798,6713.237897021369]
+,[7151.840039224798,6547.637897021369]
+,[7151.840039224798,6382.03789702137]
+,[7251.140039224798,6547.637897021369]
+,[7251.140039224798,6713.237897021369]
+,[7350.440039224798,6878.837897021368]
+,[7449.740039224798,6878.837897021368]
+,[7449.740039224798,6713.237897021369]
+,[7549.040039224798,6547.637897021369]
+,[7449.740039224798,6382.03789702137]
+,[7449.740039224798,6216.43789702137]
+,[7549.040039224798,6050.837897021371]
+,[7648.340039224799,6216.43789702137]
+,[7549.040039224798,6382.03789702137]
+,[7648.340039224799,6382.03789702137]
+,[7747.640039224799,6216.43789702137]
+,[7846.940039224799,6382.03789702137]
+,[7946.240039224799,6382.03789702137]
+,[7946.240039224799,6547.637897021369]
+,[7846.940039224799,6713.237897021369]
+,[7946.240039224799,6713.237897021369]
+,[8045.540039224799,6547.637897021369]
+,[8045.540039224799,6713.237897021369]
+,[7946.240039224799,6878.837897021368]
+,[7946.240039224799,7044.4378970213675]
+,[8045.540039224799,7210.037897021367]
+,[8144.8400392247995,7375.637897021366]
+,[8144.8400392247995,7541.237897021366]
+,[8045.540039224799,7375.637897021366]
+,[8144.8400392247995,7210.037897021367]
+,[8045.540039224799,7044.4378970213675]
+,[7946.240039224799,7210.037897021367]
+,[7846.940039224799,7210.037897021367]
+,[7946.240039224799,7375.637897021366]
+,[8045.540039224799,7541.237897021366]
+,[8144.8400392247995,7706.837897021365]
+,[8244.1400392248,7541.237897021366]
+,[8343.4400392248,7541.237897021366]
+,[8343.4400392248,7706.837897021365]
+,[8244.1400392248,7706.837897021365]
+,[4735.523842661975,3503.497768214323]
+,[4636.223842661975,3337.897768214323]
+,[4536.923842661975,3337.897768214323]
+,[4437.623842661975,3172.2977682143232]
+,[4338.323842661975,3172.2977682143232]
+,[4239.023842661974,3172.2977682143232]
+,[4338.323842661975,3006.6977682143233]
+,[4437.623842661975,2841.0977682143234]
+,[4338.323842661975,2675.4977682143235]
+,[4338.323842661975,2509.8977682143236]
+,[4239.023842661974,2675.4977682143235]
+,[4139.723842661974,2509.8977682143236]
+,[4040.4238426619745,2344.2977682143237]
+,[4139.723842661974,2178.697768214324]
+,[4239.023842661974,2178.697768214324]
+,[4139.723842661974,2344.2977682143237]
+,[4040.4238426619745,2178.697768214324]
+,[4139.723842661974,2013.0977682143237]
+,[4139.723842661974,1847.4977682143235]
+,[4239.023842661974,2013.0977682143237]
+,[4239.023842661974,1847.4977682143235]
+,[4338.323842661975,1847.4977682143235]
+,[4437.623842661975,1847.4977682143235]
+,[4536.923842661975,1681.8977682143234]
+,[4437.623842661975,1516.2977682143232]
+,[4536.923842661975,1516.2977682143232]
+,[4536.923842661975,1350.697768214323]
+,[4437.623842661975,1350.697768214323]
+,[4536.923842661975,1185.097768214323]
+,[4636.223842661975,1019.497768214323]
+,[4536.923842661975,853.897768214323]
+,[4636.223842661975,853.897768214323]
+,[4735.523842661975,688.2977682143231]
+,[4636.223842661975,522.6977682143232]
+,[4636.223842661975,357.09776821432325]
+,[4735.523842661975,357.09776821432325]
+,[4735.523842661975,522.6977682143232]
+,[4636.223842661975,688.2977682143231]
+,[4735.523842661975,853.897768214323]
+,[4834.8238426619755,853.897768214323]
+,[4735.523842661975,1019.497768214323]
+,[4735.523842661975,1185.097768214323]
+,[4735.523842661975,1350.697768214323]
+,[4834.8238426619755,1516.2977682143232]
+,[4735.523842661975,1516.2977682143232]
+,[4834.8238426619755,1350.697768214323]
+,[4834.8238426619755,1185.097768214323]
+,[4934.123842661976,1350.697768214323]
+,[5033.423842661976,1185.097768214323]
+,[5033.423842661976,1019.497768214323]
+,[5033.423842661976,853.897768214323]
+,[4934.123842661976,853.897768214323]
+,[4934.123842661976,1019.497768214323]
+,[4834.8238426619755,1019.497768214323]
+,[4934.123842661976,1185.097768214323]
+,[5033.423842661976,1350.697768214323]
+,[5132.723842661976,1350.697768214323]
+,[5132.723842661976,1185.097768214323]
+,[5232.023842661976,1019.497768214323]
+,[5232.023842661976,1185.097768214323]
+,[5331.323842661976,1019.497768214323]
+,[5430.623842661977,1019.497768214323]
+,[5529.923842661977,1185.097768214323]
+,[5430.623842661977,1350.697768214323]
+,[5430.623842661977,1516.2977682143232]
+,[5529.923842661977,1350.697768214323]
+,[5629.223842661977,1350.697768214323]
+,[5728.523842661977,1350.697768214323]
+,[5728.523842661977,1516.2977682143232]
+,[5728.523842661977,1681.8977682143234]
+,[5629.223842661977,1516.2977682143232]
+,[5529.923842661977,1516.2977682143232]
+,[5629.223842661977,1681.8977682143234]
+,[5529.923842661977,1681.8977682143234]
+,[5430.623842661977,1847.4977682143235]
+,[5331.323842661976,1847.4977682143235]
+,[5331.323842661976,2013.0977682143237]
+,[5232.023842661976,2178.697768214324]
+,[5132.723842661976,2013.0977682143237]
+,[5132.723842661976,2178.697768214324]
+,[5232.023842661976,2013.0977682143237]
+,[5232.023842661976,1847.4977682143235]
+,[5232.023842661976,1681.8977682143234]
+,[5331.323842661976,1681.8977682143234]
+,[5331.323842661976,1516.2977682143232]
+,[5331.323842661976,1350.697768214323]
+,[5232.023842661976,1350.697768214323]
+,[5232.023842661976,1516.2977682143232]
+,[5132.723842661976,1516.2977682143232]
+,[5132.723842661976,1681.8977682143234]
+,[5033.423842661976,1847.4977682143235]
+,[5132.723842661976,1847.4977682143235]
+,[5033.423842661976,2013.0977682143237]
+,[4934.123842661976,2178.697768214324]
+,[5033.423842661976,2344.2977682143237]
+,[4934.123842661976,2344.2977682143237]
+,[4834.8238426619755,2178.697768214324]
+,[4834.8238426619755,2344.2977682143237]
+,[4735.523842661975,2344.2977682143237]
+,[4636.223842661975,2344.2977682143237]
+,[4536.923842661975,2178.697768214324]
+,[4437.623842661975,2013.0977682143237]
+,[4338.323842661975,2178.697768214324]
+,[4437.623842661975,2344.2977682143237]
+,[4536.923842661975,2509.8977682143236]
+,[4636.223842661975,2675.4977682143235]
+,[4636.223842661975,2509.8977682143236]
+,[4536.923842661975,2675.4977682143235]
+,[4636.223842661975,2841.0977682143234]
+,[4536.923842661975,2841.0977682143234]
+,[4636.223842661975,3006.6977682143233]
+,[4735.523842661975,3172.2977682143232]
+,[4834.8238426619755,3006.6977682143233]
+,[4735.523842661975,2841.0977682143234]
+,[4735.523842661975,3006.6977682143233]
+,[4636.223842661975,3172.2977682143232]
+,[4735.523842661975,3337.897768214323]
+,[4834.8238426619755,3503.497768214323]
+,[4735.523842661975,3669.097768214323]
+,[4834.8238426619755,3834.697768214323]
+,[4834.8238426619755,3669.097768214323]
+,[4934.123842661976,3503.497768214323]
+,[5033.423842661976,3503.497768214323]
+,[5033.423842661976,3337.897768214323]
+,[4934.123842661976,3337.897768214323]
+,[4834.8238426619755,3172.2977682143232]
+,[4834.8238426619755,3337.897768214323]
+,[4934.123842661976,3172.2977682143232]
+,[5033.423842661976,3006.6977682143233]
+,[5132.723842661976,2841.0977682143234]
+,[5132.723842661976,3006.6977682143233]
+,[5232.023842661976,3172.2977682143232]
+,[5232.023842661976,3337.897768214323]
+,[5132.723842661976,3337.897768214323]
+,[5232.023842661976,3503.497768214323]
+,[5331.323842661976,3337.897768214323]
+,[5331.323842661976,3503.497768214323]
+,[5430.623842661977,3669.097768214323]
+,[5331.323842661976,3669.097768214323]
+,[5430.623842661977,3503.497768214323]
+,[5430.623842661977,3337.897768214323]
+,[5529.923842661977,3172.2977682143232]
+,[5529.923842661977,3337.897768214323]
+,[5629.223842661977,3337.897768214323]
+,[5728.523842661977,3337.897768214323]
+,[5728.523842661977,3503.497768214323]
+,[5827.823842661977,3503.497768214323]
+,[5927.1238426619775,3669.097768214323]
+,[6026.423842661978,3669.097768214323]
+,[6125.723842661978,3503.497768214323]
+,[6125.723842661978,3669.097768214323]
+,[6225.023842661978,3503.497768214323]
+,[6225.023842661978,3337.897768214323]
+,[6324.323842661978,3337.897768214323]
+,[6423.623842661978,3503.497768214323]
+,[6324.323842661978,3669.097768214323]
+,[6225.023842661978,3669.097768214323]
+,[6324.323842661978,3834.697768214323]
+,[6423.623842661978,3834.697768214323]
+,[6324.323842661978,4000.297768214323]
+,[6225.023842661978,3834.697768214323]
+,[6125.723842661978,3834.697768214323]
+,[6125.723842661978,4000.297768214323]
+,[6225.023842661978,4000.297768214323]
+,[6225.023842661978,4165.897768214322]
+,[6225.023842661978,4331.497768214322]
+,[6125.723842661978,4165.897768214322]
+,[6026.423842661978,4000.2977682143223]
+,[5927.1238426619775,4165.897768214322]
+,[6026.423842661978,4331.497768214322]
+,[6026.423842661978,4497.097768214321]
+,[5927.1238426619775,4497.097768214321]
+,[5827.823842661977,4662.697768214321]
+,[5728.523842661977,4828.29776821432]
+,[5827.823842661977,4828.29776821432]
+,[5927.1238426619775,4828.29776821432]
+,[5927.1238426619775,4662.697768214321]
+,[5827.823842661977,4497.097768214321]
+,[5927.1238426619775,4331.497768214322]
+,[5827.823842661977,4165.897768214322]
+,[5728.523842661977,4331.497768214322]
+,[5728.523842661977,4165.897768214322]
+,[5629.223842661977,4000.2977682143223]
+,[5629.223842661977,3834.6977682143224]
+,[5529.923842661977,3669.0977682143225]
+,[5629.223842661977,3503.4977682143226]
+,[5728.523842661977,3669.0977682143225]
+,[5827.823842661977,3669.0977682143225]
+,[5927.1238426619775,3834.6977682143224]
+,[5927.1238426619775,4000.2977682143223]
+,[6026.423842661978,4165.897768214322]
+,[6125.723842661978,4331.497768214322]
+,[6225.023842661978,4497.097768214321]
+,[6225.023842661978,4662.697768214321]
+,[6324.323842661978,4662.697768214321]
+,[6225.023842661978,4828.29776821432]
+,[6324.323842661978,4828.29776821432]
+,[6423.623842661978,4828.29776821432]
+,[6324.323842661978,4993.8977682143195]
+,[6225.023842661978,5159.497768214319]
+,[6125.723842661978,5159.497768214319]
+,[6026.423842661978,5325.097768214318]
+,[5927.1238426619775,5490.697768214318]
+,[6026.423842661978,5656.297768214317]
+,[5927.1238426619775,5821.897768214317]
+,[5927.1238426619775,5987.497768214316]
+,[6026.423842661978,5987.497768214316]
+,[6026.423842661978,5821.897768214317]
+,[5927.1238426619775,5656.297768214317]
+,[5827.823842661977,5656.297768214317]
+,[5827.823842661977,5490.697768214318]
+,[5728.523842661977,5490.697768214318]
+,[5629.223842661977,5325.097768214318]
+,[5629.223842661977,5159.497768214319]
+,[5529.923842661977,4993.8977682143195]
+,[5529.923842661977,5159.497768214319]
+,[5629.223842661977,4993.8977682143195]
+,[5629.223842661977,4828.29776821432]
+,[5529.923842661977,4662.697768214321]
+,[5430.623842661977,4828.29776821432]
+,[5529.923842661977,4828.29776821432]
+,[5629.223842661977,4662.697768214321]
+,[5728.523842661977,4662.697768214321]
+,[5629.223842661977,4497.097768214321]
+,[5728.523842661977,4497.097768214321]
+,[5827.823842661977,4331.497768214322]
+,[10216.161365168813,2951.605409896135]
+,[10116.861365168812,2951.605409896135]
+,[10017.56136516881,3117.205409896135]
+,[9918.26136516881,3117.205409896135]
+,[9818.961365168809,3117.205409896135]
+,[9719.661365168808,3282.8054098961347]
+,[9620.361365168807,3282.8054098961347]
+,[9620.361365168807,3117.205409896135]
+,[9521.061365168805,2951.605409896135]
+,[9521.061365168805,2786.005409896135]
+,[9620.361365168807,2786.005409896135]
+,[9719.661365168808,2786.005409896135]
+,[9818.961365168809,2620.405409896135]
+,[9918.26136516881,2786.005409896135]
+,[9818.961365168809,2951.605409896135]
+,[9818.961365168809,2786.005409896135]
+,[9719.661365168808,2620.405409896135]
+,[9719.661365168808,2454.805409896135]
+,[9620.361365168807,2289.2054098961353]
+,[9521.061365168805,2123.6054098961354]
+,[9620.361365168807,1958.0054098961352]
+,[9719.661365168808,2123.6054098961354]
+,[9818.961365168809,2289.2054098961353]
+,[9818.961365168809,2123.6054098961354]
+,[9818.961365168809,1958.0054098961352]
+,[9719.661365168808,1958.0054098961352]
+,[9620.361365168807,1792.405409896135]
+,[9620.361365168807,1626.805409896135]
+,[9521.061365168805,1461.2054098961348]
+,[9421.761365168804,1295.6054098961347]
+,[9521.061365168805,1130.0054098961346]
+,[9521.061365168805,964.4054098961345]
+,[9421.761365168804,964.4054098961345]
+,[9521.061365168805,798.8054098961346]
+,[9620.361365168807,798.8054098961346]
+,[9620.361365168807,964.4054098961345]
+,[9620.361365168807,1130.0054098961346]
+,[9620.361365168807,1295.6054098961347]
+,[9620.361365168807,1461.2054098961348]
+,[9719.661365168808,1295.6054098961347]
+,[9818.961365168809,1130.0054098961346]
+,[9918.26136516881,964.4054098961345]
+,[9818.961365168809,964.4054098961345]
+,[9918.26136516881,798.8054098961346]
+,[10017.56136516881,633.2054098961347]
+,[9918.26136516881,467.60540989613474]
+,[9918.26136516881,302.0054098961348]
+,[10017.56136516881,302.0054098961348]
+,[10116.861365168812,136.40540989613478]
+,[10116.861365168812,302.0054098961348]
+,[10116.861365168812,467.60540989613474]
+,[10116.861365168812,633.2054098961347]
+,[10216.161365168813,633.2054098961347]
+,[10216.161365168813,798.8054098961346]
+,[10315.461365168814,633.2054098961347]
+,[10315.461365168814,798.8054098961346]
+,[10414.761365168815,798.8054098961346]
+,[10514.061365168816,633.2054098961347]
+,[10514.061365168816,798.8054098961346]
+,[10414.761365168815,964.4054098961345]
+,[10315.461365168814,964.4054098961345]
+,[10216.161365168813,964.4054098961345]
+,[10116.861365168812,798.8054098961346]
+,[10017.56136516881,798.8054098961346]
+,[10116.861365168812,964.4054098961345]
+,[10216.161365168813,1130.0054098961346]
+,[10116.861365168812,1130.0054098961346]
+,[10216.161365168813,1295.6054098961347]
+,[10216.161365168813,1461.2054098961348]
+,[10315.461365168814,1626.805409896135]
+,[10315.461365168814,1792.405409896135]
+,[10216.161365168813,1958.0054098961352]
+,[10216.161365168813,1792.405409896135]
+,[10116.861365168812,1792.405409896135]
+,[10017.56136516881,1958.0054098961352]
+,[9918.26136516881,2123.6054098961354]
+,[9918.26136516881,1958.0054098961352]
+,[10017.56136516881,2123.6054098961354]
+,[10116.861365168812,2123.6054098961354]
+,[10017.56136516881,2289.2054098961353]
+,[10017.56136516881,2454.805409896135]
+,[10116.861365168812,2289.2054098961353]
+,[10216.161365168813,2454.805409896135]
+,[10315.461365168814,2620.405409896135]
+,[10315.461365168814,2454.805409896135]
+,[10315.461365168814,2289.2054098961353]
+,[10414.761365168815,2454.805409896135]
+,[10514.061365168816,2620.405409896135]
+,[10613.361365168817,2786.005409896135]
+,[10514.061365168816,2786.005409896135]
+,[10613.361365168817,2620.405409896135]
+,[10514.061365168816,2454.805409896135]
+,[10514.061365168816,2289.2054098961353]
+,[10613.361365168817,2289.2054098961353]
+,[10712.661365168819,2289.2054098961353]
+,[10811.96136516882,2454.805409896135]
+,[10911.26136516882,2289.2054098961353]
+,[10811.96136516882,2289.2054098961353]
+,[10712.661365168819,2454.805409896135]
+,[10712.661365168819,2620.405409896135]
+,[10811.96136516882,2786.005409896135]
+,[10911.26136516882,2620.405409896135]
+,[10911.26136516882,2786.005409896135]
+,[11010.561365168822,2620.405409896135]
+,[10911.26136516882,2454.805409896135]
+,[10811.96136516882,2620.405409896135]
+,[10712.661365168819,2786.005409896135]
+,[10811.96136516882,2951.605409896135]
+,[10911.26136516882,2951.605409896135]
+,[10811.96136516882,3117.205409896135]
+,[10712.661365168819,2951.605409896135]
+,[10613.361365168817,2951.605409896135]
+,[10514.061365168816,2951.605409896135]
+,[10414.761365168815,3117.205409896135]
+,[10414.761365168815,2951.605409896135]
+,[10315.461365168814,2786.005409896135]
+,[10216.161365168813,2620.405409896135]
+,[10216.161365168813,2786.005409896135]
+,[10315.461365168814,2951.605409896135]
+,[10315.461365168814,3117.205409896135]
+,[10216.161365168813,3117.205409896135]
+,[10116.861365168812,3117.205409896135]
+,[10017.56136516881,3282.8054098961347]
+,[9918.26136516881,3448.4054098961346]
+,[9818.961365168809,3448.4054098961346]
+,[9818.961365168809,3614.0054098961346]
+,[9719.661365168808,3448.4054098961346]
+,[9818.961365168809,3282.8054098961347]
+,[9719.661365168808,3117.205409896135]
+,[9620.361365168807,2951.605409896135]
+,[9521.061365168805,3117.205409896135]
+,[9521.061365168805,3282.8054098961347]
+,[9421.761365168804,3117.205409896135]
+,[9421.761365168804,3282.8054098961347]
+,[9322.461365168803,3117.205409896135]
+,[9421.761365168804,2951.605409896135]
+,[9322.461365168803,2951.605409896135]
+,[9223.161365168802,2786.005409896135]
+,[9322.461365168803,2620.405409896135]
+,[9421.761365168804,2454.805409896135]
+,[9521.061365168805,2289.2054098961353]
+,[9421.761365168804,2123.6054098961354]
+,[9421.761365168804,1958.0054098961352]
+,[9421.761365168804,1792.405409896135]
+,[9521.061365168805,1626.805409896135]
+,[9421.761365168804,1626.805409896135]
+,[9322.461365168803,1792.405409896135]
+,[9322.461365168803,1626.805409896135]
+,[9322.461365168803,1461.2054098961348]
+,[9421.761365168804,1461.2054098961348]
+,[9521.061365168805,1295.6054098961347]
+,[9421.761365168804,1130.0054098961346]
+,[9322.461365168803,964.4054098961345]
+,[9223.161365168802,964.4054098961345]
+,[9223.161365168802,798.8054098961346]
+,[9322.461365168803,633.2054098961347]
+,[9421.761365168804,798.8054098961346]
+,[9421.761365168804,633.2054098961347]
+,[9521.061365168805,633.2054098961347]
+,[9421.761365168804,467.60540989613474]
+,[9421.761365168804,302.0054098961348]
+,[9322.461365168803,136.40540989613478]
+,[9223.161365168802,302.0054098961348]
+,[9123.861365168801,302.0054098961348]
+,[9024.5613651688,136.40540989613478]
+,[9123.861365168801,136.40540989613478]
+,[9223.161365168802,136.40540989613478]
+,[9322.461365168803,302.0054098961348]
+,[9421.761365168804,136.40540989613478]
+,[9521.061365168805,136.40540989613478]
+,[9620.361365168807,136.40540989613478]
+,[9620.361365168807,302.0054098961348]
+,[9521.061365168805,302.0054098961348]
+,[9521.061365168805,467.60540989613474]
+,[9620.361365168807,467.60540989613474]
+,[9719.661365168808,302.0054098961348]
+,[9719.661365168808,136.40540989613478]
+,[9818.961365168809,136.40540989613478]
+,[9918.26136516881,136.40540989613478]
+,[10017.56136516881,136.40540989613478]
+,[366.07287160549004,5394.185440937868]
+,[465.37287160549005,5394.185440937868]
+,[465.37287160549005,5559.785440937868]
+,[366.0728716054901,5559.785440937868]
+,[366.0728716054901,5725.385440937867]
+,[266.77287160549014,5725.385440937867]
+,[167.47287160549016,5559.785440937868]
+,[266.77287160549014,5559.785440937868]
+,[266.77287160549014,5394.185440937868]
+,[266.77287160549014,5228.585440937869]
+,[167.47287160549016,5394.185440937868]
+,[68.17287160549016,5228.585440937869]
+,[167.47287160549013,5062.9854409378695]
+,[68.17287160549013,4897.38544093787]
+,[167.47287160549013,4731.785440937871]
+,[266.77287160549014,4731.785440937871]
+,[167.47287160549016,4566.185440937871]
+,[68.17287160549016,4566.185440937871]
+,[68.17287160549016,4731.785440937871]
+,[167.47287160549013,4897.38544093787]
+,[68.17287160549013,5062.9854409378695]
+,[167.47287160549013,5228.585440937869]
+,[266.77287160549014,5062.9854409378695]
+,[366.0728716054901,4897.38544093787]
+,[266.77287160549014,4897.38544093787]
+,[366.0728716054901,4731.785440937871]
+,[465.37287160549005,4897.38544093787]
+,[366.0728716054901,5062.9854409378695]
+,[465.37287160549005,5062.9854409378695]
+,[366.0728716054901,5228.585440937869]
+,[465.37287160549005,5228.585440937869]
+,[564.6728716054901,5394.185440937868]
+,[663.9728716054901,5228.585440937869]
+,[564.6728716054901,5062.9854409378695]
+,[663.9728716054901,4897.38544093787]
+,[763.2728716054902,4731.785440937871]
+,[862.5728716054903,4566.185440937871]
+,[961.8728716054903,4731.785440937871]
+,[862.5728716054903,4731.785440937871]
+,[961.8728716054903,4566.185440937871]
+,[862.5728716054903,4400.585440937872]
+,[961.8728716054903,4234.985440937872]
+,[1061.1728716054904,4400.585440937872]
+,[1160.4728716054904,4234.985440937872]
+,[1160.4728716054904,4400.585440937872]
+,[1259.7728716054903,4234.985440937872]
+,[1359.0728716054903,4069.3854409378723]
+,[1458.3728716054902,4069.3854409378723]
+,[1557.6728716054902,4234.985440937872]
+,[1656.9728716054901,4400.585440937872]
+,[1557.6728716054902,4400.585440937872]
+,[1458.3728716054902,4400.585440937872]
+,[1359.0728716054903,4566.185440937871]
+,[1359.0728716054903,4731.785440937871]
+,[1259.7728716054903,4731.785440937871]
+,[1359.0728716054903,4897.38544093787]
+,[1458.3728716054902,4731.785440937871]
+,[1458.3728716054902,4897.38544093787]
+,[1359.0728716054903,5062.9854409378695]
+,[1259.7728716054903,5228.585440937869]
+,[1259.7728716054903,5062.9854409378695]
+,[1259.7728716054903,4897.38544093787]
+,[1160.4728716054904,5062.9854409378695]
+,[1160.4728716054904,5228.585440937869]
+,[1061.1728716054904,5228.585440937869]
+,[1061.1728716054904,5062.9854409378695]
+,[961.8728716054903,5228.585440937869]
+,[862.5728716054903,5062.9854409378695]
+,[961.8728716054903,5062.9854409378695]
+,[961.8728716054903,4897.38544093787]
+,[1061.1728716054904,4897.38544093787]
+,[1160.4728716054904,4731.785440937871]
+,[1259.7728716054903,4566.185440937871]
+,[1359.0728716054903,4400.585440937872]
+,[1458.3728716054902,4566.185440937871]
+,[1557.6728716054902,4566.185440937871]
+,[1656.9728716054901,4731.785440937871]
+,[1557.6728716054902,4897.38544093787]
+,[1458.3728716054902,5062.9854409378695]
+,[1557.6728716054902,5228.585440937869]
+,[1656.9728716054901,5062.9854409378695]
+,[1756.27287160549,5062.9854409378695]
+,[1756.27287160549,4897.38544093787]
+,[1855.57287160549,5062.9854409378695]
+,[1954.87287160549,4897.38544093787]
+,[2054.17287160549,5062.9854409378695]
+,[1954.87287160549,5062.9854409378695]
+,[2054.17287160549,5228.585440937869]
+,[2153.4728716054897,5228.585440937869]
+,[2252.7728716054894,5062.9854409378695]
+,[2352.072871605489,5228.585440937869]
+,[2451.372871605489,5394.185440937868]
+,[2352.072871605489,5394.185440937868]
+,[2252.7728716054894,5228.585440937869]
+,[2153.4728716054897,5062.9854409378695]
+,[2153.4728716054897,4897.38544093787]
+,[2252.7728716054894,4897.38544093787]
+,[2352.072871605489,4731.785440937871]
+,[2252.7728716054894,4731.785440937871]
+,[2153.4728716054897,4731.785440937871]
+,[2054.17287160549,4566.185440937871]
+,[1954.87287160549,4731.785440937871]
+,[1855.57287160549,4897.38544093787]
+,[1756.27287160549,4731.785440937871]
+,[1855.57287160549,4731.785440937871]
+,[1855.57287160549,4566.185440937871]
+,[1756.27287160549,4566.185440937871]
+,[1656.9728716054901,4566.185440937871]
+,[1557.6728716054902,4731.785440937871]
+,[1656.9728716054901,4897.38544093787]
+,[1557.6728716054902,5062.9854409378695]
+,[1458.3728716054902,5228.585440937869]
+,[1359.0728716054903,5228.585440937869]
+,[1259.7728716054903,5394.185440937868]
+,[1259.7728716054903,5559.785440937868]
+,[1160.4728716054904,5559.785440937868]
+,[1061.1728716054904,5559.785440937868]
+,[1160.4728716054904,5725.385440937867]
+,[1259.7728716054903,5725.385440937867]
+,[1359.0728716054903,5559.785440937868]
+,[1458.3728716054902,5725.385440937867]
+,[1458.3728716054902,5559.785440937868]
+,[1359.0728716054903,5725.385440937867]
+,[1259.7728716054903,5890.985440937867]
+,[1359.0728716054903,5890.985440937867]
+,[1259.7728716054903,6056.585440937866]
+,[1359.0728716054903,6222.185440937866]
+,[1458.3728716054902,6222.185440937866]
+,[1458.3728716054902,6387.785440937865]
+,[1557.6728716054902,6222.185440937866]
+,[1557.6728716054902,6387.785440937865]
+,[1656.9728716054901,6222.185440937866]
+,[1756.27287160549,6056.585440937866]
+,[1855.57287160549,5890.985440937867]
+,[1756.27287160549,5890.985440937867]
+,[1656.9728716054901,6056.585440937866]
+,[1557.6728716054902,5890.985440937867]
+,[1458.3728716054902,5890.985440937867]
+,[1359.0728716054903,6056.585440937866]
+,[1259.7728716054903,6222.185440937866]
+,[1160.4728716054904,6056.585440937866]
+,[1061.1728716054904,5890.985440937867]
+,[1061.1728716054904,6056.585440937866]
+,[1160.4728716054904,6222.185440937866]
+,[1061.1728716054904,6222.185440937866]
+,[961.8728716054903,6222.185440937866]
+,[961.8728716054903,6056.585440937866]
+,[961.8728716054903,5890.985440937867]
+,[961.8728716054903,5725.385440937867]
+,[862.5728716054903,5559.785440937868]
+,[763.2728716054902,5725.385440937867]
+,[862.5728716054903,5725.385440937867]
+,[763.2728716054902,5890.985440937867]
+,[663.9728716054901,5725.385440937867]
+,[763.2728716054902,5559.785440937868]
+,[763.2728716054902,5394.185440937868]
+,[862.5728716054903,5228.585440937869]
+,[961.8728716054903,5394.185440937868]
+,[1061.1728716054904,5394.185440937868]
+,[961.8728716054903,5559.785440937868]
+,[862.5728716054903,5394.185440937868]
+,[763.2728716054902,5228.585440937869]
+,[663.9728716054901,5062.9854409378695]
+,[763.2728716054902,5062.9854409378695]
+,[763.2728716054902,4897.38544093787]
+,[663.9728716054901,4731.785440937871]
+,[564.6728716054901,4731.785440937871]
+,[465.37287160549005,4566.185440937871]
+,[366.0728716054901,4566.185440937871]
+,[465.37287160549005,4731.785440937871]
+,[564.6728716054901,4566.185440937871]
+,[465.37287160549005,4400.585440937872]
+,[366.0728716054901,4400.585440937872]
+,[266.77287160549014,4234.985440937872]
+,[167.47287160549016,4234.985440937872]
+,[266.77287160549014,4400.585440937872]
+,[266.77287160549014,4566.185440937871]
+,[167.47287160549016,4400.585440937872]
+,[68.17287160549016,4234.985440937872]
+,[167.47287160549013,4069.3854409378723]
+,[68.17287160549013,3903.7854409378724]
+,[68.17287160549013,4069.3854409378723]
+,[167.47287160549013,3903.7854409378724]
+,[266.77287160549014,3903.7854409378724]
+,[366.0728716054901,3738.1854409378725]
+,[266.77287160549014,3738.1854409378725]
+,[266.77287160549014,3572.5854409378726]
+,[167.47287160549016,3406.9854409378727]
+,[167.47287160549016,3241.3854409378728]
+,[266.77287160549014,3241.3854409378728]
+,[266.77287160549014,3406.9854409378727]
+,[366.0728716054901,3572.5854409378726]
+,[465.37287160549005,3738.1854409378725]
+,[465.37287160549005,3903.7854409378724]
+,[366.0728716054901,4069.3854409378723]
+,[366.0728716054901,4234.985440937872]
+,[465.37287160549005,4234.985440937872]
+,[564.6728716054901,4069.3854409378723]
+,[465.37287160549005,4069.3854409378723]
+,[564.6728716054901,4234.985440937872]
+,[663.9728716054901,4069.3854409378723]
+,[663.9728716054901,4234.985440937872]
+,[663.9728716054901,4400.585440937872]
+,[763.2728716054902,4566.185440937871]
+,[763.2728716054902,4400.585440937872]
+,[663.9728716054901,4566.185440937871]
+,[564.6728716054901,4400.585440937872]
+,[19431.915041401327,3495.506142643713]
+,[19332.61504140133,3661.1061426437127]
+,[19431.915041401327,3661.1061426437127]
+,[19531.215041401327,3661.1061426437127]
+,[19630.515041401326,3495.506142643713]
+,[19630.515041401326,3661.1061426437127]
+,[19729.815041401325,3826.7061426437126]
+,[19630.515041401326,3826.7061426437126]
+,[19729.815041401325,3992.3061426437125]
+,[19630.515041401326,3992.3061426437125]
+,[19630.515041401326,4157.906142643712]
+,[19630.515041401326,4323.506142643711]
+,[19531.215041401327,4157.906142643712]
+,[19431.915041401327,4323.506142643711]
+,[19531.215041401327,4489.106142643711]
+,[19431.915041401327,4654.70614264371]
+,[19332.61504140133,4654.70614264371]
+,[19332.61504140133,4820.30614264371]
+,[19332.61504140133,4985.906142643709]
+,[19233.31504140133,4985.906142643709]
+,[19134.01504140133,5151.506142643709]
+,[19034.71504140133,5151.506142643709]
+,[19134.01504140133,5317.106142643708]
+,[19034.71504140133,5317.106142643708]
+,[19034.71504140133,5482.706142643708]
+,[18935.41504140133,5648.306142643707]
+,[18836.115041401332,5813.9061426437065]
+,[18836.115041401332,5979.506142643706]
+,[18935.41504140133,5979.506142643706]
+,[19034.71504140133,6145.106142643705]
+,[19034.71504140133,5979.506142643706]
+,[19034.71504140133,5813.9061426437065]
+,[19134.01504140133,5648.306142643707]
+,[19233.31504140133,5648.306142643707]
+,[19134.01504140133,5813.9061426437065]
+,[19134.01504140133,5979.506142643706]
+,[19233.31504140133,5813.9061426437065]
+,[19233.31504140133,5979.506142643706]
+,[19332.61504140133,6145.106142643705]
+,[19332.61504140133,6310.706142643705]
+,[19233.31504140133,6310.706142643705]
+,[19233.31504140133,6476.306142643704]
+,[19332.61504140133,6476.306142643704]
+,[19431.915041401327,6641.906142643704]
+,[19332.61504140133,6807.506142643703]
+,[19332.61504140133,6641.906142643704]
+,[19431.915041401327,6476.306142643704]
+,[19431.915041401327,6310.706142643705]
+,[19531.215041401327,6145.106142643705]
+,[19431.915041401327,5979.506142643706]
+,[19431.915041401327,6145.106142643705]
+,[19531.215041401327,5979.506142643706]
+,[19630.515041401326,5813.9061426437065]
+,[19630.515041401326,5979.506142643706]
+,[19729.815041401325,5813.9061426437065]
+,[19829.115041401325,5979.506142643706]
+,[19729.815041401325,5979.506142643706]
+,[19729.815041401325,6145.106142643705]
+,[19729.815041401325,6310.706142643705]
+,[19630.515041401326,6476.306142643704]
+,[19729.815041401325,6476.306142643704]
+,[19630.515041401326,6310.706142643705]
+,[19531.215041401327,6310.706142643705]
+,[19531.215041401327,6476.306142643704]
+,[19630.515041401326,6641.906142643704]
+,[19729.815041401325,6807.506142643703]
+,[19829.115041401325,6973.106142643703]
+,[19928.415041401324,6973.106142643703]
+,[19928.415041401324,7138.706142643702]
+,[20027.715041401323,7138.706142643702]
+,[20027.715041401323,7304.306142643702]
+,[19928.415041401324,7304.306142643702]
+,[19829.115041401325,7304.306142643702]
+,[19829.115041401325,7469.906142643701]
+,[19928.415041401324,7469.906142643701]
+,[19928.415041401324,7635.5061426437005]
+,[19928.415041401324,7801.1061426437]
+,[20027.715041401323,7635.5061426437005]
+,[20027.715041401323,7801.1061426437]
+,[20127.015041401322,7801.1061426437]
+,[20226.31504140132,7801.1061426437]
+,[20325.61504140132,7801.1061426437]
+,[20226.31504140132,7635.5061426437005]
+,[20226.31504140132,7469.906142643701]
+,[20226.31504140132,7304.306142643702]
+,[20127.015041401322,7304.306142643702]
+,[20027.715041401323,7469.906142643701]
+,[20127.015041401322,7469.906142643701]
+,[20127.015041401322,7635.5061426437005]
+,[2748.790306732237,2362.9553147492866]
+,[2848.0903067322365,2528.5553147492865]
+,[2748.790306732237,2694.1553147492864]
+,[2649.490306732237,2859.7553147492863]
+,[2748.790306732237,3025.355314749286]
+,[2848.0903067322365,2859.7553147492863]
+,[2848.0903067322365,2694.1553147492864]
+,[2947.3903067322362,2694.1553147492864]
+,[3046.690306732236,2859.7553147492863]
+,[3145.9903067322357,2694.1553147492864]
+,[3145.9903067322357,2528.5553147492865]
+,[3046.690306732236,2694.1553147492864]
+,[3145.9903067322357,2859.7553147492863]
+,[3046.690306732236,3025.355314749286]
+,[3145.9903067322357,3025.355314749286]
+,[3245.2903067322354,3190.955314749286]
+,[3245.2903067322354,3356.555314749286]
+,[3344.590306732235,3522.155314749286]
+,[3443.890306732235,3356.555314749286]
+,[3543.1903067322346,3356.555314749286]
+,[3642.4903067322343,3190.955314749286]
+,[3741.790306732234,3025.355314749286]
+,[3741.790306732234,2859.7553147492863]
+,[3841.090306732234,3025.355314749286]
+,[3841.090306732234,3190.955314749286]
+,[3741.790306732234,3190.955314749286]
+,[3642.4903067322343,3025.355314749286]
+,[3543.1903067322346,3025.355314749286]
+,[3543.1903067322346,2859.7553147492863]
+,[3443.890306732235,3025.355314749286]
+,[3443.890306732235,3190.955314749286]
+,[3543.1903067322346,3190.955314749286]
+,[3642.4903067322343,3356.555314749286]
+,[3543.1903067322346,3522.155314749286]
+,[3443.890306732235,3687.755314749286]
+,[3443.890306732235,3853.3553147492858]
+,[3344.590306732235,3687.755314749286]
+,[3245.2903067322354,3853.3553147492858]
+,[3245.2903067322354,3687.755314749286]
+,[3145.9903067322357,3687.755314749286]
+,[3046.690306732236,3853.3553147492858]
+,[3145.9903067322357,4018.9553147492857]
+,[3145.9903067322357,3853.3553147492858]
+,[3046.690306732236,3687.755314749286]
+,[3145.9903067322357,3522.155314749286]
+,[3145.9903067322357,3356.555314749286]
+,[3145.9903067322357,3190.955314749286]
+,[3046.690306732236,3190.955314749286]
+,[3046.690306732236,3356.555314749286]
+,[2947.3903067322362,3356.555314749286]
+,[2848.0903067322365,3190.955314749286]
+,[2947.3903067322362,3025.355314749286]
+,[2848.0903067322365,3025.355314749286]
+,[2748.790306732237,2859.7553147492863]
+,[2649.490306732237,2694.1553147492864]
+,[2748.790306732237,2528.5553147492865]
+,[2848.0903067322365,2362.9553147492866]
+,[2748.790306732237,2197.3553147492867]
+,[2649.490306732237,2362.9553147492866]
+,[2649.490306732237,2197.3553147492867]
+,[2550.1903067322373,2362.9553147492866]
+,[2450.8903067322376,2362.9553147492866]
+,[2351.590306732238,2528.5553147492865]
+,[2252.290306732238,2528.5553147492865]
+,[2351.590306732238,2362.9553147492866]
+,[2252.290306732238,2197.3553147492867]
+,[2351.590306732238,2197.3553147492867]
+,[2351.590306732238,2031.7553147492865]
+,[2351.590306732238,1866.1553147492864]
+,[2252.290306732238,1866.1553147492864]
+,[2351.590306732238,1700.5553147492863]
+,[2450.8903067322376,1534.9553147492861]
+,[2351.590306732238,1369.355314749286]
+,[2252.290306732238,1203.7553147492858]
+,[2252.290306732238,1369.355314749286]
+,[2252.290306732238,1534.9553147492861]
+,[2152.9903067322384,1369.355314749286]
+,[2053.6903067322387,1369.355314749286]
+,[1954.3903067322387,1203.7553147492858]
+,[1855.0903067322388,1203.7553147492858]
+,[1755.7903067322388,1038.1553147492857]
+,[1656.4903067322389,1038.1553147492857]
+,[1557.190306732239,872.5553147492857]
+,[1457.890306732239,1038.1553147492857]
+,[1457.890306732239,872.5553147492857]
+,[1457.890306732239,706.9553147492858]
+,[1557.190306732239,706.9553147492858]
+,[1656.4903067322389,872.5553147492857]
+,[1656.4903067322389,706.9553147492858]
+,[1755.7903067322388,706.9553147492858]
+,[1656.4903067322389,541.3553147492859]
+,[1557.190306732239,375.7553147492859]
+,[1656.4903067322389,210.1553147492859]
+,[1755.7903067322388,44.55531474928592]
+,[1656.4903067322389,44.55531474928592]
+,[1557.190306732239,210.1553147492859]
+,[1457.890306732239,210.1553147492859]
+,[1457.890306732239,44.55531474928592]
+,[1358.590306732239,210.1553147492859]
+,[1358.590306732239,375.75531474928584]
+,[1259.290306732239,210.15531474928585]
+,[1259.290306732239,375.75531474928584]
+,[1259.290306732239,541.3553147492859]
+,[1358.590306732239,706.9553147492858]
+,[1358.590306732239,872.5553147492857]
+,[1259.290306732239,706.9553147492858]
+,[1259.290306732239,872.5553147492857]
+,[1259.290306732239,1038.1553147492857]
+,[1358.590306732239,1203.7553147492858]
+,[1358.590306732239,1038.1553147492857]
+,[1457.890306732239,1203.7553147492858]
+,[1557.190306732239,1369.355314749286]
+,[1656.4903067322389,1203.7553147492858]
+,[1557.190306732239,1203.7553147492858]
+,[1557.190306732239,1038.1553147492857]
+,[17254.572515546668,1460.5807801244923]
+,[17353.872515546667,1626.1807801244925]
+,[17453.172515546667,1791.7807801244926]
+,[17552.472515546666,1791.7807801244926]
+,[17453.172515546667,1626.1807801244925]
+,[17353.872515546667,1791.7807801244926]
+,[17453.172515546667,1957.3807801244927]
+,[17353.872515546667,2122.980780124493]
+,[17453.172515546667,2288.580780124493]
+,[17353.872515546667,2454.1807801244927]
+,[17453.172515546667,2619.7807801244926]
+,[17552.472515546666,2619.7807801244926]
+,[17453.172515546667,2785.3807801244925]
+,[17353.872515546667,2619.7807801244926]
+,[17254.572515546668,2454.1807801244927]
+,[17254.572515546668,2288.580780124493]
+,[17353.872515546667,2288.580780124493]
+,[17453.172515546667,2122.980780124493]
+,[17552.472515546666,2288.580780124493]
+,[17552.472515546666,2454.1807801244927]
+,[17453.172515546667,2454.1807801244927]
+,[4447.67624466283,4761.1416826913]
+,[4546.97624466283,4595.541682691301]
+,[4546.97624466283,4429.941682691301]
+,[4447.67624466283,4429.941682691301]
+,[4447.67624466283,4595.541682691301]
+,[4348.37624466283,4595.541682691301]
+,[4249.07624466283,4595.541682691301]
+,[4348.37624466283,4761.1416826913]
+,[4249.07624466283,4761.1416826913]
+,[4348.37624466283,4926.7416826912995]
+,[4348.37624466283,5092.341682691299]
+,[4447.67624466283,5257.941682691298]
+,[4546.97624466283,5257.941682691298]
+,[4646.27624466283,5092.341682691299]
+,[4546.97624466283,5092.341682691299]
+,[4646.27624466283,4926.7416826912995]
+,[4646.27624466283,4761.1416826913]
+,[4546.97624466283,4761.1416826913]
+,[4646.27624466283,4595.541682691301]
+,[4745.5762446628305,4595.541682691301]
+,[4646.27624466283,4429.941682691301]
+,[4745.5762446628305,4429.941682691301]
+,[4844.876244662831,4595.541682691301]
+,[4745.5762446628305,4761.1416826913]
+,[4745.5762446628305,4926.7416826912995]
+,[4844.876244662831,4761.1416826913]
+,[4944.176244662831,4761.1416826913]
+,[5043.476244662831,4926.7416826912995]
+,[5043.476244662831,4761.1416826913]
+,[5142.776244662831,4926.7416826912995]
+,[5142.776244662831,4761.1416826913]
+,[5242.076244662831,4595.541682691301]
+,[5142.776244662831,4595.541682691301]
+,[5242.076244662831,4429.941682691301]
+,[5242.076244662831,4264.341682691302]
+,[5142.776244662831,4429.941682691301]
+,[5043.476244662831,4595.541682691301]
+,[5043.476244662831,4429.941682691301]
+,[5043.476244662831,4264.341682691302]
+,[5142.776244662831,4098.741682691302]
+,[5043.476244662831,4098.741682691302]
+,[4944.176244662831,3933.1416826913023]
+,[4944.176244662831,4098.741682691302]
+,[4944.176244662831,4264.341682691302]
+,[4844.876244662831,4098.741682691302]
+,[4745.5762446628305,4264.341682691302]
+,[4646.27624466283,4098.741682691302]
+,[4546.97624466283,3933.1416826913023]
+,[4447.67624466283,4098.741682691302]
+,[4546.97624466283,4264.341682691302]
+,[4447.67624466283,4264.341682691302]
+,[4546.97624466283,4098.741682691302]
+,[4646.27624466283,3933.1416826913023]
+,[4546.97624466283,3767.5416826913024]
+,[4447.67624466283,3601.9416826913025]
+,[4447.67624466283,3767.5416826913024]
+,[4348.37624466283,3767.5416826913024]
+,[4348.37624466283,3933.1416826913023]
+,[4249.07624466283,3767.5416826913024]
+,[4249.07624466283,3933.1416826913023]
+,[4149.776244662829,3933.1416826913023]
+,[4050.4762446628297,4098.741682691302]
+,[4050.4762446628297,3933.1416826913023]
+,[3951.17624466283,3933.1416826913023]
+,[3951.17624466283,4098.741682691302]
+,[3851.8762446628302,4264.341682691302]
+,[3851.8762446628302,4098.741682691302]
+,[3752.5762446628305,4098.741682691302]
+,[3653.276244662831,4264.341682691302]
+,[3553.976244662831,4429.941682691301]
+,[3553.976244662831,4595.541682691301]
+,[3454.6762446628313,4429.941682691301]
+,[3553.976244662831,4264.341682691302]
+,[3653.276244662831,4429.941682691301]
+,[3752.5762446628305,4264.341682691302]
+,[3752.5762446628305,4429.941682691301]
+,[3851.8762446628302,4595.541682691301]
+,[3851.8762446628302,4429.941682691301]
+,[3951.17624466283,4429.941682691301]
+,[4050.4762446628297,4264.341682691302]
+,[4149.776244662829,4098.741682691302]
+,[4249.07624466283,4264.341682691302]
+,[4348.37624466283,4098.741682691302]
+,[4447.67624466283,3933.1416826913023]
+,[9574.088902135607,7352.26293905581]
+,[9474.788902135606,7352.26293905581]
+,[9375.488902135605,7186.662939055811]
+,[9474.788902135606,7021.0629390558115]
+,[9574.088902135607,7021.0629390558115]
+,[9474.788902135606,7186.662939055811]
+,[9574.088902135607,7186.662939055811]
+,[9673.388902135608,7021.0629390558115]
+,[9673.388902135608,6855.462939055812]
+,[9772.68890213561,6689.862939055813]
+,[9673.388902135608,6689.862939055813]
+,[9772.68890213561,6524.262939055813]
+,[9871.98890213561,6358.662939055814]
+,[9971.288902135611,6524.262939055813]
+,[10070.588902135612,6358.662939055814]
+,[10070.588902135612,6193.062939055814]
+,[9971.288902135611,6027.462939055815]
+,[9971.288902135611,5861.862939055815]
+,[9871.98890213561,5861.862939055815]
+,[9871.98890213561,5696.262939055816]
+,[9971.288902135611,5530.662939055816]
+,[10070.588902135612,5530.662939055816]
+,[10070.588902135612,5696.262939055816]
+,[10169.888902135614,5861.862939055815]
+,[10169.888902135614,5696.262939055816]
+,[10070.588902135612,5861.862939055815]
+,[10169.888902135614,6027.462939055815]
+,[10169.888902135614,6193.062939055814]
+,[10269.188902135615,6027.462939055815]
+,[10269.188902135615,5861.862939055815]
+,[10368.488902135616,6027.462939055815]
+,[10269.188902135615,6193.062939055814]
+,[10269.188902135615,6358.662939055814]
+,[10169.888902135614,6358.662939055814]
+,[10070.588902135612,6524.262939055813]
+,[10070.588902135612,6689.862939055813]
+,[9971.288902135611,6855.462939055812]
+,[9971.288902135611,7021.0629390558115]
+,[10070.588902135612,7186.662939055811]
+,[10169.888902135614,7186.662939055811]
+,[10269.188902135615,7186.662939055811]
+,[10169.888902135614,7352.26293905581]
+,[10070.588902135612,7352.26293905581]
+,[10169.888902135614,7517.86293905581]
+,[10169.888902135614,7683.462939055809]
+,[10269.188902135615,7517.86293905581]
+,[10368.488902135616,7683.462939055809]
+,[10467.788902135617,7683.462939055809]
+,[10368.488902135616,7517.86293905581]
+,[10269.188902135615,7352.26293905581]
+,[10368.488902135616,7352.26293905581]
+,[10368.488902135616,7186.662939055811]
+,[10368.488902135616,7021.0629390558115]
+,[10368.488902135616,6855.462939055812]
+,[10269.188902135615,6855.462939055812]
+,[10169.888902135614,6855.462939055812]
+,[10169.888902135614,7021.0629390558115]
+,[10070.588902135612,7021.0629390558115]
+,[10070.588902135612,6855.462939055812]
+,[10169.888902135614,6689.862939055813]
+,[10269.188902135615,6689.862939055813]
+,[10169.888902135614,6524.262939055813]
+,[10269.188902135615,6524.262939055813]
+,[10368.488902135616,6524.262939055813]
+,[10368.488902135616,6358.662939055814]
+,[10467.788902135617,6358.662939055814]
+,[10467.788902135617,6193.062939055814]
+,[10567.088902135618,6358.662939055814]
+,[10567.088902135618,6193.062939055814]
+,[10666.388902135619,6193.062939055814]
+,[10666.388902135619,6358.662939055814]
+,[10567.088902135618,6524.262939055813]
+,[10467.788902135617,6524.262939055813]
+,[10567.088902135618,6689.862939055813]
+,[10467.788902135617,6855.462939055812]
+,[10567.088902135618,7021.0629390558115]
+,[10467.788902135617,7021.0629390558115]
+,[10567.088902135618,6855.462939055812]
+,[10467.788902135617,6689.862939055813]
+,[10368.488902135616,6689.862939055813]
+,[1073.6944354374714,1154.3681204032646]
+,[974.3944354374713,1319.9681204032647]
+,[875.0944354374712,1319.9681204032647]
+,[775.7944354374712,1154.3681204032646]
+,[775.7944354374712,988.7681204032646]
+,[875.0944354374712,823.1681204032647]
+,[875.0944354374712,657.5681204032647]
+,[775.7944354374712,823.1681204032647]
+,[676.4944354374711,657.5681204032647]
+,[676.4944354374711,491.9681204032648]
+,[775.7944354374712,657.5681204032647]
+,[676.4944354374711,823.1681204032647]
+,[676.4944354374711,988.7681204032646]
+,[577.194435437471,823.1681204032647]
+,[577.194435437471,988.7681204032646]
+,[577.194435437471,1154.3681204032646]
+,[676.4944354374711,1319.9681204032647]
+,[577.194435437471,1319.9681204032647]
+,[477.89443543747103,1319.9681204032647]
+,[577.194435437471,1485.5681204032649]
+,[477.89443543747103,1651.168120403265]
+,[577.194435437471,1816.7681204032651]
+,[477.89443543747103,1816.7681204032651]
+,[378.5944354374711,1982.3681204032653]
+,[378.5944354374711,2147.9681204032654]
+,[279.2944354374711,2313.5681204032653]
+,[179.99443543747114,2147.9681204032654]
+,[80.69443543747114,2313.5681204032653]
+,[80.69443543747114,2479.168120403265]
+,[179.9944354374711,2644.768120403265]
+,[179.9944354374711,2479.168120403265]
+,[179.9944354374711,2313.5681204032653]
+,[80.69443543747111,2147.9681204032654]
+,[80.69443543747111,1982.3681204032653]
+,[179.9944354374711,1982.3681204032653]
+,[179.9944354374711,1816.7681204032651]
+,[80.69443543747111,1816.7681204032651]
+,[179.9944354374711,1651.168120403265]
+,[80.69443543747111,1485.5681204032649]
+,[80.69443543747111,1319.9681204032647]
+,[179.9944354374711,1154.3681204032646]
+,[80.69443543747111,1154.3681204032646]
+,[179.9944354374711,988.7681204032646]
+,[279.2944354374711,823.1681204032647]
+,[378.5944354374711,657.5681204032647]
+,[378.5944354374711,823.1681204032647]
+,[477.89443543747103,823.1681204032647]
+,[477.89443543747103,657.5681204032647]
+,[378.5944354374711,491.9681204032648]
+,[477.89443543747103,326.3681204032648]
+,[477.89443543747103,160.76812040326482]
+,[378.5944354374711,160.76812040326482]
+,[279.2944354374711,326.3681204032648]
+,[179.99443543747114,491.9681204032648]
+,[179.99443543747114,326.3681204032648]
+,[279.2944354374711,491.9681204032648]
+,[279.2944354374711,657.5681204032647]
+,[179.99443543747114,823.1681204032647]
+,[279.2944354374711,988.7681204032646]
+,[279.2944354374711,1154.3681204032646]
+,[378.5944354374711,1319.9681204032647]
+,[477.89443543747103,1485.5681204032649]
+,[577.194435437471,1651.168120403265]
+,[676.4944354374711,1651.168120403265]
+,[775.7944354374712,1816.7681204032651]
+,[676.4944354374711,1816.7681204032651]
+,[775.7944354374712,1651.168120403265]
+,[875.0944354374712,1651.168120403265]
+,[974.3944354374713,1651.168120403265]
+,[875.0944354374712,1485.5681204032649]
+,[775.7944354374712,1485.5681204032649]
+,[676.4944354374711,1485.5681204032649]
+,[775.7944354374712,1319.9681204032647]
+,[676.4944354374711,1154.3681204032646]
+,[3138.413562431697,2355.845602060523]
+,[3039.113562431697,2521.445602060523]
+,[3039.113562431697,2355.845602060523]
+,[3039.113562431697,2190.245602060523]
+,[3138.413562431697,2024.645602060523]
+,[3237.7135624316966,1859.045602060523]
+,[3237.7135624316966,2024.645602060523]
+,[3337.0135624316963,1859.045602060523]
+,[3337.0135624316963,1693.4456020605228]
+,[3436.313562431696,1527.8456020605227]
+,[3535.6135624316958,1693.4456020605228]
+,[3535.6135624316958,1859.045602060523]
+,[3634.9135624316955,2024.645602060523]
+,[3734.213562431695,2190.245602060523]
+,[3634.9135624316955,2190.245602060523]
+,[3535.6135624316958,2190.245602060523]
+,[3535.6135624316958,2355.845602060523]
+,[3535.6135624316958,2521.445602060523]
+,[3436.313562431696,2687.045602060523]
+,[3436.313562431696,2852.645602060523]
+,[3535.6135624316958,2687.045602060523]
+,[3634.9135624316955,2521.445602060523]
+,[3634.9135624316955,2355.845602060523]
+,[3734.213562431695,2355.845602060523]
+,[3833.513562431695,2190.245602060523]
+,[3932.8135624316947,2024.645602060523]
+,[3833.513562431695,1859.045602060523]
+,[3833.513562431695,1693.4456020605228]
+,[3734.213562431695,1859.045602060523]
+,[3734.213562431695,1693.4456020605228]
+,[3734.213562431695,1527.8456020605227]
+,[3634.9135624316955,1527.8456020605227]
+,[3634.9135624316955,1693.4456020605228]
+,[3535.6135624316958,1527.8456020605227]
+,[3634.9135624316955,1362.2456020605225]
+,[3535.6135624316958,1362.2456020605225]
+,[3436.313562431696,1196.6456020605224]
+,[3535.6135624316958,1196.6456020605224]
+,[3535.6135624316958,1031.0456020605222]
+,[3436.313562431696,1031.0456020605222]
+,[3535.6135624316958,865.4456020605222]
+,[3436.313562431696,865.4456020605222]
+,[3535.6135624316958,699.8456020605223]
+,[3634.9135624316955,699.8456020605223]
+,[3535.6135624316958,534.2456020605224]
+,[3436.313562431696,368.64560206052244]
+,[3436.313562431696,203.04560206052244]
+,[3337.0135624316963,37.445602060522454]
+,[3436.313562431696,37.445602060522454]
+,[3337.0135624316963,203.04560206052244]
+,[3237.7135624316966,37.445602060522454]
+,[3138.413562431697,37.445602060522454]
+,[3237.7135624316966,203.04560206052244]
+,[3337.0135624316963,368.6456020605224]
+,[3436.313562431696,534.2456020605224]
+,[3337.0135624316963,699.8456020605223]
+,[3237.7135624316966,534.2456020605224]
+,[3337.0135624316963,534.2456020605224]
+,[3436.313562431696,699.8456020605223]
+,[3337.0135624316963,865.4456020605222]
+,[3237.7135624316966,865.4456020605222]
+,[3337.0135624316963,1031.0456020605222]
+,[3237.7135624316966,1196.6456020605224]
+,[3138.413562431697,1362.2456020605225]
+,[3039.113562431697,1527.8456020605227]
+,[3138.413562431697,1527.8456020605227]
+,[3039.113562431697,1693.4456020605228]
+,[2939.8135624316974,1527.8456020605227]
+,[2840.5135624316977,1362.2456020605225]
+,[2840.5135624316977,1527.8456020605227]
+,[2840.5135624316977,1693.4456020605228]
+,[2939.8135624316974,1859.045602060523]
+,[2840.5135624316977,2024.645602060523]
+,[2840.5135624316977,1859.045602060523]
+,[2939.8135624316974,1693.4456020605228]
+,[3039.113562431697,1859.045602060523]
+,[3039.113562431697,2024.645602060523]
+,[2939.8135624316974,2190.245602060523]
+,[2939.8135624316974,2024.645602060523]
+,[16388.412117675925,1839.818884803299]
+,[16289.112117675924,1839.818884803299]
+,[16388.412117675925,1674.2188848032988]
+,[16487.712117675925,1508.6188848032987]
+,[16487.712117675925,1674.2188848032988]
+,[16388.412117675925,1508.6188848032987]
+,[16289.112117675924,1343.0188848032985]
+,[16289.112117675924,1508.6188848032987]
+,[16189.812117675923,1674.2188848032988]
+,[16090.512117675922,1839.818884803299]
+,[16090.512117675922,2005.418884803299]
+,[15991.212117675921,2171.018884803299]
+,[16090.512117675922,2336.618884803299]
+,[16090.512117675922,2502.218884803299]
+,[16090.512117675922,2667.8188848032987]
+,[15991.212117675921,2833.4188848032986]
+,[15991.212117675921,2999.0188848032985]
+,[15891.91211767592,3164.6188848032984]
+,[15891.91211767592,3330.2188848032984]
+,[15991.212117675921,3330.2188848032984]
+,[16090.512117675922,3330.2188848032984]
+,[16189.812117675923,3495.8188848032983]
+,[16289.112117675924,3495.8188848032983]
+,[16189.812117675923,3330.2188848032984]
+,[16189.812117675923,3164.6188848032984]
+,[16289.112117675924,3164.6188848032984]
+,[16388.412117675925,3164.6188848032984]
+,[16388.412117675925,3330.2188848032984]
+,[16487.712117675925,3330.2188848032984]
+,[16587.012117675924,3495.8188848032983]
+,[16587.012117675924,3661.418884803298]
+,[16686.312117675923,3661.418884803298]
+,[16785.612117675922,3661.418884803298]
+,[16884.91211767592,3661.418884803298]
+,[16984.21211767592,3661.418884803298]
+,[16884.91211767592,3827.018884803298]
+,[16884.91211767592,3992.618884803298]
+,[16984.21211767592,3827.018884803298]
+,[17083.51211767592,3661.418884803298]
+,[17182.81211767592,3495.8188848032983]
+,[17182.81211767592,3330.2188848032984]
+,[17282.11211767592,3164.6188848032984]
+,[17282.11211767592,3330.2188848032984]
+,[17182.81211767592,3164.6188848032984]
+,[17083.51211767592,3164.6188848032984]
+,[16984.21211767592,3330.2188848032984]
+,[16984.21211767592,3495.8188848032983]
+,[17083.51211767592,3330.2188848032984]
+,[16984.21211767592,3164.6188848032984]
+,[16984.21211767592,2999.0188848032985]
+,[17083.51211767592,2833.4188848032986]
+,[17083.51211767592,2667.8188848032987]
+,[17182.81211767592,2667.8188848032987]
+,[17182.81211767592,2833.4188848032986]
+,[17083.51211767592,2999.0188848032985]
+,[16984.21211767592,2833.4188848032986]
+,[16884.91211767592,2833.4188848032986]
+,[16884.91211767592,2999.0188848032985]
+,[16785.612117675922,2999.0188848032985]
+,[16884.91211767592,3164.6188848032984]
+,[16785.612117675922,3164.6188848032984]
+,[16686.312117675923,3164.6188848032984]
+,[16587.012117675924,3164.6188848032984]
+,[16587.012117675924,2999.0188848032985]
+,[16487.712117675925,3164.6188848032984]
+,[16587.012117675924,3330.2188848032984]
+,[16686.312117675923,3495.8188848032983]
+,[16686.312117675923,3330.2188848032984]
+,[16785.612117675922,3330.2188848032984]
+,[16884.91211767592,3495.8188848032983]
+,[16785.612117675922,3495.8188848032983]
+,[16884.91211767592,3330.2188848032984]
+,[1272.175991128079,3842.7700224365044]
+,[1371.475991128079,3842.7700224365044]
+,[1272.175991128079,3677.1700224365045]
+,[1172.875991128079,3511.5700224365046]
+,[1272.175991128079,3511.5700224365046]
+,[1172.875991128079,3345.9700224365047]
+,[1073.575991128079,3180.3700224365048]
+,[1073.575991128079,3014.770022436505]
+,[974.275991128079,3014.770022436505]
+,[874.9759911280789,3014.770022436505]
+,[775.6759911280789,2849.170022436505]
+,[775.6759911280789,3014.770022436505]
+,[775.6759911280789,3180.3700224365048]
+,[676.3759911280788,3345.9700224365047]
+,[676.3759911280788,3511.5700224365046]
+,[775.6759911280789,3677.1700224365045]
+,[676.3759911280788,3842.7700224365044]
+,[577.0759911280787,3842.7700224365044]
+,[577.0759911280787,3677.1700224365045]
+,[676.3759911280788,3677.1700224365045]
+,[775.6759911280789,3511.5700224365046]
+,[775.6759911280789,3345.9700224365047]
+,[874.9759911280789,3345.9700224365047]
+,[874.9759911280789,3180.3700224365048]
+,[974.275991128079,3180.3700224365048]
+,[974.275991128079,3345.9700224365047]
+,[1073.575991128079,3511.5700224365046]
+,[1073.575991128079,3677.1700224365045]
+,[1172.875991128079,3677.1700224365045]
+,[1172.875991128079,3842.7700224365044]
+,[1073.575991128079,3842.7700224365044]
+,[1172.875991128079,4008.3700224365043]
+,[1073.575991128079,4008.3700224365043]
+,[974.275991128079,3842.7700224365044]
+,[974.275991128079,4008.3700224365043]
+,[874.9759911280789,4008.3700224365043]
+,[775.6759911280789,4008.3700224365043]
+,[874.9759911280789,3842.7700224365044]
+,[974.275991128079,3677.1700224365045]
+,[974.275991128079,3511.5700224365046]
+,[1073.575991128079,3345.9700224365047]
+,[1172.875991128079,3180.3700224365048]
+,[1272.175991128079,3180.3700224365048]
+,[1272.175991128079,3345.9700224365047]
+,[1371.475991128079,3180.3700224365048]
+,[1470.7759911280789,3345.9700224365047]
+,[1371.475991128079,3345.9700224365047]
+,[1371.475991128079,3511.5700224365046]
+,[1470.7759911280789,3511.5700224365046]
+,[1570.0759911280788,3677.1700224365045]
+,[1470.7759911280789,3677.1700224365045]
+,[1570.0759911280788,3511.5700224365046]
+,[1669.3759911280788,3511.5700224365046]
+,[1669.3759911280788,3677.1700224365045]
+,[1768.6759911280787,3842.7700224365044]
+,[1669.3759911280788,3842.7700224365044]
+,[1768.6759911280787,4008.3700224365043]
+,[1867.9759911280787,3842.7700224365044]
+,[1967.2759911280787,3677.1700224365045]
+,[2066.5759911280784,3842.7700224365044]
+,[2165.875991128078,3677.1700224365045]
+,[2066.5759911280784,3511.5700224365046]
+,[2165.875991128078,3511.5700224365046]
+,[2066.5759911280784,3677.1700224365045]
+,[2165.875991128078,3842.7700224365044]
+,[2265.175991128078,4008.3700224365043]
+,[2364.4759911280776,4008.3700224365043]
+,[2265.175991128078,3842.7700224365044]
+,[2364.4759911280776,3677.1700224365045]
+,[2463.7759911280773,3842.7700224365044]
+,[2463.7759911280773,4008.3700224365043]
+,[2364.4759911280776,3842.7700224365044]
+];
+
+
+main() {
+ for (int i = 0; i < 6000; i++) {
+ var y = panels.length;
+ }
+}
+
diff --git a/tests/language/mixin_lib_extends_method_test.dart b/tests/language/mixin_lib_extends_method_test.dart
index 2c43281..b43e0e0 100644
--- a/tests/language/mixin_lib_extends_method_test.dart
+++ b/tests/language/mixin_lib_extends_method_test.dart
@@ -2,6 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+library mixin_lib_extends_method_test;
+
import "mixin_lib_extends_method_lib.dart" as L;
class S {
diff --git a/tests/language/optimized_string_charcodeat_test.dart b/tests/language/optimized_string_charcodeat_test.dart
index 1e84590..aa2bd64 100644
--- a/tests/language/optimized_string_charcodeat_test.dart
+++ b/tests/language/optimized_string_charcodeat_test.dart
@@ -7,27 +7,27 @@
String one_byte = "hest";
String two_byte = "høns";
-int testOneByteCharCodeAt(String x, int i) {
+int testOneByteCharCodeAt(String x, int j) {
int test() {
- return x.charCodeAt(i);
+ return x.charCodeAt(j);
}
for (int i = 0; i < 10000; i++) test();
return test();
}
-int testTwoByteCharCodeAt(String x, int i) {
+int testTwoByteCharCodeAt(String x, int j) {
int test() {
- return x.charCodeAt(i);
+ return x.charCodeAt(j);
}
for (int i = 0; i < 10000; i++) test();
return test();
}
-int testConstantStringCharCodeAt(int i) {
+int testConstantStringCharCodeAt(int j) {
int test() {
- return "høns".charCodeAt(i);
+ return "høns".charCodeAt(j);
}
for (int i = 0; i < 10000; i++) test();
return test();
@@ -43,9 +43,35 @@
}
+int testOneByteCharCodeAtInLoop(var x) {
+ var result = 0;
+ for (int i = 0; i < x.length; i++) {
+ result += x.charCodeAt(i);
+ }
+ return result;
+}
+
+
+int testTwoByteCharCodeAtInLoop(var x) {
+ var result = 0;
+ for (int i = 0; i < x.length; i++) {
+ result += x.charCodeAt(i);
+ }
+ return result;
+}
+
+
main() {
- Expect.equals(101, testOneByteCharCodeAt(one_byte, 1));
- Expect.equals(248, testTwoByteCharCodeAt(two_byte, 1));
- Expect.equals(248, testConstantStringCharCodeAt(1));
- Expect.equals(101, testConstantIndexCharCodeAt(one_byte));
+ for (int j = 0; j < 10; j++) {
+ Expect.equals(101, testOneByteCharCodeAt(one_byte, 1));
+ Expect.equals(248, testTwoByteCharCodeAt(two_byte, 1));
+ Expect.equals(248, testConstantStringCharCodeAt(1));
+ Expect.equals(101, testConstantIndexCharCodeAt(one_byte));
+ }
+ for (int j = 0; j < 2000; j++) {
+ Expect.equals(436, testOneByteCharCodeAtInLoop(one_byte));
+ Expect.equals(577, testTwoByteCharCodeAtInLoop(two_byte));
+ }
+ Expect.throws(() => testOneByteCharCodeAtInLoop(123));
+ Expect.throws(() => testTwoByteCharCodeAtInLoop(123));
}
diff --git a/tests/language/return_this_type_test.dart b/tests/language/return_this_type_test.dart
new file mode 100644
index 0000000..b97e382
--- /dev/null
+++ b/tests/language/return_this_type_test.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+// Make sure the engine does not infer the wrong type for [:A.foo:].
+
+class A {
+ foo() => this;
+}
+
+class B extends A {
+}
+
+main() {
+ Expect.isTrue(new B().foo() is B);
+}
diff --git a/tests/lib/async/future_test.dart b/tests/lib/async/future_test.dart
index 5458e83..43f083a 100644
--- a/tests/lib/async/future_test.dart
+++ b/tests/lib/async/future_test.dart
@@ -564,7 +564,8 @@
final future = completer.future;
var port = new ReceivePort();
- future.then((v) => new Future.delayed(10, () => v * 2))
+ future.then((v) => new Future.delayed(const Duration(milliseconds: 10),
+ () => v * 2))
.then((v) {
Expect.equals(42, v);
port.close();
@@ -572,6 +573,15 @@
completer.complete(21);
}
+testChainedFutureValue2Delay() {
+ var port = new ReceivePort();
+
+ new Future.delayed(const Duration(milliseconds: 10))
+ .then((v) {
+ Expect.isNull(v);
+ port.close();
+ });
+}
testChainedFutureError() {
final completer = new Completer();
final future = completer.future;
diff --git a/tests/lib/async/slow_consumer_test.dart b/tests/lib/async/slow_consumer_test.dart
index dcc6167..4b14924 100644
--- a/tests/lib/async/slow_consumer_test.dart
+++ b/tests/lib/async/slow_consumer_test.dart
@@ -28,8 +28,9 @@
.then((count) {
// Simulated amount of time it takes to handle the data.
int ms = data.length * 1000 ~/ bytesPerSecond;
+ Duration duration = new Duration(milliseconds: ms);
subscription.pause();
- return new Future.delayed(ms, () {
+ return new Future.delayed(duration, () {
subscription.resume();
// Make sure we use data here to keep tracking it.
return count + data.length;
diff --git a/tests/lib/async/stream_from_iterable_test.dart b/tests/lib/async/stream_from_iterable_test.dart
index 182bf1c..0af493d 100644
--- a/tests/lib/async/stream_from_iterable_test.dart
+++ b/tests/lib/async/stream_from_iterable_test.dart
@@ -62,7 +62,10 @@
subscription = stream.listen((int value) {
actual.add(value);
// Do a 10 ms pause during the playback of the iterable.
- if (value == 20) { subscription.pause(new Future.delayed(10, () {})); }
+ Duration duration = const Duration(milliseconds: 10);
+ if (value == 20) {
+ subscription.pause(new Future.delayed(duration, () {}));
+ }
}, onDone: expectAsync0(() {
actual.close();
Events expected = new Events.fromIterable(iter);
diff --git a/tests/lib/lib.status b/tests/lib/lib.status
index c429be3..8381332 100644
--- a/tests/lib/lib.status
+++ b/tests/lib/lib.status
@@ -17,6 +17,9 @@
crypto/sha256_test: Slow, Pass
crypto/sha1_test: Slow, Pass
+[ $runtime == safari]
+crypto/hmac_md5_test: Fail # Bug in JSC: the test only passes when being debugged.
+
[ $compiler == dart2dart ]
# Skip until we stabilize language tests.
*: Skip
diff --git a/tests/standalone/byte_array_test.dart b/tests/standalone/byte_array_test.dart
index 5b29c7a..dd5e232 100644
--- a/tests/standalone/byte_array_test.dart
+++ b/tests/standalone/byte_array_test.dart
@@ -55,6 +55,15 @@
Expect.equals(0, externalClampedByteArray[i]);
}
+ externalClampedByteArray[0] = -1;
+ Expect.equals(0, externalClampedByteArray[0]);
+
+ for (int i = 0; i < 10; i++) {
+ externalClampedByteArray[i] = i + 250;
+ }
+ for (int i = 0; i < 10; i++) {
+ Expect.equals(i + 250 > 255 ? 255 : i + 250, externalClampedByteArray[i]);
+ }
}
void testUnsignedByteArrayRange(bool check_throws) {
diff --git a/tests/standalone/constant_left_shift_test.dart b/tests/standalone/constant_left_shift_test.dart
new file mode 100644
index 0000000..3385a24
--- /dev/null
+++ b/tests/standalone/constant_left_shift_test.dart
@@ -0,0 +1,78 @@
+// 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.
+//
+// Dart test program for testing left shifts of a constant.
+
+shiftLeft0(c) => 0 << c;
+shiftLeft1(c) => 1 << c;
+shiftLeft8448(c) => 8448 << c;
+
+shiftLeftNeg1(c) => -1 << c;
+shiftLeftNeg8448(c) => -8448 << c;
+
+main() {
+ // Optimize shifts.
+ for (int i = 0; i < 6000; i++) {
+ shiftLeft1(2);
+ shiftLeft0(2);
+ shiftLeft8448(2);
+ shiftLeftNeg1(2);
+ shiftLeftNeg8448(2);
+ }
+ for (int i = 0; i < 80; i++) {
+ Expect.equals(0, shiftLeft0(i));
+ }
+ // Exceptions.
+ Expect.throws(() => shiftLeft0(-1));
+
+ return;
+ Expect.equals(1, shiftLeft1(0));
+ Expect.equals(128, shiftLeft1(7));
+ Expect.equals(536870912, shiftLeft1(29));
+ // Deoptimize on 32-bit.
+ Expect.equals(1073741824, shiftLeft1(30));
+ Expect.equals(2147483648, shiftLeft1(31));
+ Expect.equals(1152921504606846976, shiftLeft1(60));
+ Expect.equals(2305843009213693952, shiftLeft1(61));
+ // Deoptimize on 64 bits.
+ Expect.equals(4611686018427387904, shiftLeft1(62));
+ Expect.equals(9223372036854775808, shiftLeft1(63));
+
+ Expect.equals(8448, shiftLeft8448(0));
+ Expect.equals(1081344, shiftLeft8448(7));
+ Expect.equals(553648128, shiftLeft8448(16));
+ // Deoptimize on 32-bit.
+ Expect.equals(1107296256, shiftLeft8448(17));
+ Expect.equals(2214592512, shiftLeft8448(18));
+ Expect.equals(1188950301625810944, shiftLeft8448(47));
+ Expect.equals(2377900603251621888, shiftLeft8448(48));
+ // Deoptimize on 64 bits.
+ Expect.equals(4755801206503243776, shiftLeft8448(49));
+ Expect.equals(9511602413006487552, shiftLeft8448(50));
+
+ Expect.equals(-1, shiftLeftNeg1(0));
+ Expect.equals(-128, shiftLeftNeg1(7));
+ Expect.equals(-536870912, shiftLeftNeg1(29));
+ // Deoptimize on 32-bit.
+ Expect.equals(-1073741824, shiftLeftNeg1(30));
+ Expect.equals(-2147483648, shiftLeftNeg1(31));
+ Expect.equals(-1152921504606846976, shiftLeftNeg1(60));
+ Expect.equals(-2305843009213693952, shiftLeftNeg1(61));
+ // Deoptimize on 64 bits.
+ Expect.equals(-4611686018427387904, shiftLeftNeg1(62));
+ Expect.equals(-9223372036854775808, shiftLeftNeg1(63));
+
+ Expect.equals(-8448, shiftLeftNeg8448(0));
+ Expect.equals(-1081344, shiftLeftNeg8448(7));
+ Expect.equals(-553648128, shiftLeftNeg8448(16));
+ // Deoptimize on 32-bit.
+ Expect.equals(-1107296256, shiftLeftNeg8448(17));
+ Expect.equals(-2214592512, shiftLeftNeg8448(18));
+ Expect.equals(-1188950301625810944, shiftLeftNeg8448(47));
+ Expect.equals(-2377900603251621888, shiftLeftNeg8448(48));
+ // Deoptimize on 64 bits.
+ Expect.equals(-4755801206503243776, shiftLeftNeg8448(49));
+ Expect.equals(-9511602413006487552, shiftLeftNeg8448(50));
+}
+
diff --git a/tests/standalone/io/fuzz_support.dart b/tests/standalone/io/fuzz_support.dart
index 4c7cd1c..e6caa12 100644
--- a/tests/standalone/io/fuzz_support.dart
+++ b/tests/standalone/io/fuzz_support.dart
@@ -49,5 +49,7 @@
// completion.
Future doItAsync(void f()) {
// Ignore value and errors.
- return new Future.delayed(0, f).catchError((_) {}).then((_) => true);
+ return new Future.delayed(Duration.ZERO, f)
+ .catchError((_) {})
+ .then((_) => true);
}
diff --git a/tests/standalone/io/skipping_dart2js_compilations_test.dart b/tests/standalone/io/skipping_dart2js_compilations_test.dart
index d6b7eb4..c6ce377 100644
--- a/tests/standalone/io/skipping_dart2js_compilations_test.dart
+++ b/tests/standalone/io/skipping_dart2js_compilations_test.dart
@@ -141,13 +141,10 @@
Expect.isFalse(new File(fileUtils.scriptOutputPath.toNativePath())
.existsSync());
}
- fileUtils.cleanup();
}
}
-runner.TestCase makeTestCase(String testName,
- TestCompletedHandler completedHandler) {
- var fileUtils = completedHandler.fileUtils;
+runner.TestCase makeTestCase(String testName, FileUtils fileUtils) {
var config = new options.TestOptionsParser().parse(['--timeout', '2'])[0];
var scriptDirPath = new Path(new Options().script).directoryPath;
var createFileScript = scriptDirPath.
@@ -166,7 +163,7 @@
testName,
commands,
config,
- completedHandler.processCompletedTest,
+ (_) {},
new Set<String>.from([status.PASS]));
}
@@ -199,26 +196,52 @@
createJsDeps: true,
createDart: true,
createSnapshot: true);
+ void cleanup() {
+ fs_noTestJs.cleanup();
+ fs_noTestJsDeps.cleanup();
+ fs_noTestDart.cleanup();
+ fs_noTestSnapshot.cleanup();
+ fs_notUpToDate_snapshot.cleanup();
+ fs_notUpToDate_dart.cleanup();
+ fs_upToDate.cleanup();
+ }
void touchFilesAndRunTests() {
fs_notUpToDate_snapshot.touchFile(fs_notUpToDate_snapshot.testSnapshot);
fs_notUpToDate_dart.touchFile(fs_notUpToDate_dart.testDart);
fs_upToDate.touchFile(fs_upToDate.testJs);
- void runTest(String name, FileUtils fileUtils, bool shouldRun) {
- var testCase = makeTestCase(
- name, new TestCompletedHandler(fileUtils, shouldRun));
- new runner.RunningProcess(testCase, testCase.commands[0]).start();
+ Future runTest(String name, FileUtils fileUtils, bool shouldRun) {
+ var completedHandler = new TestCompletedHandler(fileUtils, shouldRun);
+ var testCase = makeTestCase(name, fileUtils);
+ var process = new runner.RunningProcess(testCase, testCase.commands[0]);
+ return process.start().then((_) {
+ completedHandler.processCompletedTest(testCase);
+ });
}
- runTest("fs_noTestJs", fs_noTestJs, true);
- runTest("fs_noTestJsDeps", fs_noTestJsDeps, true);
- runTest("fs_noTestDart", fs_noTestDart, true);
- runTest("fs_noTestSnapshot", fs_noTestSnapshot, true);
- runTest("fs_notUpToDate_snapshot", fs_notUpToDate_snapshot, true);
- runTest("fs_notUpToDate_dart", fs_notUpToDate_dart, true);
- // This is the only test where all dependencies are present and the test.js
- // file is newer than all the others. So we pass 'false' for shouldRun.
- runTest("fs_upToDate", fs_upToDate, false);
+ // We run the tests in sequence, so that if one of them failes we clean up
+ // everything and throw.
+ runTest("fs_noTestJs", fs_noTestJs, true).then((_) {
+ return runTest("fs_noTestJsDeps", fs_noTestJsDeps, true);
+ }).then((_) {
+ return runTest("fs_noTestDart", fs_noTestDart, true);
+ }).then((_) {
+ return runTest("fs_noTestSnapshot", fs_noTestSnapshot, true);
+ }).then((_) {
+ return runTest("fs_notUpToDate_snapshot", fs_notUpToDate_snapshot, true);
+ }).then((_) {
+ return runTest("fs_notUpToDate_dart", fs_notUpToDate_dart, true);
+ }).then((_) {
+ // This is the only test where all dependencies are present and the
+ // test.js file is newer than all the others. So we pass 'false' for
+ // shouldRun.
+ return runTest("fs_upToDate", fs_upToDate, false);
+ }).catchError((error) {
+ cleanup();
+ throw error;
+ }).then((_) {
+ cleanup();
+ });
}
// We need to wait some time to make sure that the files we 'touch' get a
// bigger timestamp than the old ones
diff --git a/tests/utils/uri_test.dart b/tests/utils/uri_test.dart
index 2aa688e..a5f0c23 100644
--- a/tests/utils/uri_test.dart
+++ b/tests/utils/uri_test.dart
@@ -8,8 +8,8 @@
import 'dart:uri';
testUri(String uri, bool isAbsolute) {
- Expect.equals(isAbsolute, Uri.parse(uri).isAbsolute());
- Expect.equals(isAbsolute, new Uri(uri).isAbsolute());
+ Expect.equals(isAbsolute, Uri.parse(uri).isAbsolute);
+ Expect.equals(isAbsolute, new Uri(uri).isAbsolute);
Expect.stringEquals(uri, Uri.parse(uri).toString());
Expect.stringEquals(uri, new Uri(uri).toString());
diff --git a/tools/VERSION b/tools/VERSION
index 54a53be..05b0467 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -1,4 +1,4 @@
MAJOR 0
MINOR 3
BUILD 6
-PATCH 1
+PATCH 2
diff --git a/tools/dom/scripts/generator.py b/tools/dom/scripts/generator.py
index 52e10ea..12d22c0 100644
--- a/tools/dom/scripts/generator.py
+++ b/tools/dom/scripts/generator.py
@@ -8,6 +8,7 @@
import copy
import json
+import monitored
import os
import re
from htmlrenamer import html_interface_renames, renamed_html_members
@@ -17,7 +18,7 @@
_json_path = os.path.join(_current_dir, '..', 'docs', 'docs.json')
_dom_json = json.load(open(_json_path))
-_pure_interfaces = set([
+_pure_interfaces = monitored.Set('generator._pure_interfaces', [
# TODO(sra): DOMStringMap should be a class implementing Map<String,String>.
'DOMStringMap',
'ElementTimeControl',
@@ -25,7 +26,6 @@
'EventListener',
'MediaQueryListListener',
'MutationCallback',
- 'NodeSelector',
'SVGExternalResourcesRequired',
'SVGFilterPrimitiveStandardAttributes',
'SVGFitToViewBox',
@@ -41,7 +41,8 @@
return interface_name in _pure_interfaces
-_methods_with_named_formals = set([
+_methods_with_named_formals = monitored.Set(
+ 'generator._methods_with_named_formals', [
'DataView.getFloat32',
'DataView.getFloat64',
'DataView.getInt16',
@@ -65,16 +66,15 @@
#
# Renames for attributes that have names that are not legal Dart names.
#
-_dart_attribute_renames = {
+_dart_attribute_renames = monitored.Dict('generator._dart_attribute_renames', {
'default': 'defaultValue',
- 'final': 'finalValue',
-}
+})
#
# Interface version of the DOM needs to delegate typed array constructors to a
# factory provider.
#
-interface_factories = {
+interface_factories = monitored.Dict('generator.interface_factories', {
'Float32Array': '_TypedArrayFactoryProvider',
'Float64Array': '_TypedArrayFactoryProvider',
'Int8Array': '_TypedArrayFactoryProvider',
@@ -84,19 +84,20 @@
'Uint8ClampedArray': '_TypedArrayFactoryProvider',
'Uint16Array': '_TypedArrayFactoryProvider',
'Uint32Array': '_TypedArrayFactoryProvider',
-}
+})
#
# Custom native specs for the dart2js dom.
#
-_dart2js_dom_custom_native_specs = {
+_dart2js_dom_custom_native_specs = monitored.Dict(
+ 'generator._dart2js_dom_custom_native_specs', {
# Decorate the singleton Console object, if present (workers do not have a
# console).
'Console': "=(typeof console == 'undefined' ? {} : console)",
# DOMWindow aliased with global scope.
- 'DOMWindow': '@*DOMWindow',
-}
+ 'Window': '@*DOMWindow',
+})
def IsRegisteredType(type_name):
return type_name in _idl_type_registry
@@ -419,7 +420,7 @@
_serialize_SSV = Conversion('convertDartToNative_SerializedScriptValue',
'dynamic', 'dynamic')
-dart2js_conversions = {
+dart2js_conversions = monitored.Dict('generator.dart2js_conversions', {
# Wrap non-local Windows. We need to check EventTarget (the base type)
# as well. Note, there are no functions that take a non-local Window
# as a parameter / setter.
@@ -432,11 +433,6 @@
Conversion('_convertDartToNative_EventTarget', 'EventTarget',
'dynamic'),
- 'IDBKey get':
- Conversion('_convertNativeToDart_IDBKey', 'dynamic', 'dynamic'),
- 'IDBKey set':
- Conversion('_convertDartToNative_IDBKey', 'dynamic', 'dynamic'),
-
'ImageData get':
Conversion('_convertNativeToDart_ImageData', 'dynamic', 'ImageData'),
'ImageData set':
@@ -447,7 +443,7 @@
'Dictionary set':
Conversion('convertDartToNative_Dictionary', 'Map', 'dynamic'),
- 'DOMString[] set':
+ 'sequence<DOMString> set':
Conversion('convertDartToNative_StringArray', 'List<String>', 'List'),
'any set IDBObjectStore.add': _serialize_SSV,
@@ -476,7 +472,7 @@
# IDBAny is problematic. Some uses are just a union of other IDB types,
# which need no conversion.. Others include data values which require
# serialized script value processing.
- 'IDBAny get IDBCursorWithValue.value':
+ '* get IDBCursorWithValue.value':
Conversion('_convertNativeToDart_IDBAny', 'dynamic', 'dynamic'),
# This is problematic. The result property of IDBRequest is used for
@@ -492,7 +488,7 @@
# Should be either a DOMString, an Array of DOMStrings or null.
'IDBAny get IDBObjectStore.keyPath': None,
-}
+})
def FindConversion(idl_type, direction, interface, member):
table = dart2js_conversions
@@ -513,7 +509,7 @@
# -TYPE: add annotations only if there are no member annotations.
# TYPE: add regardless of member annotations.
-dart2js_annotations = {
+dart2js_annotations = monitored.Dict('generator.dart2js_annotations', {
'CanvasRenderingContext2D.createImageData': [
"@Creates('ImageData|=Object')",
@@ -549,12 +545,6 @@
"@Creates('DatabaseSync')",
],
- # Cross-frame windows are EventTargets.
- '-EventTarget': [
- "@Creates('EventTarget|=Object')",
- "@Returns('EventTarget|=Object')",
- ],
-
# To be in callback with the browser-created Event, we had to have called
# addEventListener on the target, so we avoid
'Event.currentTarget': [
@@ -627,10 +617,6 @@
"@Returns('Request')",
"@Creates('Request')",
],
- '+IDBVersionChangeRequest': [
- "@Returns('Request')",
- "@Creates('Request')",
- ],
'MessageEvent.ports': ["@Creates('=List')"],
@@ -652,7 +638,7 @@
'XMLHttpRequest.response': [
"@Creates('ArrayBuffer|Blob|Document|=Object|=List|String|num')",
],
-}
+})
_indexed_db_annotations = [
"@SupportedBrowser(SupportedBrowser.CHROME)",
@@ -721,7 +707,7 @@
# The table is indexed as:
# INTERFACE: annotations to be added to the interface declaration
# INTERFACE.MEMBER: annotation to be added to the member declaration
-dart_annotations = {
+dart_annotations = monitored.Dict('generator.dart_annotations', {
'ArrayBuffer': _all_but_ie9_annotations,
'ArrayBufferView': _all_but_ie9_annotations,
'Database': _web_sql_annotations,
@@ -733,8 +719,10 @@
"@SupportedBrowser(SupportedBrowser.OPERA)",
"@SupportedBrowser(SupportedBrowser.SAFARI)",
],
- 'DOMWindow.convertPointFromNodeToPage': _webkit_experimental_annotations,
- 'DOMWindow.convertPointFromPageToNode': _webkit_experimental_annotations,
+ 'DOMFileSystem': _file_system_annotations,
+ 'DOMFileSystemSync': _file_system_annotations,
+ 'DOMWindow.webkitConvertPointFromNodeToPage': _webkit_experimental_annotations,
+ 'DOMWindow.webkitConvertPointFromPageToNode': _webkit_experimental_annotations,
'DOMWindow.indexedDB': _indexed_db_annotations,
'DOMWindow.openDatabase': _web_sql_annotations,
'DOMWindow.performance': _performance_annotations,
@@ -749,8 +737,6 @@
"@SupportedBrowser(SupportedBrowser.CHROME, '25')",
"@Experimental",
],
- 'FileSystem': _file_system_annotations,
- 'FileSystemSync': _file_system_annotations,
'HashChangeEvent': [
"@SupportedBrowser(SupportedBrowser.CHROME)",
"@SupportedBrowser(SupportedBrowser.FIREFOX)",
@@ -791,11 +777,9 @@
'IDBDatabase': _indexed_db_annotations,
'LocalMediaStream': _rtc_annotations,
'MediaStream': _rtc_annotations,
- 'MediaStreamEvents': _rtc_annotations,
'MediaStreamEvent': _rtc_annotations,
'MediaStreamTrack': _rtc_annotations,
'MediaStreamTrackEvent': _rtc_annotations,
- 'MediaStreamTrackEvents': _rtc_annotations,
'MutationObserver': [
"@SupportedBrowser(SupportedBrowser.CHROME)",
"@SupportedBrowser(SupportedBrowser.FIREFOX)",
@@ -837,7 +821,7 @@
'SVGFEImageElement': _svg_annotations,
'SVGFEMergeElement': _svg_annotations,
'SVGFEMergeNodeElement': _svg_annotations,
- 'SVGFEMorphology': _svg_annotations,
+ 'SVGFEMorphologyElement': _svg_annotations,
'SVGFEOffsetElement': _svg_annotations,
'SVGFEPointLightElement': _svg_annotations,
'SVGFESpecularLightingElement': _svg_annotations,
@@ -866,7 +850,7 @@
"@SupportedBrowser(SupportedBrowser.FIREFOX)",
"@SupportedBrowser(SupportedBrowser.SAFARI)",
],
-}
+})
def GetComments(library_name, interface_name, member_name=None):
""" Finds all comments for the interface or member and returns a list. """
@@ -1306,7 +1290,7 @@
return TypeData(clazz='Interface', item_type=item_type, is_typed_array=True)
-_idl_type_registry = {
+_idl_type_registry = monitored.Dict('generator._idl_type_registry', {
'boolean': TypeData(clazz='Primitive', dart_type='bool', native_type='bool',
webcore_getter_name='hasAttribute',
webcore_setter_name='setBooleanAttribute'),
@@ -1339,9 +1323,6 @@
# TODO(vsm): This won't actually work until we convert the Map to
# a native JS Map for JS DOM.
'Dictionary': TypeData(clazz='Primitive', dart_type='Map'),
- # TODO(sra): Flags is really a dictionary: {create:bool, exclusive:bool}
- # http://dev.w3.org/2009/dap/file-system/file-dir-sys.html#the-flags-interface
- 'Flags': TypeData(clazz='Primitive', dart_type='Object'),
'DOMTimeStamp': TypeData(clazz='Primitive', dart_type='int', native_type='unsigned long long'),
'object': TypeData(clazz='Primitive', dart_type='Object', native_type='ScriptValue'),
'ObjectArray': TypeData(clazz='Primitive', dart_type='List'),
@@ -1350,10 +1331,6 @@
# the documentation, the user is made aware that only a limited subset of
# serializable types are actually permitted.
'SerializedScriptValue': TypeData(clazz='Primitive', dart_type='dynamic'),
- # TODO(sra): Flags is really a dictionary: {create:bool, exclusive:bool}
- # http://dev.w3.org/2009/dap/file-system/file-dir-sys.html#the-flags-interface
- 'WebKitFlags': TypeData(clazz='Primitive', dart_type='Object'),
-
'sequence': TypeData(clazz='Primitive', dart_type='List'),
'void': TypeData(clazz='Primitive', dart_type='void'),
@@ -1368,7 +1345,6 @@
'HTMLElement': TypeData(clazz='Interface', merged_into='Element',
custom_to_dart=True),
'IDBAny': TypeData(clazz='Interface', dart_type='dynamic', custom_to_native=True),
- 'IDBKey': TypeData(clazz='Interface', dart_type='dynamic', custom_to_native=True),
'MutationRecordArray': TypeData(clazz='Interface', # C++ pass by pointer.
native_type='MutationRecordArray', dart_type='List<MutationRecord>'),
'StyleSheet': TypeData(clazz='Interface', conversion_includes=['CSSStyleSheet']),
@@ -1413,8 +1389,6 @@
'TextTrackCueList': TypeData(clazz='Interface', item_type='TextTrackCue'),
'TextTrackList': TypeData(clazz='Interface', item_type='TextTrack'),
'TouchList': TypeData(clazz='Interface', item_type='Touch'),
- 'WebKitAnimationList': TypeData(clazz='Interface',
- item_type='WebKitAnimation', suppress_interface=True),
'Float32Array': TypedArrayTypeData('double'),
'Float64Array': TypedArrayTypeData('double'),
@@ -1443,7 +1417,7 @@
'SVGTransform': TypeData(clazz='SVGTearOff'),
'SVGTransformList': TypeData(clazz='SVGTearOff', item_type='SVGTransform',
native_type='SVGTransformListPropertyTearOff'),
-}
+})
_svg_supplemental_includes = [
'"SVGAnimatedPropertyTearOff.h"',
diff --git a/tools/dom/scripts/htmleventgenerator.py b/tools/dom/scripts/htmleventgenerator.py
index a05dd1b..64063b3 100644
--- a/tools/dom/scripts/htmleventgenerator.py
+++ b/tools/dom/scripts/htmleventgenerator.py
@@ -6,6 +6,7 @@
"""This module provides functionality to generate dart:html event classes."""
import logging
+import monitored
from generator import GetAnnotationsAndComments, FormatAnnotationsAndComments
_logger = logging.getLogger('dartgenerator')
@@ -14,176 +15,24 @@
# We can automatically extract most event names by checking for
# onEventName methods in the IDL but some events aren't listed so we need
# to manually add them here so that they are easy for users to find.
-_html_manual_events = {
+_html_manual_events = monitored.Dict('htmleventgenerator._html_manual_events', {
'Element': ['touchleave', 'touchenter', 'webkitTransitionEnd'],
'Window': ['DOMContentLoaded']
-}
+})
# These event names must be camel case when attaching event listeners
# using addEventListener even though the onEventName properties in the DOM for
# them are not camel case.
-_on_attribute_to_event_name_mapping = {
+_on_attribute_to_event_name_mapping = monitored.Dict(
+ 'htmleventgenerator._on_attribute_to_event_name_mapping', {
'webkitanimationend': 'webkitAnimationEnd',
'webkitanimationiteration': 'webkitAnimationIteration',
'webkitanimationstart': 'webkitAnimationStart',
'webkitspeechchange': 'webkitSpeechChange',
'webkittransitionend': 'webkitTransitionEnd',
-}
+})
-# Mapping from raw event names to the pretty camelCase event names exposed as
-# properties in dart:html. If the DOM exposes a new event name, you will need
-# to add the lower case to camel case conversion for that event name here.
-_html_event_names = {
- 'DOMContentLoaded': 'contentLoaded',
- 'abort': 'abort',
- 'addstream': 'addStream',
- 'addtrack': 'addTrack',
- 'audioend': 'audioEnd',
- 'audioprocess': 'audioProcess',
- 'audiostart': 'audioStart',
- 'beforecopy': 'beforeCopy',
- 'beforecut': 'beforeCut',
- 'beforepaste': 'beforePaste',
- 'beforeunload': 'beforeUnload',
- 'blocked': 'blocked',
- 'blur': 'blur',
- 'cached': 'cached',
- 'canplay': 'canPlay',
- 'canplaythrough': 'canPlayThrough',
- 'change': 'change',
- 'chargingchange': 'chargingChange',
- 'chargingtimechange': 'chargingTimeChange',
- 'checking': 'checking',
- 'click': 'click',
- 'close': 'close',
- 'complete': 'complete',
- 'connect': 'connect',
- 'connecting': 'connecting',
- 'contextmenu': 'contextMenu',
- 'copy': 'copy',
- 'cuechange': 'cueChange',
- 'cut': 'cut',
- 'dblclick': 'doubleClick',
- 'devicemotion': 'deviceMotion',
- 'deviceorientation': 'deviceOrientation',
- 'dischargingtimechange': 'dischargingTimeChange',
- 'display': 'display',
- 'downloading': 'downloading',
- 'drag': 'drag',
- 'dragend': 'dragEnd',
- 'dragenter': 'dragEnter',
- 'dragleave': 'dragLeave',
- 'dragover': 'dragOver',
- 'dragstart': 'dragStart',
- 'drop': 'drop',
- 'durationchange': 'durationChange',
- 'emptied': 'emptied',
- 'end': 'end',
- 'ended': 'ended',
- 'enter': 'enter',
- 'error': 'error',
- 'exit': 'exit',
- 'focus': 'focus',
- 'hashchange': 'hashChange',
- 'icecandidate': 'iceCandidate',
- 'icechange': 'iceChange',
- 'input': 'input',
- 'invalid': 'invalid',
- 'keydown': 'keyDown',
- 'keypress': 'keyPress',
- 'keyup': 'keyUp',
- 'levelchange': 'levelChange',
- 'load': 'load',
- 'loadeddata': 'loadedData',
- 'loadedmetadata': 'loadedMetadata',
- 'loadend': 'loadEnd',
- 'loadstart': 'loadStart',
- 'message': 'message',
- 'mousedown': 'mouseDown',
- 'mousemove': 'mouseMove',
- 'mouseout': 'mouseOut',
- 'mouseover': 'mouseOver',
- 'mouseup': 'mouseUp',
- 'mousewheel': 'mouseWheel',
- 'mute': 'mute',
- 'negotiationneeded': 'negotiationNeeded',
- 'nomatch': 'noMatch',
- 'noupdate': 'noUpdate',
- 'obsolete': 'obsolete',
- 'offline': 'offline',
- 'online': 'online',
- 'open': 'open',
- 'pagehide': 'pageHide',
- 'pageshow': 'pageShow',
- 'paste': 'paste',
- 'pause': 'pause',
- 'play': 'play',
- 'playing': 'playing',
- 'popstate': 'popState',
- 'progress': 'progress',
- 'ratechange': 'rateChange',
- 'readystatechange': 'readyStateChange',
- 'removestream': 'removeStream',
- 'removetrack': 'removeTrack',
- 'reset': 'reset',
- 'resize': 'resize',
- 'result': 'result',
- 'resultdeleted': 'resultDeleted',
- 'scroll': 'scroll',
- 'search': 'search',
- 'seeked': 'seeked',
- 'seeking': 'seeking',
- 'select': 'select',
- 'selectionchange': 'selectionChange',
- 'selectstart': 'selectStart',
- 'show': 'show',
- 'soundend': 'soundEnd',
- 'soundstart': 'soundStart',
- 'speechend': 'speechEnd',
- 'speechstart': 'speechStart',
- 'stalled': 'stalled',
- 'start': 'start',
- 'statechange': 'stateChange',
- 'storage': 'storage',
- 'submit': 'submit',
- 'success': 'success',
- 'suspend': 'suspend',
- 'timeupdate': 'timeUpdate',
- 'touchcancel': 'touchCancel',
- 'touchend': 'touchEnd',
- 'touchenter': 'touchEnter',
- 'touchleave': 'touchLeave',
- 'touchmove': 'touchMove',
- 'touchstart': 'touchStart',
- 'unload': 'unload',
- 'upgradeneeded': 'upgradeNeeded',
- 'unmute': 'unmute',
- 'updateready': 'updateReady',
- 'versionchange': 'versionChange',
- 'volumechange': 'volumeChange',
- 'waiting': 'waiting',
- 'webkitAnimationEnd': 'animationEnd',
- 'webkitAnimationIteration': 'animationIteration',
- 'webkitAnimationStart': 'animationStart',
- 'webkitfullscreenchange': 'fullscreenChange',
- 'webkitfullscreenerror': 'fullscreenError',
- 'webkitkeyadded': 'keyAdded',
- 'webkitkeyerror': 'keyError',
- 'webkitkeymessage': 'keyMessage',
- 'webkitneedkey': 'needKey',
- 'webkitpointerlockchange': 'pointerLockChange',
- 'webkitpointerlockerror': 'pointerLockError',
- 'webkitSpeechChange': 'speechChange',
- 'webkitsourceclose': 'sourceClose',
- 'webkitsourceended': 'sourceEnded',
- 'webkitsourceopen': 'sourceOpen',
- 'webkitTransitionEnd': 'transitionEnd',
- 'write': 'write',
- 'writeend': 'writeEnd',
- 'writestart': 'writeStart'
-}
-
-_html_event_types = {
+_html_event_types = monitored.Dict('htmleventgenerator._html_event_types', {
'*.abort': ('abort', 'Event'),
'*.beforecopy': ('beforeCopy', 'Event'),
'*.beforecut': ('beforeCut', 'Event'),
@@ -275,12 +124,10 @@
'DOMApplicationCache.obsolete': ('obsolete', 'Event'),
'DOMApplicationCache.progress': ('progress', 'Event'),
'DOMApplicationCache.updateready': ('updateReady', 'Event'),
- 'Document.cuechange': ('cueChange', 'Event'),
'Document.readystatechange': ('readyStateChange', 'Event'),
'Document.selectionchange': ('selectionChange', 'Event'),
'Document.webkitpointerlockchange': ('pointerLockChange', 'Event'),
'Document.webkitpointerlockerror': ('pointerLockError', 'Event'),
- 'Element.cuechange': ('cueChange', 'Event'),
'EventSource.open': ('open', 'Event'),
'FileReader.abort': ('abort', 'ProgressEvent'),
'FileReader.load': ('load', 'ProgressEvent'),
@@ -306,12 +153,10 @@
'IDBOpenDBRequest.upgradeneeded': ('upgradeNeeded', 'VersionChangeEvent'),
'IDBRequest.success': ('success', 'Event'),
'IDBTransaction.complete': ('complete', 'Event'),
- 'IDBVersionChangeRequest.blocked': ('blocked', 'Event'),
- 'MediaController.play': ('play', 'Event'),
+ 'MediaStream.addtrack': ('addTrack', 'Event'),
+ 'MediaStream.removetrack': ('removeTrack', 'Event'),
'MediaStreamTrack.mute': ('mute', 'Event'),
'MediaStreamTrack.unmute': ('unmute', 'Event'),
- 'MediaStreamTrackList.addtrack': ('addTrack', 'MediaStreamTrackEvent'),
- 'MediaStreamTrackList.removetrack': ('removeTrack', 'MediaStreamTrackEvent'),
'Notification.click': ('click', 'Event'),
'Notification.close': ('close', 'Event'),
'Notification.display': ('display', 'Event'),
@@ -319,15 +164,13 @@
'RTCDataChannel.close': ('close', 'Event'),
'RTCDataChannel.open': ('open', 'Event'),
'RTCPeerConnection.addstream': ('addStream', 'MediaStreamEvent'),
- 'RTCPeerConnection.connecting': ('connecting', 'MediaStreamEvent'),
'RTCPeerConnection.datachannel': ('dataChannel', 'RtcDataChannelEvent'),
'RTCPeerConnection.icecandidate': ('iceCandidate', 'RtcIceCandidateEvent'),
'RTCPeerConnection.icechange': ('iceChange', 'Event'),
+ 'RTCPeerConnection.gatheringchange': ('gatheringChange', 'Event'),
'RTCPeerConnection.negotiationneeded': ('negotiationNeeded', 'Event'),
- 'RTCPeerConnection.open': ('open', 'Event'),
'RTCPeerConnection.removestream': ('removeStream', 'MediaStreamEvent'),
'RTCPeerConnection.statechange': ('stateChange', 'Event'),
- 'ScriptProcessorNode.audioprocess': ('audioProcess', 'AudioProcessingEvent'),
'SharedWorkerContext.connect': ('connect', 'Event'),
'SpeechRecognition.audioend': ('audioEnd', 'Event'),
'SpeechRecognition.audiostart': ('audioStart', 'Event'),
@@ -347,7 +190,6 @@
'WebSocket.close': ('close', 'CloseEvent'),
'WebSocket.open': ('open', 'Event'), # should be OpenEvent, but not exposed.
'Window.DOMContentLoaded': ('contentLoaded', 'Event'),
- 'Window.cuechange': ('cueChange', 'Event'),
'Window.devicemotion': ('deviceMotion', 'DeviceMotionEvent'),
'Window.deviceorientation': ('deviceOrientation', 'DeviceOrientationEvent'),
'Window.loadstart': ('loadStart', 'Event'),
@@ -367,7 +209,7 @@
'XMLHttpRequestUpload.loadend': ('loadEnd', 'ProgressEvent'),
'XMLHttpRequestUpload.loadstart': ('loadStart', 'ProgressEvent'),
'XMLHttpRequestUpload.progress': ('progress', 'ProgressEvent'),
-}
+})
# These classes require an explicit declaration for the "on" method even though
# they don't declare any unique events, because the concrete class hierarchy
@@ -517,84 +359,3 @@
_logger.warn('Cannot resolve event type for %s.%s' %
(html_interface_name, dom_event_name))
return None
-
- def ProcessInterface(self, interface, html_interface_name, custom_events,
- events_implementation_emitter):
- event_names = set([attr.id[2:] for attr in interface.attributes
- if attr.type.id == 'EventListener'])
-
- # Document and DocumentFragment actually derive from Element, so omit
- # any events which are duplicated with that.
- if interface.id == 'Document' or interface.id == 'DocumentFragment':
- element_interface = self._database.GetInterface('Element')
- for attr in element_interface.attributes:
- if attr.type.id == 'EventListener' and attr.id[2:] in event_names:
- event_names.remove(attr.id[2:])
-
- if not event_names and interface.id not in _html_explicit_event_classes:
- return None
-
- self._event_classes.add(interface.id)
- events_class_name = html_interface_name + 'Events'
- parent_events_class_name = self._GetParentEventsClassName(interface)
-
- if not event_names:
- return parent_events_class_name
-
- template_file = 'impl_%s.darttemplate' % events_class_name
- template = (self._template_loader.TryLoad(template_file) or
- '\n'
- '@DocsEditable\n'
- '@deprecated\n'
- 'class $CLASSNAME extends $SUPER {\n'
- ' @DocsEditable\n'
- ' $CLASSNAME(EventTarget _ptr) : super(_ptr);\n'
- '$!MEMBERS}\n')
-
- # TODO(jacobr): specify the type of _ptr as EventTarget
- implementation_events_members = events_implementation_emitter.Emit(
- template,
- CLASSNAME=events_class_name,
- SUPER='%s' % parent_events_class_name)
-
- dom_event_names = set()
- for event in event_names:
- dom_name = event
- dom_name = _on_attribute_to_event_name_mapping.get(dom_name, dom_name)
- dom_event_names.add(dom_name)
- if html_interface_name in _html_manual_events:
- dom_event_names.update(_html_manual_events[html_interface_name])
- for dom_name in sorted(dom_event_names):
- if dom_name not in _html_event_names:
- _logger.warn('omitting %s event as there is no HTML name for it' % dom_name)
- continue
-
- html_name = _html_event_names[dom_name]
- full_event_name = '%sEvents.%s' % (html_interface_name, html_name)
- if not full_event_name in custom_events:
- implementation_events_members.Emit(
- "\n"
- " @DocsEditable\n"
- " EventListenerList get $NAME => this['$DOM_NAME'];\n",
- NAME=html_name,
- DOM_NAME=dom_name)
-
- return events_class_name
-
- # TODO(jacobr): this isn't quite right....
- def _GetParentEventsClassName(self, interface):
- # Ugly hack as we don't specify that Document and DocumentFragment inherit
- # from Element in our IDL.
- if interface.id == 'Document' or interface.id == 'DocumentFragment':
- return 'ElementEvents'
-
- parent_events_class_name = 'Events'
- interfaces_with_events = set()
- for parent in self._database.Hierarchy(interface):
- if parent != interface and parent.id in self._event_classes:
- parent_name = self._renamer.RenameInterface(parent)
- parent_events_class_name = parent_name + 'Events'
- interfaces_with_events.add(parent)
- if len(interfaces_with_events) > 1:
- raise Exception('Only one parent event class allowed ' + interface.id)
- return parent_events_class_name
diff --git a/tools/dom/scripts/htmlrenamer.py b/tools/dom/scripts/htmlrenamer.py
index 1dc400e..2057291 100644
--- a/tools/dom/scripts/htmlrenamer.py
+++ b/tools/dom/scripts/htmlrenamer.py
@@ -135,6 +135,9 @@
'Element.querySelectorAll',
'Element.removeAttribute',
'Element.removeAttributeNS',
+ 'Element.scrollIntoView',
+ 'Element.scrollIntoViewIfNeeded',
+ 'Element.setAttributeNS',
'Element.setAttribute',
'Element.setAttributeNS',
'ElementTraversal.childElementCount',
@@ -198,7 +201,6 @@
'DOMWindow.webkitResolveLocalFileSystemURL': 'resolveLocalFileSystemUrl',
'DOMWindow.webkitRequestFileSystem': 'requestFileSystem',
'DOMWindow.webkitResolveLocalFileSystemURL': 'resolveLocalFileSystemUrl',
- 'Element.scrollIntoViewIfNeeded': 'scrollIntoView',
'Element.webkitCreateShadowRoot': 'createShadowRoot',
'Element.webkitMatchesSelector' : 'matches',
'Navigator.webkitGetUserMedia': '_getUserMedia',
@@ -337,7 +339,6 @@
'Element.innerText',
'Element.outerText',
'Element.removeAttributeNode',
- 'Element.scrollIntoView',
'Element.set:outerHTML',
'Element.setAttributeNode',
'Element.setAttributeNodeNS',
diff --git a/tools/dom/scripts/idlsync.py b/tools/dom/scripts/idlsync.py
index 7307845..1439399 100755
--- a/tools/dom/scripts/idlsync.py
+++ b/tools/dom/scripts/idlsync.py
@@ -14,22 +14,75 @@
SCRIPT_PATH = os.path.abspath(os.path.dirname(__file__))
DART_PATH = os.path.abspath(os.path.join(SCRIPT_PATH, '..', '..', '..'))
-# Path to install latest IDL.
-IDL_PATH = os.path.join(DART_PATH, 'third_party', 'WebCore')
+# Dartium DEPS file with Chrome and WebKit revisions.
+DEPS = ('http://dart.googlecode.com/svn/branches/'
+ 'bleeding_edge/deps/dartium.deps/DEPS')
# Whitelist of files to keep.
WHITELIST = [
r'LICENSE(\S+)',
- r'(\S+)\.idl']
+ r'(\S+)\.idl',
+ r'(\S+)\.json',
+ r'(\S+)\.py',
+ ]
-# README file to generate.
-README = os.path.join(IDL_PATH, 'README')
-
-# SVN URL to latest Dartium version of WebKit.
-DEPS = 'http://dart.googlecode.com/svn/branches/bleeding_edge/deps/dartium.deps/DEPS'
-URL_PATTERN = r'"dartium_webkit_trunk": "(\S+)",'
-REV_PATTERN = r'"dartium_webkit_revision": "(\d+)",'
+# WebKit / WebCore info.
+WEBKIT_URL_PATTERN = r'"dartium_webkit_trunk": "(\S+)",'
+WEBKIT_REV_PATTERN = r'"dartium_webkit_revision": "(\d+)",'
WEBCORE_SUBPATH = 'Source/WebCore'
+LOCAL_WEBKIT_IDL_PATH = os.path.join(DART_PATH, 'third_party', 'WebCore')
+LOCAL_WEBKIT_README = os.path.join(LOCAL_WEBKIT_IDL_PATH, 'README')
+LOCAL_WEBKIT_README = """\
+This directory contains a copy of WebKit/WebCore IDL files.
+See the attached LICENSE-* files in this directory.
+
+Please do not modify the files here. They are periodically copied
+using the script: $DART_ROOT/sdk/lib/html/scripts/%(script)s
+
+The current version corresponds to:
+URL: %(url)s
+Current revision: %(revision)s
+"""
+
+# Chrome info.
+CHROME_URL_PATTERN = r'"chromium_url": "(\S+)",'
+CHROME_REV_PATTERN = r'"chromium_revision": "(\d+)",'
+CHROME_IDL_SUBPATH = 'trunk/src/chrome/common/extensions/api'
+CHROME_TOOLS_SUBPATH = 'trunk/src/tools/json_schema_compiler'
+LOCAL_CHROME_IDL_PATH = os.path.join(DART_PATH, 'third_party', 'chrome', 'idl')
+LOCAL_CHROME_TOOLS_PATH = os.path.join(DART_PATH, 'third_party', 'chrome',
+ 'tools')
+LOCAL_CHROME_README = """\
+This directory contains a copy of Chromium IDL and generation scripts
+used to generate Dart APIs for Chrome Apps.
+
+The original files are from:
+URL: %(url)s
+Current revision: %(revision)s
+
+Please see the corresponding LICENSE file at
+%(url)s/trunk/src/LICENSE.
+"""
+
+# Regular expressions corresponding to URL/revision patters in the
+# DEPS file.
+DEPS_PATTERNS = {
+ 'webkit': (WEBKIT_URL_PATTERN, WEBKIT_REV_PATTERN),
+ 'chrome': (CHROME_URL_PATTERN, CHROME_REV_PATTERN),
+ }
+
+# List of components to update.
+UPDATE_LIST = [
+ # (component, remote subpath, local path, local readme file)
+
+ # WebKit IDL.
+ ('webkit', WEBCORE_SUBPATH, LOCAL_WEBKIT_IDL_PATH, LOCAL_WEBKIT_README),
+ # Chrome IDL.
+ ('chrome', CHROME_IDL_SUBPATH, LOCAL_CHROME_IDL_PATH, LOCAL_CHROME_README),
+ # Chrome IDL compiler files.
+ ('chrome', CHROME_TOOLS_SUBPATH, LOCAL_CHROME_TOOLS_PATH,
+ LOCAL_CHROME_README),
+ ]
def RunCommand(cmd):
@@ -45,30 +98,40 @@
sys.exit(pipe.returncode)
-def GetWebkitSvnRevision():
+def GetDeps():
+ """Returns the DEPS file contents with pinned revision info."""
+ return RunCommand(['svn', 'cat', DEPS])
+
+
+def GetSvnRevision(deps, component):
"""Returns a tuple with the (dartium webkit repo, latest revision)."""
- deps = RunCommand(['svn', 'cat', DEPS])
- url = re.search(URL_PATTERN, deps).group(1)
- revision = re.search(REV_PATTERN, deps).group(1)
+ url_pattern, rev_pattern = DEPS_PATTERNS[component]
+ url = re.search(url_pattern, deps).group(1)
+ revision = re.search(rev_pattern, deps).group(1)
return (url, revision)
-def RefreshIDL(url, revision):
- """Refreshes the IDL to specific WebKit url / revision."""
+def RefreshIDL(url, revision, remote_path, local_path):
+ """Refreshes refreshes files in the local_path to specific url /
+ revision / remote_path."""
cwd = os.getcwd()
try:
- shutil.rmtree(IDL_PATH)
- os.chdir(os.path.dirname(IDL_PATH))
- RunCommand(['svn', 'export', '-r', revision, url + '/' + WEBCORE_SUBPATH])
+ if os.path.exists(local_path):
+ shutil.rmtree(local_path)
+ head, tail = os.path.split(local_path)
+ if not os.path.exists(head):
+ os.makedirs(head)
+ os.chdir(head)
+ RunCommand(['svn', 'export', '-r', revision, url + '/' + remote_path, tail])
finally:
os.chdir(cwd)
-def PruneExtraFiles():
+def PruneExtraFiles(local_path):
"""Removes all files that do not match the whitelist."""
pattern = re.compile(reduce(lambda x,y: '%s|%s' % (x,y),
map(lambda z: '(%s)' % z, WHITELIST)))
- for (root, dirs, files) in os.walk(IDL_PATH, topdown=False):
+ for (root, dirs, files) in os.walk(local_path, topdown=False):
for f in files:
if not pattern.match(f):
os.remove(os.path.join(root, f))
@@ -78,41 +141,48 @@
shutil.rmtree(dirpath)
-def ParseOptions():
- parser = optparse.OptionParser()
- parser.add_option('--revision', '-r', dest='revision',
- help='Revision to install', default=None)
- args, _ = parser.parse_args()
- return args.revision
-
-
-def GenerateReadme(url, revision):
- readme = """This directory contains a copy of WebKit/WebCore IDL files.
-See the attached LICENSE-* files in this directory.
-
-Please do not modify the files here. They are periodically copied
-using the script: $DART_ROOT/sdk/lib/html/scripts/%(script)s
-
-The current version corresponds to:
-URL: %(url)s
-Current revision: %(revision)s
-""" % {
+def GenerateReadme(local_path, template, url, revision):
+ readme = template % {
'script': os.path.basename(__file__),
'url': url,
'revision': revision }
- out = open(README, 'w')
+
+ readme_path = os.path.join(local_path, 'README')
+ out = open(readme_path, 'w')
out.write(readme)
out.close()
+def ParseOptions():
+ parser = optparse.OptionParser()
+ parser.add_option('--webkit-revision', '-w', dest='webkit_revision',
+ help='WebKit IDL revision to install', default=None)
+ parser.add_option('--chrome-revision', '-c', dest='chrome_revision',
+ help='Chrome IDL revision to install', default=None)
+ parser.add_option('--update', '-u', dest='update',
+ help='IDL to update (webkit | chrome | all)',
+ default='webkit')
+ args, _ = parser.parse_args()
+ update = {}
+ if args.update == 'all' or args.update == 'chrome':
+ update['chrome'] = args.chrome_revision
+ if args.update == 'all' or args.update == 'webkit':
+ update['webkit'] = args.webkit_revision
+ return update
+
+
def main():
- revision = ParseOptions()
- url, latest = GetWebkitSvnRevision()
- if not revision:
- revision = latest
- RefreshIDL(url, revision)
- PruneExtraFiles()
- GenerateReadme(url, revision)
+ deps = GetDeps()
+ update = ParseOptions()
+ for (component, remote_path, local_path, readme) in UPDATE_LIST:
+ if component in update.keys():
+ revision = update[component]
+ url, latest = GetSvnRevision(deps, component)
+ if revision is None:
+ revision = latest
+ RefreshIDL(url, revision, remote_path, local_path)
+ PruneExtraFiles(local_path)
+ GenerateReadme(local_path, readme, url, revision)
if __name__ == '__main__':
diff --git a/tools/dom/scripts/systemhtml.py b/tools/dom/scripts/systemhtml.py
index d1f4542..2594b1e 100644
--- a/tools/dom/scripts/systemhtml.py
+++ b/tools/dom/scripts/systemhtml.py
@@ -7,11 +7,12 @@
Dart:html APIs from the IDL database."""
import emitter
+import monitored
import os
from generator import *
from htmldartgenerator import *
-_js_custom_members = set([
+_js_custom_members = monitored.Set('systemhtml._js_custom_members', [
'ArrayBuffer.slice',
'AudioBufferSourceNode.start',
'AudioBufferSourceNode.stop',
@@ -66,12 +67,10 @@
'Window.location',
'Window.open',
'Window.requestAnimationFrame',
- 'Window.webkitCancelAnimationFrame',
- 'Window.webkitRequestAnimationFrame',
'WorkerContext.indexedDB',
])
-_js_custom_constructors = set([
+_js_custom_constructors = monitored.Set('systemhtml._js_custom_constructors', [
'AudioContext',
'Blob',
'MutationObserver',
@@ -118,7 +117,8 @@
info.pure_dart_constructor = True
return info
-_html_element_constructors = {
+_html_element_constructors = monitored.Dict(
+ 'systemhtml._html_element_constructors', {
'HTMLAnchorElement' :
ElementConstructorInfo(tag='a', opt_params=[('DOMString', 'href')]),
'HTMLAreaElement': 'area',
@@ -184,9 +184,10 @@
'HTMLTrackElement': 'track',
'HTMLUListElement': 'ul',
'HTMLVideoElement': 'video'
-}
+})
-_svg_element_constructors = {
+_svg_element_constructors = monitored.Dict(
+ 'systemhtml._svg_element_constructors', {
'SVGAElement': 'a',
'SVGAltGlyphElement': 'altGlyph',
'SVGAnimateElement': 'animate',
@@ -252,7 +253,7 @@
'SVGUseElement': 'use',
'SVGViewElement': 'view',
'SVGVKernElement': 'vkern',
-}
+})
_element_constructors = {
'html': _html_element_constructors,
@@ -517,13 +518,6 @@
self._backend.EmitSupportCheck()
- events_class_name = self._event_generator.ProcessInterface(
- self._interface, interface_name,
- self._backend.CustomJSMembers(),
- implementation_emitter)
- if events_class_name:
- self._backend.EmitEventGetter(events_class_name)
-
merged_interface = self._interface_type_info.merged_interface()
if merged_interface:
self._backend.AddMembers(self._database.GetInterface(merged_interface),
diff --git a/tools/dom/src/Isolates.dart b/tools/dom/src/Isolates.dart
index 3e4f507..467d998 100644
--- a/tools/dom/src/Isolates.dart
+++ b/tools/dom/src/Isolates.dart
@@ -99,12 +99,10 @@
// TODO(vsm): Set this up set once, on the first call.
var source = '$target-result';
var result = null;
- var listener = (Event e) {
+ window.on[source].first.then((Event e) {
result = json.parse(_getPortSyncEventData(e));
- };
- window.on[source].add(listener);
+ });
_dispatchEvent(target, [source, message]);
- window.on[source].remove(listener);
return result;
}
@@ -159,7 +157,7 @@
num _portId;
Function _callback;
- EventListener _listener;
+ StreamSubscription _portSubscription;
ReceivePortSync() {
if (_portIdCount == null) {
@@ -184,21 +182,20 @@
void receive(callback(var message)) {
_callback = callback;
- if (_listener == null) {
- _listener = (Event e) {
+ if (_portSubscription == null) {
+ _portSubscription = window.on[_listenerName].listen((Event e) {
var data = json.parse(_getPortSyncEventData(e));
var replyTo = data[0];
var message = _deserialize(data[1]);
var result = _callback(message);
_dispatchEvent(replyTo, _serialize(result));
- };
- window.on[_listenerName].add(_listener);
+ });
}
}
void close() {
_portMap.remove(_portId);
- if (_listener != null) window.on[_listenerName].remove(_listener);
+ if (_portSubscription != null) _portSubscription.cancel();
}
SendPortSync toSendPort() {
diff --git a/tools/dom/templates/html/dartium/html_dartium.darttemplate b/tools/dom/templates/html/dartium/html_dartium.darttemplate
index 3445f6b..825b6c8 100644
--- a/tools/dom/templates/html/dartium/html_dartium.darttemplate
+++ b/tools/dom/templates/html/dartium/html_dartium.darttemplate
@@ -75,9 +75,9 @@
_callPortSync(num id, var message) {
if (!_callPortInitialized) {
- window.on['js-result'].add((event) {
+ window.on['js-result'].listen((event) {
_callPortLastResult = json.parse(_getPortSyncEventData(event));
- }, false);
+ });
_callPortInitialized = true;
}
assert(_callPortLastResult == null);
diff --git a/tools/dom/templates/html/impl/impl_Element.darttemplate b/tools/dom/templates/html/impl/impl_Element.darttemplate
index 47f53c1..5499b22 100644
--- a/tools/dom/templates/html/impl/impl_Element.darttemplate
+++ b/tools/dom/templates/html/impl/impl_Element.darttemplate
@@ -775,6 +775,44 @@
$endif
var xtag;
+ /**
+ * Scrolls this element into view.
+ *
+ * Only one of of the alignment options may be specified at a time.
+ *
+ * If no options are specified then this will attempt to scroll the minimum
+ * amount needed to bring the element into view.
+ *
+ * Note that alignCenter is currently only supported on WebKit platforms. If
+ * alignCenter is specified but not supported then this will fall back to
+ * alignTop.
+ *
+ * See also:
+ *
+ * * [scrollIntoView](http://docs.webplatform.org/wiki/dom/methods/scrollIntoView)
+ * * [scrollIntoViewIfNeeded](http://docs.webplatform.org/wiki/dom/methods/scrollIntoViewIfNeeded)
+ */
+ void scrollIntoView([ScrollAlignment alignment]) {
+ var hasScrollIntoViewIfNeeded = false;
+$if DART2JS
+ hasScrollIntoViewIfNeeded =
+ JS('bool', '!!(#.scrollIntoViewIfNeeded)', this);
+$endif
+ if (alignment == ScrollAlignment.TOP) {
+ this.$dom_scrollIntoView(true);
+ } else if (alignment == ScrollAlignment.BOTTOM) {
+ this.$dom_scrollIntoView(false);
+ } else if (hasScrollIntoViewIfNeeded) {
+ if (alignment == ScrollAlignment.CENTER) {
+ this.$dom_scrollIntoViewIfNeeded(true);
+ } else {
+ this.$dom_scrollIntoViewIfNeeded();
+ }
+ } else {
+ this.$dom_scrollIntoView();
+ }
+ }
+
$if DART2JS
@DomName('Element.mouseWheelEvent')
static const EventStreamProvider<WheelEvent> mouseWheelEvent =
@@ -1064,3 +1102,20 @@
document.$dom_createElement(tag);
$endif
}
+
+
+/**
+ * Options for Element.scrollIntoView.
+ */
+class ScrollAlignment {
+ final _value;
+ const ScrollAlignment._internal(this._value);
+ toString() => 'ScrollAlignment.$_value';
+
+ /// Attempt to align the element to the top of the scrollable area.
+ static const TOP = const ScrollAlignment._internal('TOP');
+ /// Attempt to center the element in the scrollable area.
+ static const CENTER = const ScrollAlignment._internal('CENTER');
+ /// Attempt to align the element to the bottom of the scrollable area.
+ static const BOTTOM = const ScrollAlignment._internal('BOTTOM');
+}
diff --git a/tools/dom/templates/html/impl/impl_EventTarget.darttemplate b/tools/dom/templates/html/impl/impl_EventTarget.darttemplate
index e0ff57e..bce2318 100644
--- a/tools/dom/templates/html/impl/impl_EventTarget.darttemplate
+++ b/tools/dom/templates/html/impl/impl_EventTarget.darttemplate
@@ -7,15 +7,38 @@
/**
* Base class that supports listening for and dispatching browser events.
*
- * Events can either be accessed by string name (using the indexed getter) or by
- * getters exposed by subclasses. Use the getters exposed by subclasses when
- * possible for better compile-time type checks.
+ * Normally events are accessed via the Stream getter:
*
- * Using an indexed getter:
- * events['mouseover'].add((e) => print("Mouse over!"));
+ * element.onMouseOver.listen((e) => print('Mouse over!'));
*
- * Using a getter provided by a subclass:
- * elementEvents.mouseOver.add((e) => print("Mouse over!"));
+ * To access bubbling events which are declared on one element, but may bubble
+ * up to another element type (common for MediaElement events):
+ *
+ * MediaElement.pauseEvent.forTarget(document.body).listen(...);
+ *
+ * To useCapture on events:
+ *
+ * Element.keyDownEvent.forTarget(element, useCapture: true).listen(...);
+ *
+ * Custom events can be declared as:
+ *
+ * class DataGenerator {
+ * static EventStreamProvider<Event> dataEvent =
+ * new EventStreamProvider('data');
+ * }
+ *
+ * Then listeners should access the event with:
+ *
+ * DataGenerator.dataEvent.forTarget(element).listen(...);
+ *
+ * Custom events can also be accessed as:
+ *
+ * element.on['some_event'].listen(...);
+ *
+ * This approach is generally discouraged as it loses the event typing and
+ * some DOM events may have multiple platform-dependent event names under the
+ * covers. By using the standard Stream getters you will get the platform
+ * specific event name automatically.
*/
class Events {
/* Raw event target. */
@@ -23,59 +46,24 @@
Events(this._ptr);
- EventListenerList operator [](String type) {
- return new EventListenerList(_ptr, type);
- }
-}
-
-/**
- * Supports adding, removing, and dispatching events for a specific event type.
- */
-class EventListenerList {
-
- final EventTarget _ptr;
- final String _type;
-
- EventListenerList(this._ptr, this._type);
-
- // TODO(jacobr): implement equals.
-
- EventListenerList add(EventListener listener,
- [bool useCapture = false]) {
- _add(listener, useCapture);
- return this;
- }
-
- EventListenerList remove(EventListener listener,
- [bool useCapture = false]) {
- _remove(listener, useCapture);
- return this;
- }
-
- bool dispatch(Event evt) {
- return _ptr.dispatchEvent(evt);
- }
-
- void _add(EventListener listener, bool useCapture) {
- _ptr.$dom_addEventListener(_type, listener, useCapture);
- }
-
- void _remove(EventListener listener, bool useCapture) {
- _ptr.$dom_removeEventListener(_type, listener, useCapture);
+ Stream operator [](String type) {
+ return new _EventStream(_ptr, type, false);
}
}
/**
* Base class for all browser objects that support events.
*
- * Use the [on] property to add, remove, and dispatch events (rather than
- * [$dom_addEventListener], [$dom_dispatchEvent], and
- * [$dom_removeEventListener]) for compile-time type checks and a more concise
- * API.
+ * Use the [on] property to add, and remove events (rather than
+ * [$dom_addEventListener] and [$dom_removeEventListener]
+ * for compile-time type checks and a more concise API.
*/
$(ANNOTATIONS)class $CLASSNAME$EXTENDS$IMPLEMENTS$NATIVESPEC {
- @DomName('EventTarget.addEventListener, EventTarget.removeEventListener, EventTarget.dispatchEvent')
+ /**
+ * This is an ease-of-use accessor for event streams which should only be
+ * used when an explicit accessor is not available.
+ */
Events get on => new Events(this);
$!MEMBERS
}
diff --git a/tools/dom/templates/html/impl/impl_IDBObjectStore.darttemplate b/tools/dom/templates/html/impl/impl_IDBObjectStore.darttemplate
index b8ee68a..ec7d9b3 100644
--- a/tools/dom/templates/html/impl/impl_IDBObjectStore.darttemplate
+++ b/tools/dom/templates/html/impl/impl_IDBObjectStore.darttemplate
@@ -54,7 +54,7 @@
* the current transaction.
*/
@DomName('IDBObjectStore.openCursor')
- Stream<Cursor> openCursor({key, KeyRange range, String direction,
+ Stream<CursorWithValue> openCursor({key, KeyRange range, String direction,
bool autoAdvance}) {
var key_OR_range = null;
if (key != null) {
@@ -86,7 +86,7 @@
// TODO: need to guarantee that the controller provides the values
// immediately as waiting until the next tick will cause the transaction to
// close.
- var controller = new StreamController<Cursor>();
+ var controller = new StreamController();
request.onError.listen((e) {
//TODO: Report stacktrace once issue 4061 is resolved.
diff --git a/tools/gyp/configurations_make.gypi b/tools/gyp/configurations_make.gypi
index edbe56e..8a73b91 100644
--- a/tools/gyp/configurations_make.gypi
+++ b/tools/gyp/configurations_make.gypi
@@ -33,17 +33,17 @@
},
'Dart_ia32_Base': {
- 'cflags': [ '-m32', ],
+ 'cflags': [ '-m32', '-msse2' ],
'ldflags': [ '-m32', ],
},
'Dart_x64_Base': {
- 'cflags': [ '-m64', ],
+ 'cflags': [ '-m64', '-msse2' ],
'ldflags': [ '-m64', ],
},
'Dart_simarm_Base': {
- 'cflags': [ '-O3', '-m32', ],
+ 'cflags': [ '-O3', '-m32', '-msse2' ],
'ldflags': [ '-m32', ],
},
@@ -57,7 +57,7 @@
},
'Dart_simmips_Base': {
- 'cflags': [ '-O3', '-m32', ],
+ 'cflags': [ '-O3', '-m32', '-msse2' ],
'ldflags': [ '-m32', ],
},
diff --git a/tools/testing/dart/http_server.dart b/tools/testing/dart/http_server.dart
index 84a5b77..06b87da 100644
--- a/tools/testing/dart/http_server.dart
+++ b/tools/testing/dart/http_server.dart
@@ -6,6 +6,7 @@
import 'dart:io';
import 'dart:isolate';
+import 'dart:uri';
import 'test_suite.dart'; // For TestUtils.
// TODO(efortuna): Rewrite to not use the args library and simply take an
// expected number of arguments, so test.dart doesn't rely on the args library?
@@ -28,6 +29,8 @@
parser.addFlag('help', abbr: 'h', negatable: false,
help: 'Print this usage information.');
parser.addOption('package-root', help: 'The package root to use.');
+ parser.addOption('network', help: 'The network interface to use.',
+ defaultsTo: '127.0.0.1');
var args = parser.parse(new Options().arguments);
if (args['help']) {
print(parser.getUsage());
@@ -41,11 +44,12 @@
.canonicalize()
.toNativePath();
TestingServerRunner._packageRootDir = new Path(args['package-root']);
- TestingServerRunner.startHttpServer('127.0.0.1',
+ var network = args['network'];
+ TestingServerRunner.startHttpServer(network,
port: int.parse(args['port']));
print('Server listening on port '
'${TestingServerRunner.serverList[0].port}.');
- TestingServerRunner.startHttpServer('127.0.0.1',
+ TestingServerRunner.startHttpServer(network,
allowedPort: TestingServerRunner.serverList[0].port, port:
int.parse(args['crossOriginPort']));
print(
@@ -93,10 +97,14 @@
file.exists().then((exists) {
if (exists) {
if (allowedPort != -1) {
- // Allow loading from localhost:$allowedPort in browsers.
- resp.headers.set("Access-Control-Allow-Origin",
- "http://127.0.0.1:$allowedPort");
- resp.headers.set('Access-Control-Allow-Credentials', 'true');
+ if (request.headers.value('Origin') != null) {
+ var origin = new Uri(request.headers.value('Origin'));
+ // Allow loading from http://*:$allowedPort in browsers.
+ var allowedOrigin =
+ '${origin.scheme}://${origin.domain}:${allowedPort}';
+ resp.headers.set("Access-Control-Allow-Origin", allowedOrigin);
+ resp.headers.set('Access-Control-Allow-Credentials', 'true');
+ }
} else {
// No allowedPort specified. Allow from anywhere (but cross-origin
// requests *with credentials* will fail because you can't use "*").
@@ -111,16 +119,14 @@
}
file.openInputStream().pipe(resp.outputStream);
} else {
- resp.statusCode = HttpStatus.NOT_FOUND;
- try {
- resp.outputStream.close();
- } catch (e) {
- if (e is StreamException) {
- print('Test http_server error closing the response stream: $e');
+ var directory = new Directory.fromPath(path);
+ directory.exists().then((exists) {
+ if (!exists) {
+ sendNotFound(resp);
} else {
- throw e;
+ sendDirectoryListing(directory, request, resp);
}
- }
+ });
}
});
};
@@ -136,7 +142,84 @@
serverList.add(httpServer);
}
+ static void sendNotFound(HttpResponse response) {
+ response.statusCode = HttpStatus.NOT_FOUND;
+ try {
+ response.outputStream.close();
+ } catch (e) {
+ if (e is StreamException) {
+ print('Test http_server error closing the response stream: $e');
+ } else {
+ throw e;
+ }
+ }
+ }
+
+ /**
+ * Sends a simple listing of all the files and sub-directories within
+ * directory.
+ *
+ * This is intended to make it easier to browse tests when manually running
+ * tests against this test server.
+ */
+ static void sendDirectoryListing(Directory directory, HttpRequest request,
+ HttpResponse response) {
+ response.headers.set('Content-Type', 'text/html');
+ var header = '''<!DOCTYPE html>
+ <html>
+ <head>
+ <title>${request.path}</title>
+ </head>
+ <body>
+ <code>
+ <div>${request.path}</div>
+ <hr/>
+ <ul>''';
+ var footer = '''
+ </ul>
+ </code>
+ </body>
+ </html>''';
+
+ var entries = [];
+
+ directory.list()
+ ..onFile = (filepath) {
+ var filename = new Path(filepath).filename;
+ entries.add(new _Entry(filename, filename));
+ }
+ ..onDir = (dirpath) {
+ var filename = new Path(dirpath).filename;
+ entries.add(new _Entry(filename, '$filename/'));
+ }
+ ..onDone = (_) {
+ var requestPath = new Path.raw(request.path);
+ entries.sort();
+
+ response.outputStream.writeString(header);
+ for (var entry in entries) {
+ response.outputStream.writeString(
+ '<li><a href="${requestPath.append(entry.name)}">'
+ '${entry.displayName}</a></li>');
+ }
+ response.outputStream.writeString(footer);
+ response.outputStream.close();
+ };
+ }
+
static terminateHttpServers() {
for (var server in serverList) server.close();
}
}
+
+// Helper class for displaying directory listings.
+class _Entry {
+ final String name;
+ final String displayName;
+
+ _Entry(this.name, this.displayName);
+
+ int compareTo(_Entry other) {
+ return name.compareTo(other.name);
+ }
+}
diff --git a/utils/apidoc/apidoc.dart b/utils/apidoc/apidoc.dart
index 7cd8b7f..4caf0d5 100644
--- a/utils/apidoc/apidoc.dart
+++ b/utils/apidoc/apidoc.dart
@@ -274,7 +274,7 @@
includeMdnMemberComment(member), super.getMemberComment(member));
}
- doc.DocComment _mergeDocs(MdnComment mdnComment,
+ doc.DocComment _mergeDocs(doc.MdnComment mdnComment,
doc.DocComment fileComment) {
// Otherwise, prefer comment from the (possibly generated) Dart file.
if (fileComment != null) return fileComment;
@@ -321,11 +321,21 @@
}
}
+ doc.MdnComment lookupMdnComment(Mirror mirror) {
+ if (mirror is TypeMirror) {
+ return includeMdnTypeComment(mirror);
+ } else if (mirror is MemberMirror) {
+ return includeMdnMemberComment(mirror);
+ } else {
+ return null;
+ }
+ }
+
/**
* Gets the MDN-scraped docs for [type], or `null` if this type isn't
* scraped from MDN.
*/
- MdnComment includeMdnTypeComment(TypeMirror type) {
+ doc.MdnComment includeMdnTypeComment(TypeMirror type) {
if (_mdnTypeNamesToSkip.contains(type.simpleName)) {
print('Skipping MDN type ${type.simpleName}');
return null;
@@ -359,7 +369,7 @@
if (mdnType['summary'].trim().isEmpty) return null;
// Remember which MDN page we're using so we can attribute it.
- return new MdnComment(mdnType['summary'], mdnType['srcUrl']);
+ return new doc.MdnComment(mdnType['summary'], mdnType['srcUrl']);
}
/**
@@ -412,7 +422,7 @@
if (mdnMember['help'].trim().isEmpty) return null;
// Remember which MDN page we're using so we can attribute it.
- return new MdnComment(mdnMember['help'], mdnType['srcUrl']);
+ return new doc.MdnComment(mdnMember['help'], mdnType['srcUrl']);
}
/**
@@ -430,27 +440,3 @@
return a(memberUrl(member), memberName);
}
}
-
-class MdnComment implements doc.DocComment {
- final String mdnComment;
- final String mdnUrl;
-
- MdnComment(String this.mdnComment, String this.mdnUrl);
-
- String get text => mdnComment;
-
- ClassMirror get inheritedFrom => null;
-
- String get html {
- // Wrap the mdn comment so we can highlight it and so we handle MDN scraped
- // content that lacks a top-level block tag.
- return '''
- <div class="mdn">
- $mdnComment
- <div class="mdn-note"><a href="$mdnUrl">from MDN</a></div>
- </div>
- ''';
- }
-
- String toString() => mdnComment;
-}
diff --git a/utils/pub/command_lish.dart b/utils/pub/command_lish.dart
index d3a2cb4..f2e5f05 100644
--- a/utils/pub/command_lish.dart
+++ b/utils/pub/command_lish.dart
@@ -146,15 +146,15 @@
return listDir(rootDir, recursive: true).then((entries) {
return entries
.where(fileExists) // Skip directories.
- .map((entry) => relativeTo(entry, rootDir));
+ .map((entry) => path.relative(entry, from: rootDir));
});
}).then((files) => files.where(_shouldPublish).toList());
}
/// Returns `true` if [file] should be published.
bool _shouldPublish(String file) {
- if (_BLACKLISTED_FILES.contains(basename(file))) return false;
- return !splitPath(file).any(_BLACKLISTED_DIRS.contains);
+ if (_BLACKLISTED_FILES.contains(path.basename(file))) return false;
+ return !path.split(file).any(_BLACKLISTED_DIRS.contains);
}
/// Returns the value associated with [key] in [map]. Throws a user-friendly
diff --git a/utils/pub/entrypoint.dart b/utils/pub/entrypoint.dart
index 6d7ffe0..f778bbb 100644
--- a/utils/pub/entrypoint.dart
+++ b/utils/pub/entrypoint.dart
@@ -5,6 +5,9 @@
library entrypoint;
import 'dart:async';
+
+import '../../pkg/path/lib/path.dart' as path;
+
import 'io.dart';
import 'lock_file.dart';
import 'log.dart' as log;
@@ -49,8 +52,8 @@
cache = cache;
// TODO(rnystrom): Make this path configurable.
- /// The path to this "packages" directory.
- String get path => join(root.dir, 'packages');
+ /// The path to the entrypoint's "packages" directory.
+ String get packagesDir => join(root.dir, 'packages');
/// Ensures that the package identified by [id] is installed to the directory.
/// Returns the resolved [PackageId].
@@ -67,9 +70,9 @@
var pendingOrCompleted = _installs[id];
if (pendingOrCompleted != null) return pendingOrCompleted;
- var packageDir = join(path, id.name);
+ var packageDir = join(packagesDir, id.name);
var future = defer(() {
- ensureDir(dirname(packageDir));
+ ensureDir(path.dirname(packageDir));
if (!dirExists(packageDir)) return;
// TODO(nweiz): figure out when to actually delete the directory, and when
@@ -127,7 +130,7 @@
/// Removes the old packages directory, installs all dependencies listed in
/// [packageVersions], and writes a [LockFile].
Future _installDependencies(List<PackageId> packageVersions) {
- return cleanDir(path).then((_) {
+ return cleanDir(packagesDir).then((_) {
return Future.wait(packageVersions.map((id) {
if (id.isRoot) return new Future.immediate(id);
return install(id);
@@ -224,10 +227,10 @@
/// allow a package to import its own files using `package:`.
Future _installSelfReference(_) {
return defer(() {
- var linkPath = join(path, root.name);
+ var linkPath = join(packagesDir, root.name);
// Create the symlink if it doesn't exist.
if (entryExists(linkPath)) return;
- ensureDir(path);
+ ensureDir(packagesDir);
return createPackageSymlink(root.name, root.dir, linkPath,
isSelfLink: true);
});
@@ -275,7 +278,7 @@
Future<List<String>> _listDirWithoutPackages(dir) {
return listDir(dir).then((files) {
return Future.wait(files.map((file) {
- if (basename(file) == 'packages') return new Future.immediate([]);
+ if (path.basename(file) == 'packages') return new Future.immediate([]);
return defer(() {
if (!dirExists(file)) return [];
return _listDirWithoutPackages(file);
@@ -293,7 +296,7 @@
return defer(() {
var to = join(dir, 'packages');
if (entryExists(to)) return;
- return createSymlink(path, to);
+ return createSymlink(packagesDir, to);
});
}
}
diff --git a/utils/pub/io.dart b/utils/pub/io.dart
index 0eab87a..c439384 100644
--- a/utils/pub/io.dart
+++ b/utils/pub/io.dart
@@ -33,27 +33,13 @@
parts[6], parts[7]);
}
-/// Gets the basename, the file name without any leading directory path, for
-/// [file], which can either be a [String], [File], or [Directory].
-String basename(file) => path.basename(_getPath(file));
-
-/// Gets the the leading directory path for [file], which can either be a
-/// [String], [File], or [Directory].
-String dirname(file) => path.dirname(_getPath(file));
-
-/// Splits [entry] into its individual components.
-List<String> splitPath(entry) => path.split(_getPath(entry));
-
/// Returns whether or not [entry] is nested somewhere within [dir]. This just
/// performs a path comparison; it doesn't look at the actual filesystem.
-bool isBeneath(entry, dir) {
- var relative = relativeTo(entry, dir);
- return !path.isAbsolute(relative) && splitPath(relative)[0] != '..';
+bool isBeneath(String entry, String dir) {
+ var relative = path.relative(entry, from: dir);
+ return !path.isAbsolute(relative) && path.split(relative)[0] != '..';
}
-/// Returns the path to [target] from [base].
-String relativeTo(target, base) => path.relative(target, from: base);
-
/// Determines if [path], which can be a [String] file path, a [File], or a
/// [Directory] exists on the file system.
bool entryExists(path) => fileExists(path) || dirExists(path);
@@ -93,8 +79,7 @@
return file..writeAsStringSync(contents);
}
-/// Deletes [file], which can be a [String] or a [File]. Returns a [Future]
-/// that completes when the deletion is done.
+/// Deletes [file], which can be a [String] or a [File].
File deleteFile(file) => _getFile(file)..delete();
/// Creates [file] (which can either be a [String] or a [File]), and writes
@@ -128,16 +113,16 @@
/// Creates a directory [dir].
Directory createDir(dir) => _getDirectory(dir)..createSync();
-/// Ensures that [path] and all its parent directories exist. If they don't
+/// Ensures that [dirPath] and all its parent directories exist. If they don't
/// exist, creates them.
-Directory ensureDir(path) {
- path = _getPath(path);
+Directory ensureDir(dirPath) {
+ dirPath = _getPath(dirPath);
- log.fine("Ensuring directory $path exists.");
- var dir = new Directory(path);
- if (path == '.' || dirExists(path)) return dir;
+ log.fine("Ensuring directory $dirPath exists.");
+ var dir = new Directory(dirPath);
+ if (dirPath == '.' || dirExists(dirPath)) return dir;
- ensureDir(dirname(path));
+ ensureDir(path.dirname(dirPath));
try {
createDir(dir);
@@ -155,12 +140,12 @@
/// Creates a temp directory whose name will be based on [dir] with a unique
/// 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.
-Directory createTempDir([dir = '']) {
+/// created in a platform-dependent temporary location. Returns the path of the
+/// created directory.
+String createTempDir([dir = '']) {
var tempDir = _getDirectory(dir).createTempSync();
log.io("Created temp directory ${tempDir.path}");
- return tempDir;
+ return tempDir.path;
}
/// Asynchronously recursively deletes [dir], which can be a [String] or a
@@ -218,8 +203,8 @@
var children = [];
lister.onError = (error) => completer.completeError(error, stackTrace);
lister.onDir = (file) {
- if (!includeHiddenFiles && basename(file).startsWith('.')) return;
- file = join(dir, basename(file));
+ if (!includeHiddenFiles && path.basename(file).startsWith('.')) return;
+ file = join(dir, path.basename(file));
contents.add(file);
// TODO(nweiz): don't manually recurse once issue 7358 is fixed. Note that
// once we remove the manual recursion, we'll need to explicitly filter
@@ -230,8 +215,8 @@
};
lister.onFile = (file) {
- if (!includeHiddenFiles && basename(file).startsWith('.')) return;
- contents.add(join(dir, basename(file)));
+ if (!includeHiddenFiles && path.basename(file).startsWith('.')) return;
+ contents.add(join(dir, path.basename(file)));
};
return completer.future.then((contents) {
@@ -315,7 +300,7 @@
from = _getPath(from);
to = _getPath(to);
- log.fine("Create symlink $from -> $to.");
+ log.fine("Creating symlink ($to is a symlink to $from)");
var command = 'ln';
var args = ['-s', from, to];
@@ -361,13 +346,6 @@
});
}
-/// Given [entry] which may be a [String], [File], or [Directory] relative to
-/// the current working directory, returns its full canonicalized path.
-String getFullPath(entry) => path.absolute(_getPath(entry));
-
-/// Returns whether or not [entry] is an absolute path.
-bool isAbsolute(entry) => path.isAbsolute(_getPath(entry));
-
/// Resolves [target] relative to the location of pub.dart.
String relativeToPub(String target) {
var scriptPath = new File(new Options().script).fullPathSync();
@@ -375,10 +353,11 @@
// Walk up until we hit the "util(s)" directory. This lets us figure out where
// we are if this function is called from pub.dart, or one of the tests,
// which also live under "utils", or from the SDK where pub is in "util".
- var utilDir = dirname(scriptPath);
- while (basename(utilDir) != 'utils' && basename(utilDir) != 'util') {
- if (basename(utilDir) == '') throw 'Could not find path to pub.';
- utilDir = dirname(utilDir);
+ var utilDir = path.dirname(scriptPath);
+ while (path.basename(utilDir) != 'utils' &&
+ path.basename(utilDir) != 'util') {
+ if (path.basename(utilDir) == '') throw 'Could not find path to pub.';
+ utilDir = path.dirname(utilDir);
}
return path.normalize(join(utilDir, 'pub', target));
@@ -728,7 +707,7 @@
Future withTempDir(Future fn(String path)) {
return defer(() {
var tempDir = createTempDir();
- return fn(tempDir.path).whenComplete(() {
+ return fn(tempDir).whenComplete(() {
return deleteDir(tempDir);
});
});
@@ -835,13 +814,13 @@
var controller = new StreamController<List<int>>();
if (baseDir == null) baseDir = path.current;
- baseDir = getFullPath(baseDir);
+ baseDir = path.absolute(baseDir);
contents = contents.map((entry) {
- entry = getFullPath(entry);
+ entry = path.absolute(_getPath(entry));
if (!isBeneath(entry, baseDir)) {
throw 'Entry $entry is not inside $baseDir.';
}
- return relativeTo(entry, baseDir);
+ return path.relative(entry, from: baseDir);
}).toList();
if (Platform.operatingSystem != "windows") {
diff --git a/utils/pub/oauth2.dart b/utils/pub/oauth2.dart
index 9711452..3ea33cc 100644
--- a/utils/pub/oauth2.dart
+++ b/utils/pub/oauth2.dart
@@ -10,6 +10,8 @@
// TODO(nweiz): Make this a "package:" URL, or something nicer than this.
import '../../pkg/oauth2/lib/oauth2.dart';
+import '../../pkg/path/lib/path.dart' as path;
+
import 'http.dart';
import 'io.dart';
import 'log.dart' as log;
@@ -138,9 +140,9 @@
void _saveCredentials(SystemCache cache, Credentials credentials) {
log.fine('Saving OAuth2 credentials.');
_credentials = credentials;
- var path = _credentialsFile(cache);
- ensureDir(dirname(path));
- writeTextFile(path, credentials.toJson(), dontLogContents: true);
+ var credentialsPath = _credentialsFile(cache);
+ ensureDir(path.dirname(credentialsPath));
+ writeTextFile(credentialsPath, credentials.toJson(), dontLogContents: true);
}
/// The path to the file in which the user's OAuth2 credentials are stored.
diff --git a/utils/pub/package.dart b/utils/pub/package.dart
index 5485b65..dd988cb 100644
--- a/utils/pub/package.dart
+++ b/utils/pub/package.dart
@@ -5,6 +5,9 @@
library package;
import 'dart:async';
+
+import '../../pkg/path/lib/path.dart' as path;
+
import 'io.dart';
import 'pubspec.dart';
import 'source.dart';
@@ -21,7 +24,7 @@
/// The name of the package.
String get name {
if (pubspec.name != null) return pubspec.name;
- if (dir != null) return basename(dir);
+ if (dir != null) return path.basename(dir);
return null;
}
diff --git a/utils/pub/path_source.dart b/utils/pub/path_source.dart
new file mode 100644
index 0000000..123a308
--- /dev/null
+++ b/utils/pub/path_source.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.
+
+library path_source;
+
+import 'dart:async';
+import 'dart:io';
+
+import '../../pkg/path/lib/path.dart' as path;
+
+import 'io.dart';
+import 'package.dart';
+import 'pubspec.dart';
+import 'version.dart';
+import 'source.dart';
+import 'utils.dart';
+
+// TODO(rnystrom): Support relative paths. (See comment in _validatePath().)
+/// A package [Source] that installs packages from a given local file path.
+class PathSource extends Source {
+ final name = 'path';
+ final shouldCache = false;
+
+ Future<Pubspec> describe(PackageId id) {
+ return defer(() {
+ _validatePath(id.name, id.description);
+ return new Pubspec.load(id.name, id.description, systemCache.sources);
+ });
+ }
+
+ Future<bool> install(PackageId id, String path) {
+ return defer(() {
+ try {
+ _validatePath(id.name, id.description);
+ } on FormatException catch(err) {
+ return false;
+ }
+ return createPackageSymlink(id.name, id.description, path);
+ }).then((_) => true);
+ }
+
+ void validateDescription(description, {bool fromLockFile: false}) {
+ if (description is! String) {
+ throw new FormatException("The description must be a path string.");
+ }
+ }
+
+ /// Ensures that [dir] is a valid path. It must be an absolute path that
+ /// points to an existing directory. Throws a [FormatException] if the path
+ /// is invalid.
+ void _validatePath(String name, String dir) {
+ // Relative paths are not (currently) allowed because the user would expect
+ // them to be relative to the pubspec where the dependency appears. That in
+ // turn means that two pubspecs in different locations with the same
+ // relative path dependency could refer to two different packages. That
+ // violates pub's rule that a description should uniquely identify a
+ // package.
+ //
+ // At some point, we may want to loosen this, but it will mean tracking
+ // where a given PackageId appeared.
+ if (!path.isAbsolute(dir)) {
+ throw new FormatException(
+ "Path dependency for package '$name' must be an absolute path. "
+ "Was '$dir'.");
+ }
+
+ if (fileExists(dir)) {
+ throw new FormatException(
+ "Path dependency for package '$name' must refer to a "
+ "directory, not a file. Was '$dir'.");
+ }
+
+ if (!dirExists(dir)) {
+ throw new FormatException("Could not find package '$name' at '$dir'.");
+ }
+ }
+}
\ No newline at end of file
diff --git a/utils/pub/pub.dart b/utils/pub/pub.dart
index 302420f..a837163 100644
--- a/utils/pub/pub.dart
+++ b/utils/pub/pub.dart
@@ -235,12 +235,19 @@
handleError(error, trace) {
// This is basically the top-level exception handler so that we don't
// spew a stack trace on our users.
- var message = error.toString();
+ var message;
- // TODO(rnystrom): The default exception implementation class puts
- // "Exception:" in the output, so strip that off.
- if (message.startsWith("Exception: ")) {
- message = message.substring("Exception: ".length);
+ try {
+ // Most exception types have a "message" property. We prefer this since
+ // it skips the "Exception:", "HttpException:", etc. prefix that calling
+ // toString() adds. But, alas, "message" isn't actually defined in the
+ // base Exception type so there's no easy way to know if it's available
+ // short of a giant pile of type tests for each known exception type.
+ //
+ // So just try it. If it throws, default to toString().
+ message = error.message;
+ } on NoSuchMethodError catch (_) {
+ message = error.toString();
}
log.error(message);
@@ -271,7 +278,7 @@
'${path.current}.';
} else if (e is PubspecHasNoNameException && e.name == null) {
e = 'pubspec.yaml is missing the required "name" field (e.g. "name: '
- '${basename(path.current)}").';
+ '${path.basename(path.current)}").';
}
handleError(e, asyncError.stackTrace);
diff --git a/utils/pub/source.dart b/utils/pub/source.dart
index 777c1a0..30fd5eb 100644
--- a/utils/pub/source.dart
+++ b/utils/pub/source.dart
@@ -5,6 +5,9 @@
library source;
import 'dart:async';
+
+import '../../pkg/path/lib/path.dart' as path;
+
import 'io.dart';
import 'package.dart';
import 'pubspec.dart';
@@ -105,15 +108,51 @@
///
/// By default, this uses [systemCacheDirectory] and [install].
Future<Package> installToSystemCache(PackageId id) {
- var path;
+ var packageDir;
return systemCacheDirectory(id).then((p) {
- path = p;
- if (dirExists(path)) return true;
- ensureDir(dirname(path));
- return install(id, path);
+ packageDir = p;
+
+ // See if it's already cached.
+ if (!dirExists(packageDir)) return false;
+
+ return _isCachedPackageCorrupted(packageDir).then((isCorrupted) {
+ if (!isCorrupted) return true;
+
+ // Busted, so wipe out the package and reinstall.
+ return deleteDir(packageDir).then((_) => false);
+ });
+ }).then((isInstalled) {
+ if (isInstalled) return true;
+ ensureDir(path.dirname(packageDir));
+ return install(id, packageDir);
}).then((found) {
if (!found) throw 'Package $id not found.';
- return new Package.load(id.name, path, systemCache.sources);
+ return new Package.load(id.name, packageDir, systemCache.sources);
+ });
+ }
+
+ /// Since pub generates symlinks that point into the system cache (in
+ /// particular, targeting the "lib" directories of cached packages), it's
+ /// possible to accidentally break cached packages if something traverses
+ /// that symlink.
+ ///
+ /// This tries to determine if the cached package at [packageDir] has been
+ /// corrupted. The heuristics are it is corrupted if any of the following are
+ /// true:
+ ///
+ /// * It has an empty "lib" directory.
+ /// * It has no pubspec.
+ Future<bool> _isCachedPackageCorrupted(String packageDir) {
+ return defer(() {
+ if (!fileExists(join(packageDir, "pubspec.yaml"))) return true;
+
+ var libDir = join(packageDir, "lib");
+ if (dirExists(libDir)) {
+ return listDir(libDir).then((contents) => contents.length == 0);
+ }
+
+ // If we got here, it's OK.
+ return false;
});
}
diff --git a/utils/pub/system_cache.dart b/utils/pub/system_cache.dart
index 13e6b8d..377ac17 100644
--- a/utils/pub/system_cache.dart
+++ b/utils/pub/system_cache.dart
@@ -13,6 +13,7 @@
import 'io.dart' as io show createTempDir;
import 'log.dart' as log;
import 'package.dart';
+import 'path_source.dart';
import 'pubspec.dart';
import 'sdk_source.dart';
import 'source.dart';
@@ -46,9 +47,10 @@
/// Creates a system cache and registers the standard set of sources.
factory SystemCache.withSources(String rootDir) {
var cache = new SystemCache(rootDir);
- cache.register(new SdkSource());
cache.register(new GitSource());
cache.register(new HostedSource());
+ cache.register(new PathSource());
+ cache.register(new SdkSource());
cache.sources.setDefault('hosted');
return cache;
}
@@ -101,7 +103,7 @@
/// 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.
- Directory createTempDir() {
+ String createTempDir() {
var temp = ensureDir(tempDir);
return io.createTempDir(join(temp, 'dir'));
}
diff --git a/utils/pub/validator/compiled_dartdoc.dart b/utils/pub/validator/compiled_dartdoc.dart
index e5a7353..20f69be 100644
--- a/utils/pub/validator/compiled_dartdoc.dart
+++ b/utils/pub/validator/compiled_dartdoc.dart
@@ -22,8 +22,8 @@
Future validate() {
return listDir(entrypoint.root.dir, recursive: true).then((entries) {
for (var entry in entries) {
- if (basename(entry) != "nav.json") return false;
- var dir = dirname(entry);
+ if (path.basename(entry) != "nav.json") return false;
+ var dir = path.dirname(entry);
// Look for tell-tale Dartdoc output files all in the same directory.
var files = [
diff --git a/utils/pub/validator/dependency.dart b/utils/pub/validator/dependency.dart
index a848c54..de02738 100644
--- a/utils/pub/validator/dependency.dart
+++ b/utils/pub/validator/dependency.dart
@@ -10,6 +10,7 @@
import '../hosted_source.dart';
import '../http.dart';
import '../package.dart';
+import '../path_source.dart';
import '../utils.dart';
import '../validator.dart';
import '../version.dart';
@@ -62,7 +63,13 @@
}
}
- warnings.add('Don\'t depend on "${ref.name}" from the ${ref.source.name} '
+ // Path sources are errors. Other sources are just warnings.
+ var messages = warnings;
+ if (ref.source is PathSource) {
+ messages = errors;
+ }
+
+ messages.add('Don\'t depend on "${ref.name}" from the ${ref.source.name} '
'source. Use the hosted source instead. For example:\n'
'\n'
'dependencies:\n'
diff --git a/utils/pub/validator/directory.dart b/utils/pub/validator/directory.dart
index 6ab932c..1d1c2b8 100644
--- a/utils/pub/validator/directory.dart
+++ b/utils/pub/validator/directory.dart
@@ -6,6 +6,8 @@
import 'dart:async';
+import '../../../pkg/path/lib/path.dart' as path;
+
import '../entrypoint.dart';
import '../io.dart';
import '../utils.dart';
@@ -23,7 +25,7 @@
for (var dir in dirs) {
if (!dirExists(dir)) continue;
- dir = basename(dir);
+ dir = path.basename(dir);
if (_PLURAL_NAMES.contains(dir)) {
// Cut off the "s"
var singularName = dir.substring(0, dir.length - 1);
diff --git a/utils/pub/validator/lib.dart b/utils/pub/validator/lib.dart
index 7346223e..c72d309 100644
--- a/utils/pub/validator/lib.dart
+++ b/utils/pub/validator/lib.dart
@@ -7,6 +7,8 @@
import 'dart:async';
import 'dart:io';
+import '../../../pkg/path/lib/path.dart' as path;
+
import '../entrypoint.dart';
import '../io.dart';
import '../system_cache.dart';
@@ -31,7 +33,7 @@
}
return listDir(libDir).then((files) {
- files = files.map((file) => relativeTo(file, libDir)).toList();
+ files = files.map((file) => path.relative(file, from: libDir)).toList();
if (files.isEmpty) {
errors.add('You must have a non-empty "lib" directory.\n'
"Without that, users cannot import any code from your package.");
diff --git a/utils/pub/validator/license.dart b/utils/pub/validator/license.dart
index 8c32548..63b9aa8 100644
--- a/utils/pub/validator/license.dart
+++ b/utils/pub/validator/license.dart
@@ -6,6 +6,8 @@
import 'dart:async';
+import '../../../pkg/path/lib/path.dart' as path;
+
import '../entrypoint.dart';
import '../io.dart';
import '../system_cache.dart';
@@ -20,7 +22,7 @@
return listDir(entrypoint.root.dir).then((files) {
var licenseLike = new RegExp(
r"^([a-zA-Z0-9]+[-_])?(LICENSE|COPYING)(\..*)?$");
- if (files.map(basename).any(licenseLike.hasMatch)) return;
+ if (files.map(path.basename).any(licenseLike.hasMatch)) return;
errors.add(
"You must have a COPYING or LICENSE file in the root directory.\n"
diff --git a/utils/pub/validator/name.dart b/utils/pub/validator/name.dart
index 0386089..6a8cd91 100644
--- a/utils/pub/validator/name.dart
+++ b/utils/pub/validator/name.dart
@@ -8,6 +8,7 @@
import 'dart:io';
import '../../../pkg/path/lib/path.dart' as path;
+
import '../entrypoint.dart';
import '../io.dart';
import '../utils.dart';
@@ -53,8 +54,8 @@
return listDir(libDir, recursive: true);
}).then((files) {
return files
- .map((file) => relativeTo(file, dirname(libDir)))
- .where((file) => !splitPath(file).contains("src") &&
+ .map((file) => path.relative(file, from: path.dirname(libDir)))
+ .where((file) => !path.split(file).contains("src") &&
path.extension(file) == '.dart')
.toList();
});
diff --git a/utils/tests/pub/install/hosted/repair_cache_test.dart b/utils/tests/pub/install/hosted/repair_cache_test.dart
new file mode 100644
index 0000000..8f2f79f
--- /dev/null
+++ b/utils/tests/pub/install/hosted/repair_cache_test.dart
@@ -0,0 +1,64 @@
+// 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 pub_tests;
+
+import '../../../../../pkg/path/lib/path.dart' as path;
+
+import '../../../../pub/io.dart';
+import '../../test_pub.dart';
+
+main() {
+ initConfig();
+ integration('re-installs a package if it has an empty "lib" directory', () {
+
+ servePackages([package("foo", "1.2.3")]);
+
+ // Set up a cache with a broken foo package.
+ dir(cachePath, [
+ dir('hosted', [
+ async(port.then((p) => dir('localhost%58$p', [
+ dir("foo-1.2.3", [
+ libPubspec("foo", "1.2.3"),
+ // Note: empty "lib" directory.
+ dir("lib", [])
+ ])
+ ])))
+ ])
+ ]).scheduleCreate();
+
+ appDir([dependency("foo", "1.2.3")]).scheduleCreate();
+
+ schedulePub(args: ['install'],
+ output: new RegExp("Dependencies installed!\$"));
+
+ cacheDir({"foo": "1.2.3"}).scheduleValidate();
+ packagesDir({"foo": "1.2.3"}).scheduleValidate();
+ });
+
+ integration('re-installs a package if it has no pubspec', () {
+
+ servePackages([package("foo", "1.2.3")]);
+
+ // Set up a cache with a broken foo package.
+ dir(cachePath, [
+ dir('hosted', [
+ async(port.then((p) => dir('localhost%58$p', [
+ dir("foo-1.2.3", [
+ libDir("foo")
+ // Note: no pubspec.
+ ])
+ ])))
+ ])
+ ]).scheduleCreate();
+
+ appDir([dependency("foo", "1.2.3")]).scheduleCreate();
+
+ schedulePub(args: ['install'],
+ output: new RegExp("Dependencies installed!\$"));
+
+ cacheDir({"foo": "1.2.3"}).scheduleValidate();
+ packagesDir({"foo": "1.2.3"}).scheduleValidate();
+ });
+}
diff --git a/utils/tests/pub/install/path/absolute_path_test.dart b/utils/tests/pub/install/path/absolute_path_test.dart
new file mode 100644
index 0000000..cef0a76
--- /dev/null
+++ b/utils/tests/pub/install/path/absolute_path_test.dart
@@ -0,0 +1,46 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import '../../../../../pkg/path/lib/path.dart' as path;
+
+import '../../test_pub.dart';
+
+main() {
+ initConfig();
+ integration('path dependency with absolute path', () {
+ dir('foo', [
+ libDir('foo'),
+ libPubspec('foo', '0.0.1')
+ ]).scheduleCreate();
+
+ dir(appPath, [
+ pubspec({
+ "name": "myapp",
+ "dependencies": {
+ "foo": {"path": path.join(sandboxDir, "foo")}
+ }
+ })
+ ]).scheduleCreate();
+
+ schedulePub(args: ["install"],
+ output: new RegExp(r"Dependencies installed!$"));
+
+ dir(packagesPath, [
+ dir("foo", [
+ file("foo.dart", 'main() => "foo";')
+ ])
+ ]).scheduleValidate();
+
+ // Move the packages directory and ensure the symlink still works. That
+ // will validate that we actually created an absolute symlink.
+ dir("moved").scheduleCreate();
+ scheduleRename(packagesPath, "moved/packages");
+
+ dir("moved/packages", [
+ dir("foo", [
+ file("foo.dart", 'main() => "foo";')
+ ])
+ ]).scheduleValidate();
+ });
+}
\ No newline at end of file
diff --git a/utils/tests/pub/install/path/no_pubspec_test.dart b/utils/tests/pub/install/path/no_pubspec_test.dart
new file mode 100644
index 0000000..92f54fd
--- /dev/null
+++ b/utils/tests/pub/install/path/no_pubspec_test.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import '../../../../../pkg/path/lib/path.dart' as path;
+
+import '../../test_pub.dart';
+
+main() {
+ initConfig();
+ integration('path dependency to non-package directory', () {
+ // Make an empty directory.
+ dir('foo').scheduleCreate();
+ var fooPath = path.join(sandboxDir, "foo");
+
+ dir(appPath, [
+ pubspec({
+ "name": "myapp",
+ "dependencies": {
+ "foo": {"path": fooPath}
+ }
+ })
+ ]).scheduleCreate();
+
+ schedulePub(args: ['install'],
+ error: new RegExp('Package "foo" doesn\'t have a pubspec.yaml file.'),
+ exitCode: 1);
+ });
+}
\ No newline at end of file
diff --git a/utils/tests/pub/install/path/nonexistent_dir_test.dart b/utils/tests/pub/install/path/nonexistent_dir_test.dart
new file mode 100644
index 0000000..4a129f4
--- /dev/null
+++ b/utils/tests/pub/install/path/nonexistent_dir_test.dart
@@ -0,0 +1,37 @@
+// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:io';
+
+import '../../../../../pkg/path/lib/path.dart' as path;
+
+import '../../../../pub/exit_codes.dart' as exit_codes;
+import '../../test_pub.dart';
+
+main() {
+ initConfig();
+ integration('path dependency to non-existent directory', () {
+ var badPath = path.join(sandboxDir, "bad_path");
+
+ dir(appPath, [
+ pubspec({
+ "name": "myapp",
+ "dependencies": {
+ "foo": {"path": badPath}
+ }
+ })
+ ]).scheduleCreate();
+
+ // TODO(rnystrom): The "\" in a Windows path gets treated like a regex
+ // character, so hack escape. A better fix is to use a literal string
+ // instead of a RegExp to validate, but that requires us to move the
+ // stack traces out of the stderr when we invoke pub. See also: #4706.
+ var escapePath = badPath.replaceAll(r"\", r"\\");
+
+ schedulePub(args: ['install'],
+ error:
+ new RegExp("Could not find package 'foo' at '$escapePath'."),
+ exitCode: exit_codes.DATA);
+ });
+}
\ No newline at end of file
diff --git a/utils/tests/pub/install/path/path_is_file_test.dart b/utils/tests/pub/install/path/path_is_file_test.dart
new file mode 100644
index 0000000..8717b49
--- /dev/null
+++ b/utils/tests/pub/install/path/path_is_file_test.dart
@@ -0,0 +1,41 @@
+// 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 '../../../../../pkg/path/lib/path.dart' as path;
+
+import '../../../../pub/exit_codes.dart' as exit_codes;
+import '../../test_pub.dart';
+
+main() {
+ initConfig();
+ integration('path dependency when path is a file', () {
+ dir('foo', [
+ libDir('foo'),
+ libPubspec('foo', '0.0.1')
+ ]).scheduleCreate();
+
+ file('dummy.txt', '').scheduleCreate();
+ var dummyPath = path.join(sandboxDir, 'dummy.txt');
+
+ dir(appPath, [
+ pubspec({
+ "name": "myapp",
+ "dependencies": {
+ "foo": {"path": dummyPath}
+ }
+ })
+ ]).scheduleCreate();
+
+ // TODO(rnystrom): The "\" in a Windows path gets treated like a regex
+ // character, so hack escape. A better fix is to use a literal string
+ // instead of a RegExp to validate, but that requires us to move the
+ // stack traces out of the stderr when we invoke pub. See also: #4706.
+ var escapePath = dummyPath.replaceAll(r"\", r"\\");
+
+ schedulePub(args: ['install'],
+ error: new RegExp("Path dependency for package 'foo' must refer to a "
+ "directory, not a file. Was '$escapePath'."),
+ exitCode: exit_codes.DATA);
+ });
+}
\ No newline at end of file
diff --git a/utils/tests/pub/install/path/relative_path_test.dart b/utils/tests/pub/install/path/relative_path_test.dart
new file mode 100644
index 0000000..56fe28a
--- /dev/null
+++ b/utils/tests/pub/install/path/relative_path_test.dart
@@ -0,0 +1,25 @@
+// 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 '../../../../pub/exit_codes.dart' as exit_codes;
+import '../../test_pub.dart';
+
+main() {
+ initConfig();
+ integration('path dependencies cannot use relative paths', () {
+ dir(appPath, [
+ pubspec({
+ "name": "myapp",
+ "dependencies": {
+ "foo": {"path": "../foo"}
+ }
+ })
+ ]).scheduleCreate();
+
+ schedulePub(args: ['install'],
+ error: new RegExp("Path dependency for package 'foo' must be an "
+ "absolute path. Was '../foo'."),
+ exitCode: exit_codes.DATA);
+ });
+}
\ No newline at end of file
diff --git a/utils/tests/pub/pub.status b/utils/tests/pub/pub.status
index 2605568..254abd7 100644
--- a/utils/tests/pub/pub.status
+++ b/utils/tests/pub/pub.status
@@ -15,4 +15,4 @@
*: Skip
[ $system == windows ]
-io_test: Timeout # Issue 7505
+io_test: Fail # Issue 7505
diff --git a/utils/tests/pub/test_pub.dart b/utils/tests/pub/test_pub.dart
index b84a7aa..cae3a80 100644
--- a/utils/tests/pub/test_pub.dart
+++ b/utils/tests/pub/test_pub.dart
@@ -31,6 +31,7 @@
import '../../pub/hosted_source.dart';
import '../../pub/http.dart';
import '../../pub/io.dart';
+import '../../pub/path_source.dart';
import '../../pub/sdk_source.dart';
import '../../pub/system_cache.dart';
import '../../pub/utils.dart';
@@ -404,6 +405,9 @@
case "hosted":
source = new HostedSource();
break;
+ case "path":
+ source = new PathSource();
+ break;
case "sdk":
source = new SdkSource();
break;
@@ -423,10 +427,14 @@
switch (sourceName) {
case "git":
var url = description is String ? description : description['url'];
- return basename(url.replaceFirst(new RegExp(r"(\.git)?/?$"), ""));
+ // TODO(rnystrom): Using path.basename on a URL is hacky. If we add URL
+ // support to pkg/path, should use an explicit builder for that.
+ return path.basename(url.replaceFirst(new RegExp(r"(\.git)?/?$"), ""));
case "hosted":
if (description is String) return description;
return description['name'];
+ case "path":
+ return path.basename(description);
case "sdk":
return description;
default:
@@ -434,6 +442,10 @@
}
}
+/// The full path to the created sandbox directory for an integration test.
+String get sandboxDir => _sandboxDir;
+String _sandboxDir;
+
/// The path of the package cache directory used for tests. Relative to the
/// sandbox directory.
final String cachePath = "cache";
@@ -452,7 +464,7 @@
/// The type for callbacks that will be fired during [schedulePub]. Takes the
/// sandbox directory as a parameter.
-typedef Future _ScheduledEvent(Directory parentDir);
+typedef Future _ScheduledEvent(String parentDir);
/// The list of events that are scheduled to run as part of the test case.
List<_ScheduledEvent> _scheduled;
@@ -488,27 +500,32 @@
file('version', '0.1.2.3')
]).scheduleCreate();
+ _sandboxDir = createTempDir();
+
// Schedule the test.
body();
// 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 sandboxDir = createTempDir();
- return timeout(_runScheduled(sandboxDir, _scheduled),
+ return timeout(_runScheduled(_scheduled),
_TIMEOUT, 'waiting for a test to complete').catchError((e) {
- return _runScheduled(sandboxDir, _scheduledOnException).then((_) {
+ return _runScheduled(_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(sandboxDir, _scheduledCleanup).then((_) {
+ return _runScheduled(_scheduledCleanup).then((_) {
_scheduled = null;
_scheduledCleanup = null;
_scheduledOnException = null;
- if (sandboxDir != null) return deleteDir(sandboxDir);
+ if (_sandboxDir != null) {
+ var dir = _sandboxDir;
+ _sandboxDir = null;
+ return deleteDir(dir);
+ }
});
}).then((_) {
// If we got here, the test completed successfully so tell unittest so.
@@ -527,9 +544,17 @@
/// tests.
String get testDirectory {
var dir = new Options().script;
- while (basename(dir) != 'pub') dir = dirname(dir);
+ while (path.basename(dir) != 'pub') dir = path.dirname(dir);
- return getFullPath(dir);
+ return path.absolute(dir);
+}
+
+/// Schedules renaming (moving) the directory at [from] to [to], both of which
+/// are assumed to be relative to [sandboxDir].
+void scheduleRename(String from, String to) {
+ _schedule((sandboxDir) {
+ return renameDir(join(sandboxDir, from), join(sandboxDir, to));
+ });
}
/// Schedules a call to the Pub command-line utility. Runs Pub with [args] and
@@ -602,12 +627,14 @@
pub.writeLine("y");
}
-
/// Calls [fn] with appropriately modified arguments to run a pub process. [fn]
/// should have the same signature as [startProcess], except that the returned
/// [Future] may have a type other than [Process].
Future _doPub(Function fn, sandboxDir, List args, Future<Uri> tokenEndpoint) {
- String pathInSandbox(path) => join(getFullPath(sandboxDir), path);
+ String pathInSandbox(String relPath) {
+ return join(path.absolute(sandboxDir), relPath);
+ }
+
return defer(() {
ensureDir(pathInSandbox(appPath));
return Future.wait([
@@ -677,7 +704,7 @@
});
}
-Future _runScheduled(Directory parentDir, List<_ScheduledEvent> scheduled) {
+Future _runScheduled(List<_ScheduledEvent> scheduled) {
if (scheduled == null) return new Future.immediate(null);
var iterator = scheduled.iterator;
@@ -688,7 +715,7 @@
return new Future.immediate(null);
}
- var future = iterator.current(parentDir);
+ var future = iterator.current(_sandboxDir);
if (future != null) {
return future.then(runNextEvent);
} else {
@@ -815,7 +842,7 @@
/// Schedules the directory to be validated after Pub is run with
/// [schedulePub]. The directory will be validated relative to the sandbox
/// directory.
- void scheduleValidate() => _schedule((parentDir) => validate(parentDir.path));
+ void scheduleValidate() => _schedule((parentDir) => validate(parentDir));
/// Asserts that the name of the descriptor is a [String] and returns it.
String get _stringName {
@@ -1169,7 +1196,7 @@
typedef Validator ValidatorCreator(Entrypoint entrypoint);
/// Schedules a single [Validator] to run on the [appPath]. Returns a scheduled
-/// Future that contains the erros and warnings produced by that validator.
+/// Future that contains the errors and warnings produced by that validator.
Future<Pair<List<String>, List<String>>> schedulePackageValidation(
ValidatorCreator fn) {
return _scheduleValue((sandboxDir) {
diff --git a/utils/tests/pub/validator_test.dart b/utils/tests/pub/validator_test.dart
index b11d90f..b64f131 100644
--- a/utils/tests/pub/validator_test.dart
+++ b/utils/tests/pub/validator_test.dart
@@ -10,9 +10,10 @@
import 'dart:math' as math;
import 'test_pub.dart';
-import '../../../pkg/unittest/lib/unittest.dart';
import '../../../pkg/http/lib/http.dart' as http;
import '../../../pkg/http/lib/testing.dart';
+import '../../../pkg/path/lib/path.dart' as path;
+import '../../../pkg/unittest/lib/unittest.dart';
import '../../pub/entrypoint.dart';
import '../../pub/io.dart';
import '../../pub/validator.dart';
@@ -38,6 +39,16 @@
expectLater(schedulePackageValidation(fn), pairOf(isEmpty, isNot(isEmpty)));
}
+expectDependencyValidationError(String error) {
+ expectLater(schedulePackageValidation(dependency),
+ pairOf(someElement(contains(error)), isEmpty));
+}
+
+expectDependencyValidationWarning(String warning) {
+ expectLater(schedulePackageValidation(dependency),
+ pairOf(isEmpty, someElement(contains(warning))));
+}
+
Validator compiledDartdoc(Entrypoint entrypoint) =>
new CompiledDartdocValidator(entrypoint);
@@ -66,7 +77,31 @@
void scheduleNormalPackage() => normalPackage.scheduleCreate();
+/// Sets up a test package with dependency [dep] and mocks a server with
+/// [hostedVersions] of the package available.
+setUpDependency(Map dep, {List<String> hostedVersions}) {
+ useMockClient(new MockClient((request) {
+ expect(request.method, equals("GET"));
+ expect(request.url.path, equals("/packages/foo.json"));
+
+ if (hostedVersions == null) {
+ return new Future.immediate(new http.Response("not found", 404));
+ } else {
+ return new Future.immediate(new http.Response(json.stringify({
+ "name": "foo",
+ "uploaders": ["nweiz@google.com"],
+ "versions": hostedVersions
+ }), 200));
+ }
+ }));
+
+ dir(appPath, [
+ libPubspec("test_pkg", "1.0.0", deps: [dep])
+ ]).scheduleCreate();
+}
+
main() {
+ initConfig();
group('should consider a package valid if it', () {
setUp(scheduleNormalPackage);
@@ -326,124 +361,88 @@
expectValidationError(lib);
});
- group('has a dependency with a non-hosted source', () {
- group('where a hosted version of that dependency exists', () {
- integration("and should suggest the hosted package's primary "
- "version", () {
- useMockClient(new MockClient((request) {
- expect(request.method, equals("GET"));
- expect(request.url.path, equals("/packages/foo.json"));
-
- return new Future.immediate(new http.Response(json.stringify({
- "name": "foo",
- "uploaders": ["nweiz@google.com"],
- "versions": ["3.0.0-pre", "2.0.0", "1.0.0"]
- }), 200));
- }));
-
- dir(appPath, [
- libPubspec("test_pkg", "1.0.0", deps: [
- {'git': 'git://github.com/dart-lang/foo'}
- ])
- ]).scheduleCreate();
-
- expectLater(schedulePackageValidation(dependency),
- pairOf(isEmpty, someElement(contains(
- ' foo: ">=2.0.0 <3.0.0"'))));
+ group('has a git dependency', () {
+ group('where a hosted version exists', () {
+ integration("and should suggest the hosted primary version", () {
+ setUpDependency({'git': 'git://github.com/dart-lang/foo'},
+ hostedVersions: ["3.0.0-pre", "2.0.0", "1.0.0"]);
+ expectDependencyValidationWarning(' foo: ">=2.0.0 <3.0.0"');
});
- integration("and should suggest the hosted package's prerelease "
- "version if it's the only version available", () {
- useMockClient(new MockClient((request) {
- expect(request.method, equals("GET"));
- expect(request.url.path, equals("/packages/foo.json"));
-
- return new Future.immediate(new http.Response(json.stringify({
- "name": "foo",
- "uploaders": ["nweiz@google.com"],
- "versions": ["3.0.0-pre", "2.0.0-pre"]
- }), 200));
- }));
-
- dir(appPath, [
- libPubspec("test_pkg", "1.0.0", deps: [
- {'git': 'git://github.com/dart-lang/foo'}
- ])
- ]).scheduleCreate();
-
- expectLater(schedulePackageValidation(dependency),
- pairOf(isEmpty, someElement(contains(
- ' foo: ">=3.0.0-pre <4.0.0"'))));
+ integration("and should suggest the hosted prerelease version if "
+ "it's the only version available", () {
+ setUpDependency({'git': 'git://github.com/dart-lang/foo'},
+ hostedVersions: ["3.0.0-pre", "2.0.0-pre"]);
+ expectDependencyValidationWarning(' foo: ">=3.0.0-pre <4.0.0"');
});
- integration("and should suggest a tighter constraint if the primary "
- "version is pre-1.0.0", () {
- useMockClient(new MockClient((request) {
- expect(request.method, equals("GET"));
- expect(request.url.path, equals("/packages/foo.json"));
-
- return new Future.immediate(new http.Response(json.stringify({
- "name": "foo",
- "uploaders": ["nweiz@google.com"],
- "versions": ["0.0.1", "0.0.2"]
- }), 200));
- }));
-
- dir(appPath, [
- libPubspec("test_pkg", "1.0.0", deps: [
- {'git': 'git://github.com/dart-lang/foo'}
- ])
- ]).scheduleCreate();
-
- expectLater(schedulePackageValidation(dependency),
- pairOf(isEmpty, someElement(contains(
- ' foo: ">=0.0.2 <0.0.3"'))));
+ integration("and should suggest a tighter constraint if primary is "
+ "pre-1.0.0", () {
+ setUpDependency({'git': 'git://github.com/dart-lang/foo'},
+ hostedVersions: ["0.0.1", "0.0.2"]);
+ expectDependencyValidationWarning(' foo: ">=0.0.2 <0.0.3"');
});
});
- group('where no hosted version of that dependency exists', () {
+ group('where no hosted version exists', () {
integration("and should use the other source's version", () {
- useMockClient(new MockClient((request) {
- expect(request.method, equals("GET"));
- expect(request.url.path, equals("/packages/foo.json"));
-
- return new Future.immediate(new http.Response("not found", 404));
- }));
-
- dir(appPath, [
- libPubspec("test_pkg", "1.0.0", deps: [
- {
- 'git': {'url': 'git://github.com/dart-lang/foo'},
- 'version': '>=1.0.0 <2.0.0'
- }
- ])
- ]).scheduleCreate();
-
- expectLater(schedulePackageValidation(dependency),
- pairOf(isEmpty, someElement(contains(
- ' foo: ">=1.0.0 <2.0.0"'))));
+ setUpDependency({
+ 'git': 'git://github.com/dart-lang/foo',
+ 'version': '>=1.0.0 <2.0.0'
+ });
+ expectDependencyValidationWarning(' foo: ">=1.0.0 <2.0.0"');
});
integration("and should use the other source's unquoted version if "
- "it's concrete", () {
- useMockClient(new MockClient((request) {
- expect(request.method, equals("GET"));
- expect(request.url.path, equals("/packages/foo.json"));
+ "concrete", () {
+ setUpDependency({
+ 'git': 'git://github.com/dart-lang/foo',
+ 'version': '0.2.3'
+ });
+ expectDependencyValidationWarning(' foo: 0.2.3');
+ });
+ });
+ });
- return new Future.immediate(new http.Response("not found", 404));
- }));
+ group('has a path dependency', () {
+ group('where a hosted version exists', () {
+ integration("and should suggest the hosted primary version", () {
+ setUpDependency({'path': path.join(sandboxDir, 'foo')},
+ hostedVersions: ["3.0.0-pre", "2.0.0", "1.0.0"]);
+ expectDependencyValidationError(' foo: ">=2.0.0 <3.0.0"');
+ });
- dir(appPath, [
- libPubspec("test_pkg", "1.0.0", deps: [
- {
- 'git': {'url': 'git://github.com/dart-lang/foo'},
- 'version': '0.2.3'
- }
- ])
- ]).scheduleCreate();
+ integration("and should suggest the hosted prerelease version if "
+ "it's the only version available", () {
+ setUpDependency({'path': path.join(sandboxDir, 'foo')},
+ hostedVersions: ["3.0.0-pre", "2.0.0-pre"]);
+ expectDependencyValidationError(' foo: ">=3.0.0-pre <4.0.0"');
+ });
- expectLater(schedulePackageValidation(dependency),
- pairOf(isEmpty, someElement(contains(' foo: 0.2.3'))));
+ integration("and should suggest a tighter constraint if primary is "
+ "pre-1.0.0", () {
+ setUpDependency({'path': path.join(sandboxDir, 'foo')},
+ hostedVersions: ["0.0.1", "0.0.2"]);
+ expectDependencyValidationError(' foo: ">=0.0.2 <0.0.3"');
+ });
+ });
+
+ group('where no hosted version exists', () {
+ integration("and should use the other source's version", () {
+ setUpDependency({
+ 'path': path.join(sandboxDir, 'foo'),
+ 'version': '>=1.0.0 <2.0.0'
+ });
+ expectDependencyValidationError(' foo: ">=1.0.0 <2.0.0"');
+ });
+
+ integration("and should use the other source's unquoted version if "
+ "concrete", () {
+ setUpDependency({
+ 'path': path.join(sandboxDir, 'foo'),
+ 'version': '0.2.3'
+ });
+ expectDependencyValidationError(' foo: 0.2.3');
});
});
});
@@ -507,9 +506,7 @@
}))
]).scheduleCreate();
- expectLater(schedulePackageValidation(dependency),
- pairOf(isEmpty, someElement(contains(
- ' foo: ">=1.2.3 <2.0.0"'))));
+ expectDependencyValidationWarning(' foo: ">=1.2.3 <2.0.0"');
});
integration('and it should suggest a concrete constraint if the locked '
@@ -532,9 +529,7 @@
}))
]).scheduleCreate();
- expectLater(schedulePackageValidation(dependency),
- pairOf(isEmpty, someElement(contains(
- ' foo: ">=0.1.2 <0.1.3"'))));
+ expectDependencyValidationWarning(' foo: ">=0.1.2 <0.1.3"');
});
});
});